Appeler une méthode de SAVON avec des préfixes d'espace de noms
Mon C# client de service web envoie la suite dans le message soap en Java-service web:
<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<soap:Body>
<getData>
<request>
<requestParameters xmlns="http://b...">
<equals>
...
</equals>
</requestParameters>
</request>
</getData>
</soap:Body>
</soap:Envelope>
et Java web service renvoie l'erreur:
500 Internal Server Error ... Cannot find dispatch method for {}getData ...
Client écrit en Java, qui fonctionne, envoie le message suivant:
<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<soap:Body>
<ns2:getData xmlns:ns2="http://a...">
<ns2:request>
<ns3:requestParameters xmlns:ns3="http://b...">
<ns3:equals>
...
</ns3:equals>
</ns3:requestParameters>
</ns2:request>
</ns2:getData>
</soap:Body>
</soap:Envelope>
Est-il un moyen facile en C# pour envoyer des messages SOAP de la même manière Java client envoie: avec des préfixes d'espace de noms?
Qui suit est le code C# qui envoie un message:
//class MyService is auto-generated using wsdl.exe tool
MyService service = new MyService();
RequestMessage request = new RequestMessage();
...
ResponseMessage response = service.getData(request);
...
Mise à JOUR:
Ici est RequestMessage classe:
///<remarks/>
[System.CodeDom.Compiler.GeneratedCodeAttribute("svcutil", "3.0.4506.2152")]
[System.SerializableAttribute()]
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlTypeAttribute(Namespace="http://uri.etsi.org/02657/v1.5.1#/RetainedData")]
public partial class RequestMessage
{
private byte[] requestPriorityField;
private RequestConstraints requestParametersField;
private string deliveryPointHIBField;
private string maxHitsField;
private NationalRequestParameters nationalRequestParametersField;
private System.Xml.XmlElement anyField;
///<remarks/>
[System.Xml.Serialization.XmlElementAttribute(DataType="hexBinary", Order=0)]
public byte[] requestPriority
{
get
{
return this.requestPriorityField;
}
set
{
this.requestPriorityField = value;
}
}
///<remarks/>
[System.Xml.Serialization.XmlElementAttribute(Order=1)]
public RequestConstraints requestParameters
{
get
{
return this.requestParametersField;
}
set
{
this.requestParametersField = value;
}
}
///<remarks/>
[System.Xml.Serialization.XmlElementAttribute(Order=2)]
public string deliveryPointHIB
{
get
{
return this.deliveryPointHIBField;
}
set
{
this.deliveryPointHIBField = value;
}
}
///<remarks/>
[System.Xml.Serialization.XmlElementAttribute(DataType="integer", Order=3)]
public string maxHits
{
get
{
return this.maxHitsField;
}
set
{
this.maxHitsField = value;
}
}
///<remarks/>
[System.Xml.Serialization.XmlElementAttribute(Order=4)]
public NationalRequestParameters nationalRequestParameters
{
get
{
return this.nationalRequestParametersField;
}
set
{
this.nationalRequestParametersField = value;
}
}
///<remarks/>
[System.Xml.Serialization.XmlAnyElementAttribute(Order=5)]
public System.Xml.XmlElement Any
{
get
{
return this.anyField;
}
set
{
this.anyField = value;
}
}
}
Mise à JOUR #2:
La raison pour laquelle basé sur Java web service n'a pas aimé mon client C# produit SAVON message n'est pas d'omission de préfixes d'espace de noms, mais seulement en raison de l'omission de xmlns dans getData élément, donc si mon message ressemble à ceci:
...
<getData xmlns="http://a...">
...
</getData>
...
ça marche!!!
J'ai réussi à mettre xmlns à l'intérieur de getData en modifiant manuellement SoapRpcMethodAttribute en wsdl.exe-produit code source. Voici l'extrait:
///<remarks/>
[System.CodeDom.Compiler.GeneratedCodeAttribute("wsdl", "2.0.50727.3038")]
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Web.Services.WebServiceBindingAttribute(
Name="AxxxPortTypeBinding", Namespace="http://a...")]
public partial class AxxxService
: System.Web.Services.Protocols.SoapHttpClientProtocol {
...
///<remarks/>
[System.Web.Services.Protocols.SoapRpcMethodAttribute(
"http://a.../getData",
RequestNamespace = "http://a...",
ResponseNamespace = "http://a...",
Use = System.Web.Services.Description.SoapBindingUse.Literal)]
[return: System.Xml.Serialization.XmlElementAttribute("response")]
public ResponseMessage getData(RequestMessage request) {
object[] results = this.Invoke("getData", new object[] {
request});
return ((ResponseMessage)(results[0]));
}
...
}
Avant mon changement, SoapRpcMethodAttribute avait constructeur suivant:
[System.Web.Services.Protocols.SoapRpcMethodAttribute(
"", RequestNamespace = "", ResponseNamespace = "",
Use = System.Web.Services.Description.SoapBindingUse.Literal)]
Maintenant, la question est: que mettre dans le fichier WSDL afin que SoapRpcMethodAttribute ces chaînes dans le constructeur (rempli par le wsdl.exe l'outil) en premier lieu?
- Avez-vous générer votre service proxy avec wsdl.exe?
- Oui (voir le commentaire dans le code, au fond de la question).
Vous devez vous connecter pour publier un commentaire.
J'ai vu ce problème avant de où la WSDL.exe l'outil n'a pas correctement tirez dans l'espace de noms lors de la génération du code de service. De vérifier la
request
définition de l'objet dans votre code généré. Ma conjecture est qu'il n'est pasXmlRootAttribute
attribut défini sur la définition de classe pour larequest
objet.L'ajout de l'attribut
[XmlRootAttribute(Namespace "http://a...")]
à la définition de classe pour larequest
objet devrait corriger ce problème.Comme une note de côté, je recommande d'ajouter cet attribut supplémentaire dans un autre fichier de code à l'aide d'une définition de classe partielle. La définition de l'attribut dans un fichier distinct va vous permettre de régénérer le code de service web à l'aide de WSDL.exe chaque fois que nécessaire sans écraser le correctif pour régler l'élément racine de l'espace de noms correctement.
XmlTypeAttribute
attribut, pas laXmlRootAttribute
attribut. Compte tenu de votre exemple de requête SOAP le RequestMessage classe doit être identifié comme étant l'élément racine du document XML message envoyé. J'ai aussi l'avis de votre exemple que le service retourne une respone (probablement dans le ResponseMessage classe?). Vous aurez également besoin pour décorer cette reponse classe avec leXmlRootAttribute
attribut assurez-vous que la réponse est renvoyée à l'aide de l'espace de noms correct.Le proxy généré classe devrait avoir eu le bon espace de noms en elle. Je recommande deux choses:
1) Exécuter WSDL.EXE à partir de la ligne de commande et notez si il y a des erreurs ou des avertissements. Si oui, merci d'éditer votre question de les inclure.
2), Sauf si vous êtes coincé à l'aide .NET 2.0, vous devriez essayer de créer votre proxy classes en utilisant "Ajouter une Référence de Service" ou l'équivalent "SVCUTIL.EXE" ces utilisera le moderne, WCF de l'infrastructure sur le côté client, ce qui est beaucoup plus susceptibles d'avoir été fixé pour résoudre ce problème.
J'ai eu le même problème et l'a résolu en changeant la valeur de la propriété Utilisation dans Système.Web.Services.Les protocoles.SoapDocumentMethodAttribute attribut corrisponding pour chaque méthode de service web.
Le Système.Web.Services.Description.SoapBindingUse.Littéral valeur par défaut a été remplacé par le Système.Web.Services.Description.SoapBindingUse.Codé.