APEXA, LLC
Blog Gallery Contact

WCF: DataContractSerializer Schema Rules

Blog Date: 4/28/2008

 Recent Blogs << Back

System.ServiceModel.CommunicationException: The un 4/23/2008

VSLive 2008 for Visual Studio in Orlando 4/24/2008

Visual Studio and WCF Tips and Tricks 4/25/2008

 More...
 

Anyone who have tried to do contract/schema first design of data contracts or tried to generate proxies using SVCUTIL.EXE in an interop scenario with e.g. Spring-WS, will have run into how WCF magically decides to use the old XmlSerializer rather than the new DataContractsSerializer (DCS). And deducing which parts of a schema that cause this is not easy with real-life contracts.

The
XML schema rules/limitations for DCS is well documented, but the proxy generator will not tell you which of the rules your XSD/WSDL does not adhere to. Even worse, if you specify /serializer:DataContractSerializer and the rules are broken; the proxy will get generated without any error, but also without any messages and data transfer objects.

Note that the SVCUTIL switches /collectionType /ct and /reference /r only work with the DataContractSerializer, not the XmlSerializer. Thus, if the proxy generator falls back to the XmlSerializer, you will not get collections (List / BindingList / etc) for arrays nor any reuse of existing object types.


The only way I've found that will tell you why DCS is not used, is by using the /DCONLY option to extract the data contracts from the WSDL. Using this switch will disclose data contract (XSD) errors one at a time, but it is still better than not knowing why. Note that it will not disclose any errors related to the messages not being document/literal wrapped (WSDL).

The most common XSD schema lapsus is not wrapping arrays in a two-level complex type, one for the list of items and one for the items themselves. This is not very well documented in the DCS rules. The array XSD schema must follow this construct:

<xs:element name="ItemList" type="tns:ItemListType" />

<xs:complexType name="ItemListType">
<xs:sequence>
<xs:element minOccurs="0" maxOccurs="unbounded" name="Item" type="tns:ItemType"/>
</xs:sequence>
</xs:complexType>

<xs:complexType name="ItemType">
<xs:sequence>
<xs:element name="Id" type="xs:long" />
<xs:element name="Value" nillable="true" type="xs:string" />
</xs:sequence>
</xs:complexType>

Note that there is no need to use the prefix ArrayOf on the list element name.


The reason for wrapping the array seems quite silly when the message contains elements of only one type. However, look at this XML segment that contains elements of multiple types:
<root><a/><b/><b/><b/></root>

The DCS does not like a XSD schema where the children of an element varies in numbers and are not of the same type; it requires that all child elements that varies in numbers must have the same type, thus the wrapper element:
<root><a/><itemList><b/><b/><b/></itemList></root>


This way the <root> element contains a fixed number of different elements, the <a> element and the <itemList> element; while the <itemList> element contains a varying number of <b> elements only.

The other typical WSDL lapsus wrt DCS is about the message part definitions and the related operation input and output elements plus the related binding section. The important rule here is to remember to use only one part in each message (WS-I Basic Profile) and to set the @name = "parameters" (by convention) on message parts to make the messages document/literal wrapped. This is an example that will allow you to use the DataContractSerializer:

<wsdl:message name="GetItemRequest">
<wsdl:part element="tns:GetItemRequestType" name="parameters">
</wsdl:part></wsdl:message>

<wsdl:message name="GetItemResponse">
<wsdl:part element="tns:GetItemResponseType" name="parameters"> </wsdl:part></wsdl:message>

<wsdl:portType name="InspectValues">
<wsdl:operation name="GetItem">
<wsdl:input message="tns:GetItemRequest" name="GetItemRequest"></wsdl:input>
<wsdl:output message="tns:GetItemResponse" name="GetItemResponse"></wsdl:output>
</wsdl:operation>
</wsdl:portType>

<wsdl:binding name="InspectValuesSoap11" type="tns:InspectValues">
<soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http" />
<wsdl:operation name="GetItem">
<soap:operation soapAction="" />
<wsdl:input name="GetItemRequest"><soap:body use="literal" /></wsdl:input>
<wsdl:output name="GetItemResponse"><soap:body use="literal" /></wsdl:output>
</wsdl:operation>
</wsdl:binding>

If the generated DCS-based proxy interface contains operations that has no input or output messages, then your WSDL does not adhere to the above rules. The same is true if you get any "cannot import" errors or warnings related to wsdl:binding, wsdl:portType or wsdl:port. Note also that the element referenced as a message part must be a DCS allowable <xs:complexType> with an <xs:sequence> child (can also be empty). Read more about message schema rules in Handcrafting WCF friendly WSDLs.

I wish the DCS rules documentation had included more XSD schema examples, both for allowable and invalid schema constructs.
The /reference option is very important when using an architecture like CAB/SCSF where the service implementation (proxy) is separated from the service definition (interface). Then, it is important that the data contracts are included in the service interface assembly for reuse across business modules; i.e. the DTO objects can not be inside the proxy implementation assembly. The proxy itself is most likely wrapped in a service agent and should never be exposed in the DDD service or repository pattern interface.

If you can't get the /dconly plus /reference combo to work, then you're stuck with generating the contracts and proxy into classes in a single file using a .Service.Interface namespace and then extracting the proxy code into a separate file in a .Service namespace using e.g. a RegEx script, followed by some namespace using/imports refactoring for the extracted proxy code file so that it references the data contracts in the interface namespace.




4/28/2008 5:53:01 PM

Home | Gallery | Contact | IT Consulting | Web Marketing | Search Engine Optimization | Web Design & CMS | My Blog on C# .NET

Site Map | Copyright 2007 Web Design web design | Developed by APEXA, LLC

APEXA, LLC