Invoke a SOAP method with namespace prefixes
I've seen this problem before where the WSDL.exe tool did not properly pull in the namespace when generating the service code. Check the request
object definition in your generated code. My guess is that there is no XmlRootAttribute
attribute defined on the class definition for the request
object.
Adding the attribute [XmlRootAttribute(Namespace "http://a...")]
to the class definition for the request
object should fix this issue.
As a side note, I recommend adding this additional attribute in a separate code file using a partial class definition. Defining the attribute in a separate file will allow you to regenerate the web service code using WSDL.exe whenever neccessary without overwriting the fix to set the root element's namespace properly.
mvladic
Updated on June 04, 2022Comments
-
mvladic almost 2 years
My C# web service client sends following soap message to Java-based web service:
<?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>
and Java-based web service returns error:
500 Internal Server Error ... Cannot find dispatch method for {}getData ...
Client written in Java, which works, sends the following message:
<?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>
Is there an easy way in C# to send SOAP messages the same way Java client sends: with namespace prefixes?
Following is C# code that sends message:
// class MyService is auto-generated using wsdl.exe tool MyService service = new MyService(); RequestMessage request = new RequestMessage(); ... ResponseMessage response = service.getData(request); ...
UPDATE:
Here is RequestMessage class:
/// <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; } } }
UPDATE #2:
The reason why Java-based web service didn't like my C# client produced SOAP message is not omission of namespace prefixes, but only because of omission of xmlns in getData element, so if my message looks like this:
... <getData xmlns="http://a..."> ... </getData> ...
it works!
I managed to put xmlns inside getData by manually editing SoapRpcMethodAttribute in wsdl.exe-produced source code. Here is excerpt:
/// <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])); } ... }
Before my change, SoapRpcMethodAttribute had following constructor:
[System.Web.Services.Protocols.SoapRpcMethodAttribute( "", RequestNamespace = "", ResponseNamespace = "", Use = System.Web.Services.Description.SoapBindingUse.Literal)]
Now, the question is: what to put in WSDL file so that SoapRpcMethodAttribute have those strings in constructor (filled by the wsdl.exe tool) in the first place?
-
mvladic over 13 yearsYes, you are right, there is no XmlRootAttribute in the RequestMessage class definition (or in any other class in the same auto-generated file).
-
mvladic over 13 years"Add Service Reference" works only with asmx, and I only have one wsdl and one xsd file.
-
mvladic over 13 yearsI've added XmlRootAttribute to the class definition and it doesn't help.
-
mvladic over 13 yearsI've created client with "svcutil my.wsdl my.xsd /language:C#" and it still doesn't work - there is no namespace prefixes.
-
mvladic over 13 yearsI've added definition of RequestMessage class in my question.
-
pmartin over 13 years@mvladic The example you posted above shows that you added the
XmlTypeAttribute
attribute, not theXmlRootAttribute
attribute. Given your example SOAP request the RequestMessage class should be identified as the root element of the XML message being sent. I also notice from your example that the service returns a respone (likely in the ResponseMessage class?). You will also need to decorate this reponse class with theXmlRootAttribute
attribute to make sure that the response is being returned using the correct namespace. -
mvladic over 13 yearsExample that I posted is original, generated by wsdl tool. I tried, as you suggested, to add XmlRootAttribute but it didn't helped.
-
John Saunders over 13 years@mvladic: you should report this problem to Microsoft at connect.microsoft.com/visualstudio. Be sure to include that WSDL and any included XSD files. Unlike ASMX, WCF is in active development, and bug should actually get fixed.
-
John Saunders over 13 years@mvladic: you are mistaken about "Add Service Reference" - it works against WSDL as well. The only reason it looks at .asmx or .svc is to go find the WSDL.