Saturday, March 17, 2012

Serialization ordering causes problems when using DataContactSerializer in WCF services

Have you ever created a WCF service and, when you’ve called it from a consuming application, some values appeared to come through just fine while other values were ignored?  Perhaps you’ve been stung by the default ordering rules that are applied when using the DataContractSerializer (the default choice in WCF).

First up, if you are not aware of how serialization in WCF works, here is a link to a good Msdn article which compares some of the differences between the various serialization techniques that are on offer in WCF: http://msdn.microsoft.com/en-us/magazine/cc163569.aspx

A big issue is the fact that the DataContractSerializer works on the order in which it expects to receive fields in the incoming messages. This can cause some very unexpected behaviour.

To describe the issue, we will first create a data contract to model an incoming message. The contract that we are modelling here contains 4 properties, 3 of which are Integers, and the other is an Enum value (not that that's significant).

The Data Contract
clip_image001

Next we create a simple service to receive our message and to do some processing over it. In this case we will receive the message and then simply write out the values that have been set by the deserialization process.

A Simple Serviceclip_image002

When using the DataContractSerializer to handle serialization in your web service, it is important to understand the default ordering rules that it uses and what that means in terms of the order in which elements are expected to appear.

Given our fairly simple type above, the main rule that we need to be aware of is that the properties are expected to be ordered alphabetically. If we obey that rule, then the results of our message processing work out just fine.

Default Ordering – OK
clip_image003

However look at what happens if we change the order of the elements in our request message.

Changed Ordering - Errorclip_image004

In this case, the DataContractSerializer has skipped the elements that were not found in the correct order and then moved on to processing the next element. This can have some pretty disastrous consequences because, not only is the data skipped for the elements that were out of order, but the corresponding properties now have incorrect values set for them!

Use the XmlSerializer

The default ordering issue is probably not a big deal if you are in a pure .NET environment and you have WCF at both ends of the communication. But how often does that happen these days? In our environment at work it is typical to have all types of clients that want to connect to our service - Classic ASP, Client Side Web Pages, and External Vendor applications.

In each of these scenarios, it is likely that the consumer of the service will craft the messages in such a manner that it is difficult to enforce and verify that the correct order is always obeyed. And the resulting bugs may not get picked up unless you have a very sophisticated and well disciplined UAT process!

A solution to this problem is to configure your service to use the XmlSerializer approach which has been around since the early days of .NET. This is achieved by simply annotating your service contract with an attribute to tell WCF that you want to override the default serialization technique.

Overriding the default serialization technique

clip_image005

Once we do this, elements can appear in any order because of how the XmlSerializer uses names to do element mapping.

clip_image006

The downsides of using the XmlSerializer are:

  • Using the XmlSerializer incurs additional performance costs because it generates strongly typed assemblies for the classes that are subject to the serialization process. However this can be avoided by pre-generating the assemblies that you need using the SGen tool.
  • DataContactSerializer has some additional attributes (Order and IsRequired) that can help with certain versioning scenarios.

The benefits or using XmlSerializer are:

  • Get around the ordering issues which results in less fragility in consuming applications.
  • Ability to easily work with Xml attributes as part of the serialization mapping on .NET types can aid interoperability and makes it easier to adopt a “contract first” approach to service implementation

No comments:

Post a Comment