Invoke a SOAP method with namespace prefixes

19,775

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.

Share:
19,775
mvladic
Author by

mvladic

Updated on June 04, 2022

Comments

  • mvladic
    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
    mvladic over 13 years
    Yes, you are right, there is no XmlRootAttribute in the RequestMessage class definition (or in any other class in the same auto-generated file).
  • mvladic
    mvladic over 13 years
    "Add Service Reference" works only with asmx, and I only have one wsdl and one xsd file.
  • mvladic
    mvladic over 13 years
    I've added XmlRootAttribute to the class definition and it doesn't help.
  • mvladic
    mvladic over 13 years
    I've created client with "svcutil my.wsdl my.xsd /language:C#" and it still doesn't work - there is no namespace prefixes.
  • mvladic
    mvladic over 13 years
    I've added definition of RequestMessage class in my question.
  • pmartin
    pmartin over 13 years
    @mvladic The example you posted above shows that you added the XmlTypeAttribute attribute, not the XmlRootAttribute 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 the XmlRootAttribute attribute to make sure that the response is being returned using the correct namespace.
  • mvladic
    mvladic over 13 years
    Example that I posted is original, generated by wsdl tool. I tried, as you suggested, to add XmlRootAttribute but it didn't helped.
  • John Saunders
    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
    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.