By default, Windows Communication Foundation (WCF) uses the DataContractSerializer to serialize and deserialize XML in a service, but this serialization mechanism can be replaced to use the XmlSerializer. The following article on MSDN covers this in more detail:
http://msdn2.microsoft.com/en-us/library/ms733901.aspx
Whilst using the Data Contract attributes is much easier, and many more types are supported for serialization, there are various scenarios where switching to the XmlSerializer can be beneficial, such as:
- Migrating services from ASMX services
- Tighter control over XML serialization
- Using WCF with MsmqIntegrationBinding
The latter of these three examples is core reason why I have spent a lot of time investigating the use of serializers within WCF. Msmq integration binding relies upon the old Msmq API's used by the System.Messaging namespace in order to ensure interoperability with other legacy Msmq endpoints, such as BizTalk Server 2006 (pre R2).
The scenario I have been working with is that I want to use MsmqIntegrationBinding with BizTalk Server 2006 in the short term, and move to BizTalk Server 2006 R2 and NetMsmqBinding in the future. Thus in the future I want to move towards using the DataContractSerializer, but in the short term, I need to support the old XmlSerializer, because MsmqIntegrationBinding uses this serialization method internally.
Getting MsmqIntegrationBinding to work with complex data contracts
I have seen dozens of samples on the internet for using MsmqIntegrationBinding in WCF, and in short the basic mechanics are as follows:
- Create a service contract with a one way service operation that takes a single argument MsmqMessage<T>, where T is a data contract.
- Ensure the T of MsmqMessage<T> is specified using the ServiceKnownType attribute.
The problem is, all the examples I have seen use a single simple data contract to demonstrate this binding. When a more complex data contract is used, things get more difficult. For example if I have two data contracts A and B, and A exposes B as a data member, the above instructions alone do not work; the message is never received by the service implementation. The reason this would not work is because data contract B is not known to the serializer and thus A could not be serialized.
After much hunting, I found the solution was to implement serialization using the old XmlSerializer, using XmlRoot and XmlArray attributes to decorate each data contract. By using the XmlSerializerFormatAttribute, you don't need to use the data contract attributes at all, as WCF will use the old serializer instead throughout the service contract.
Comparing the DataContractSerializer with the XmlSerializer
In order to ensure a smooth transition from MsmqIntegrationBinding to NetMsmqIntegration binding I have opted to support both serializers in my data contracts, with a view to retiring the XmlSerializer as some point in the future. The problem is, the serializers handle things in different ways. The table below lists the differences:
DataContractSerializer | XmlSerializer | Resolution to serialization differences |
If ordering is not specified, the data members are serialized in alphabetical order | The properties are serialized in the order they appear in the class | Ensure the order argument is specified in the data member attribute in the order that the properties appear in the class. |
If the data contract contains an array of objects from a different XML namespace, the serialization will automatically set the namespace of the array to be that of the objects within the array. | The namespace of the array will be that of the outer data contract. | Ensure the XmlArray attribute is used against the array property to ensure that the array is serialized the same in both serializers. |
Additionally, you must ensure the XSD namespace for each DataContractAttribute and XmlRootAttribute match.
You can compare how the two serialization models match by running svcutil.exe and xsd.exe against the data contract assembly and look at the output XSD schemas.