Search code examples
c#wcfdatacontractserializerdatacontract

Why would a WCF DataContract not serialize members in alphabetical order?


I have several DataContracts that looks similar to this (shortened for brevity):

[DataContract(Name = "ItemDTO", Namespace = "http://foo.com/")]
public class ItemDTO : IExtensibleDataObject
{
    [DataMember(IsRequired = true)]
    public string Name { get; set; }

    [DataMember]
    public string Value { get; set; }

    [DataMember(IsRequired = true)]
    public int Id { get; set; }

    public ExtensionDataObject ExtensionData { get; set; }
}

I hadn't taken notice of the serialized messages before but after a recent change, two things were done: I added a new property, called ReturnCode, and ran CodeMaid's "Reorganize", which alphabetized the properties.

It now looked something like this:

[DataContract(Name = "ItemDTO", Namespace = "http://foo.com/")]
public class ItemDTO : IExtensibleDataObject
{
    public ExtensionDataObject ExtensionData { get; set; }

    [DataMember(IsRequired = true)]
    public int Id { get; set; }

    [DataMember(IsRequired = true)]
    public string Name { get; set; }

    [DataMember]
    public int ReturnCode { get; set; }

    [DataMember]
    public string Value { get; set; }
}

According to Microsoft's page on Data Contract Member Order I realized ReturnCode would break the contract since the serializer would insert it before Value, so I added an Order attribute value, assuming the original order was alphabetic, yielding:

[DataContract(Name = "ItemDTO", Namespace = "http://foo.com/")]
public class ItemDTO : IExtensibleDataObject
{
    public ExtensionDataObject ExtensionData { get; set; }

    [DataMember(IsRequired = true, Order = 0)]
    public int Id { get; set; }

    [DataMember(IsRequired = true, Order = 1)]
    public string Name { get; set; }

    [DataMember(Order = 3)]
    public int ReturnCode { get; set; }

    [DataMember(Order = 2)]
    public string Value { get; set; }
}

This however threw an exception that the deserialized members were out of order. I rolled back to a prior changeset, before all the changes, and sure enough the original order of the members was not alphabetic in the SOAP request (viewed through Fiddler), but following the original order expressed in the code, ie: Name, Value, Id.

I'm currently in the process of adding Order values to all my old DTO types to sequence them according to their prior, pre-alphabetizing of the properties, arrangement. What I'd like to know is why the coded order instead of alphabetized order was being used by the serializer? Microsoft's rules say:

Next in order are the current type’s data members that do not have the Order property of the DataMemberAttribute attribute set, in alphabetical order.

Update:

After I added the Order values to sequence the properties in their original order, I again ran Fiddler and it's still using the order the items are literally coded in. In other words, for some reason, my WCF service is completely ignoring any serialization sequencing logic and just sequencing the properties by the order they appear in the .cs file. In fact, the only way I was able to get it to serialize properly was to physically rearrange the properties in each type to their original order. That worked, but it's not preferred.

Update 2 - Solution:

Following Dracor's advice, I added [XmlElement(Order = 1)] attributes and an XmlRootAttribute to my DTOs. The SOAP serialization DID end up following the ordering assigned by these attributes. I hadn't considered it but my service does use Castle DynamicProxy and so I'm guessing it's changing the serializer from DataContractSerializer to XmlSerializer.


Solution

  • Why don't you simply use XmlSerializer to Serialize/Deserialize your XML? It's way more forgiving than DataContractSerializer, and works most of the time.