2010-11-11 53 views
10

J'ai importé un WSDL et l'utilise pour envoyer une requête SOAP. Il ressemble à ceci:Suppression de l'espace de nom de la requête SOAP

<?xml version="1.0"?> 
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> 
    <SOAP-ENV:Body> 
     <Calculate xmlns="urn:xx.WSDL.xxxxxWebService"> 
      <ContractdocumentIn> 
       <AL> 
       ...More XML... 

Le problème est la partie xmlns="urn:xx.WSDL.xxxxxWebService" dans l'élément Calculer. Le service Web ne peut pas accepter cela. Le service web n'aime pas les espaces de noms comme ça ...
En utilisant SoapUI J'ai trouvé cette demande de travailler très bien:

<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://www.w3.org/2003/05/soap-envelope" xmlns:col="http://example.com.service.xxx/"> 
    <SOAP-ENV:Body> 
     <col:Calculate> 
      <ContractdocumentIn> 
       <AL> 
        ...More XML... 

Alors, comment puis-je changer la demande de la première à la deuxième version? (Sans utiliser des tours sales!)
(réimportation est pas un problème si cela entraînerait le bon format de demande.)




Encore une fois: pas de trucs sales autorisés, comme le piratage du flux de demande de le modifier !


Et alors que je ne l'ai pas complètement testé, il semble que C#/VS2010 et Delphi 2010 sont également incapables d'utiliser le service Web que je suis en train d'appeler. Un service Web qui semble être écrit en Java. SoapUI arrive à être écrit en Java, donc nous avons un client Java qui parle à un service Java, ce qui semble fonctionner correctement. Mais tout autre client?
De toute façon, il est temps d'ajouter deux tags supplémentaires: "Java", puisqu'il s'agit d'un service Java, et "vs2010", car .NET déteste également ce service.
Et j'étais sur le point d'écrire un wrapper autour de ce service dans .NET, espérant que cela fonctionnerait ... Ce n'est pas le cas. Il s'agit donc d'un défaut très sérieux, peut-être un défaut Java ...

+0

Bonne chance. J'ai dû recourir à des trucs sales. –

+0

Oui, je sais. Je peux probablement le résoudre en utilisant des astuces sales, mais la direction n'est pas d'accord avec ça. Donc le code doit être propre. –

+2

Le code SOAP vous permet d'examiner le code XML envoyé et de le modifier si nécessaire. Il prend en charge la manipulation manuelle explicitement. Et le code serait là - rien de "sale" à propos de la manipulation post-build. Peut-être pas aussi bien que automatique, mais personne ne devrait s'inquiéter à ce sujet. – mj2008

Répondre

14

Si un service attend:

<col:Calculate> 
    <ContractdocumentIn> 
     <AL> 

et Delphi SOAP envoie ...

<Calculate xmlns="urn:xx.WSDL.xxxxxWebService"> 
     <ContractdocumentIn> 
      <AL> 

... le problème est que ContractdocumentIn est un élément non qualifié et (jusqu'à ce que Delphi XE) Delphi SOAP ne prend pas en charge les éléments non qualifiés qui sont des éléments de niveau supérieur d'une opération. Les éléments de premier niveau sont des paramètres de la fonction et il n'y a nulle part où stocker le fait que l'élément sous-jacent doit être non qualifié; Pour les éléments qui correspondent aux propriétés, nous utilisons l'index de la propriété pour stocker l'indicateur IS_UNQL.

BTW, il n'est pas nécessaire d'utiliser un préfixe. Le Service (doit) accepter aussi:

<Calculate xmlns="urn:xx.WSDL.xxxxxWebService"> 
     <ContractdocumentIn xmlns=""> 
      <AL> 

Ce dernier est plus bavard, mais il est équivalent au cas préfixe.

Dans Delphi XE, l'importateur stocke le fait qu'un paramètre particulier correspond à un élément non qualifié et que le moteur d'exécution agit sur cette information. J'ai posté des correctifs basé sur la mise en œuvre de XE pour D2010 et D2007 dans le forum quand il est venu dans un fil récemment:

https://forums.embarcadero.com/thread.jspa?threadID=43057

Si quelqu'un a besoin d'accéder à eux (ils étaient dans la zone des pièces jointes, mais peut-être ont défilé), s'il vous plaît écrivez-moi et je les rendrai disponibles. [Dot com bbabet à Embarcadero]

Cheers,

Bruneau

+1

Belle explication! Merci. J'utilise D2005 avec les correctifs D2007 pour les bibliothèques SOAP. Pensez-vous que vos correctifs pour les correctifs D2007 fonctionneraient pour moi? –

+4

Oui, ça devrait. Le patch que j'ai posté est ici: https://forums.embarcadero.com/thread.jspa?messageID=290788 – BruneauB

+0

Si vous rencontrez des problèmes, s'il vous plaît, pointez-moi (ou envoyez-moi un courriel) le WSDL et je vais enquêter. À votre santé! – BruneauB

8

OMG! Il a fallu beaucoup de café et beaucoup de dépravation de sommeil mais j'ai réussi à résoudre mon problème! C'est aussi simple que ça ...
J'importais d'abord le WSDL, comme prévu. Cela générera plusieurs classes TRemotable. Ensuite, pour chaque TRemotable qui a besoin d'un espace de noms différent, je substitue la méthode ObjectToSOAP()! (Et inclure XMLIntf à la source WSDL.) Dans mon cas avec le code comme ceci pour plusieurs des types distants:

function AL2.ObjectToSOAP(RootNode, ParentNode: IXMLNode; const ObjConverter: IObjConverter; const NodeName, NodeNamespace, ChildNamespace: InvString; ObjConvOpts: TObjectConvertOptions; out RefID: InvString): IXMLNode; 
begin 
    Result := inherited ObjectToSOAP(RootNode, ParentNode, ObjConverter, NodeName, '', '', ObjConvOpts, RefID); 
end; 

qui a travaillé dans Delphi XE. Dans Delphi 2007 je devais utiliser des unités XMLIntf et XMLDoc, plus ce code sur le type d'entrée:

function ContractdocumentInType.ObjectToSOAP(RootNode, ParentNode: IXMLNode; const ObjConverter: IObjConverter; const Name, URI: InvString; ObjConvOpts: TObjectConvertOptions; out RefID: InvString): IXMLNode; 

    procedure AlterChildren(Child: IXMLNode); 
    var 
    I: Integer; 
    begin 
    if (Child.NodeType = ntElement) then Child.SetAttributeNS('xmlns', '', ''); 
    for I := 0 to Pred(Child.ChildNodes.Count) do 
     AlterChildren(Child.ChildNodes[I]); 
    end; 

begin 
    Result := inherited ObjectToSOAP(RootNode, ParentNode, ObjConverter, Name, '', ObjConvOpts, RefID); 
    AlterChildren(Result); 
end; 

Il est un hack, à mon avis. Mais ce n'est pas très sale. C'est un peu expérimental, en capturant les requêtes SOAP et les réponses pour vérifier leur contenu et voir s'il utilise les espaces de noms appropriés. Malheureusement, Delphi XE fait un bien meilleur travail à ce que Delphi 2007.

Pourtant, je garde cette Q ouverte pour toutes les meilleures solutions ...


BTW, pour ajouter le col: à la sortie, J'ai également dû changer cette ligne dans le WSDL RemClassRegistry.RegisterXSClass(Calculate, 'http://colan.ogconnect.service.wzp/', 'Calculate'); à ceci: RemClassRegistry.RegisterXSClass(Calculate, 'http://colan.ogconnect.service.wzp/', 'cal:Calculate');. Le résultat devient alors <cal:Calculate xmlns:cal="http://example.webservice/">. Plus de chose doit être fait, cependant: déplacer ce xmlns:cal à l'en-tête xml. Mais comme c'est le cas maintenant, cela fonctionne pour moi.


Une autre note: le WSDL j'ai utilisé les paramètres suivants: 'Un Outparam est de retour', 'Déroulez params littérale', 'Générer Destructeurs', 'commentaires d'avertissement', 'émettent types littéral', "Chaîne de mappage au format". Les autres options sont: 'Générer des informations détaillées sur les types et les interfaces', 'Ignorer les types de port avec les liaisons HTTP', 'Valider les membres de l'énumération', 'Importer les types de faute', 'Importer les types d'en-tête', 'Générer alias de classe comme types de classe ',' Allow Out parameters 'et' Traiter les éléments nillables et optionnels '. Le émettait littéralement les types était pratique car il génère une classe autour de la méthode unique que j'appelais. Malheureusement, cela n'aidera pas non plus, bien que la classe vous aiderait à modifier la requête SOAP au niveau supérieur dans l'enveloppe en remplaçant la méthode ObjectToSOAP().
La création de l'enveloppe elle-même se fait dans l'unité SOAPEnv et est utilisée dans l'unité OPToSOAPDomConv. Malheureusement, je n'ai pas trouvé une méthode facile d'accéder à l'enveloppe elle-même pour modifier l'en-tête pour ajouter cet espace de noms supplémentaire. Là encore, je pourrais substituer la classe TSOAPDomConv avec ma propre version qui ajoute l'espace de noms supplémentaire. Mais le code fonctionne pour moi maintenant, et comme mon père me l'a dit, quand il m'a appris à programmer: ne jamais réparer quoi que ce soit qui ne soit pas cassé.

+0

On dirait prometteur - Je vais faire un tourbillon. Cela peut faire économiser beaucoup de temps et de douleur sur un gros projet à venir, alors je suis heureux de contribuer des points de prime dans la discussion. –

+0

Cela vous at-il vraiment donné une sortie comme ceci:

+0

Je pense que cela peut me donner un bon endroit pour me connecter, mais je devrais peut-être faire plus de travail dans la fonction AlterChildren. –