Wednesday, October 15, 2008

Interoperability Gotcha: elementFormDefault

@YaronNaveh

Recently I was getting an error from a web service indicating that my request is invalid.
I looked at my request:



<soap:Body>
  <GetPerson xmlns="http://someOrganization">
     <name>Rick</name>
   </GetPerson>
</soap:Body>



And at the schema:



<s:complexType name="GetPerson">
  <s:sequence>
    <s:element minOccurs="0" maxOccurs="1" name="name" type="s:string" />
  </s:sequence>
</s:complexType>



And it seemed valid to me.

So I asked the service provider to show me an example of a working soap request. And so he did:



<soap:Body>
   <ns:GetPerson xmlns:ns="http://someOrganization">
     <name>Rick</name>
   </ns:GetPerson>
</soap:Body>




You can see that the difference is in the namespace of the inner "name" element: It is from the "http://someOrganization" namespace in my request but from the empty namespace in the working request. For those of you less familiar with xml namespaces: In the previous request "xmlns" defined a default namespace for all elements without prefixes; In this case only elements that explicitly use the "ns" prefix belong to the namespace.

After a short investigation the cause of this was identified. Let's take a second look at the schema (which is a part of the wsdl file):



<s:schema elementFormDefault="qualified" targetNamespace="http://someOrganization">



elementFormDefault can have 2 values:
  • unqualified means that non top level elements should appear as belonging to the empty namespace
  • qualified means that every element should appear as belonging to the targetNamespace of its defining schema

    So my request was valid for the "qualified" option and the provider sample was valid for "unqualified". Since the wsdl contains "qualified" my request is correct after all.

    However - as in many times with interoperability - there is a Gotcha:

    Many web services frameworks poorly implement elementFormDefault

    This effectively means that a server can use "unqualified" format even though the wsdl has "qualified".

    The solutions can be:

    1. Fix the server implementation
    2. Manually change "qualified" to "unqualified" in the wsdl and recreate your client stubs.

    For new services it is recommended to use "qualified" which is also the default for most new soap stacks.

    @YaronNaveh

    What's next? get this blog rss updates or register for mail updates!
  • 1 comments:

    Anonymous said...

    I know this is an older post, yet it is still true to this day. At the moment I am in the process of writing a dynamic WCF C# client that has the requirement to connect to either a Java or C# web service, without knowing if it is a C# or Java service, all we know is the Data and Service contract layout. Getting Qualified and UnQualified returns was one of the issues to get rid of.

    So thanks for the post!