tags:

views:

917

answers:

4

I have a C# WCF REST Service which allows the addition of a bookmark, by sending an HTTP POST request with the bookmark serialised in XML. I have specified the operation contract for the service, which picks up the xml and automatically deserialises the object for me. My problem is that the deserialisation only works correctly if the XML elements in the request are given in alphabetical order, and the values for any elements that are out of order are not populated.

This behaviour has been reported elsewhere: http://bit.ly/WUz6

I find this to be quite unsatisfactory; I consider the requirement to construct the XML in a specific order to be unnecessary, and a major headache. This is a major requirement to add to all clients of the service, and a source of potentially difficult problems to debug.

Is it possible to direct WCF to be XML element order agnostic?


Some further details for clarification purposes:

My operation contract looks like this:

[OperationContract]
[WebInvoke(Method="POST", UriTemplate = "/{username}/bookmarks", ResponseFormat = WebMessageFormat.Xml)]
public void PostBookmark(string username, RestBookmark newBookmark);

The RestMessage looks as follows:

[DataContract(Name = "Bookmark", Namespace = "")]
public class RestBookmark
{   
    [DataMember]
    public string BookmarkMd5 { get; set; }

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

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

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

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

If I send the following XML message, then only the UserName property of the RestMessage object will be populated when PostBookmark() is invoked:

<?xml version="1.0"?><Bookmark><UserName>nick.street</UserName><Url>http://www.stackoverflow.com&lt;/Url&gt;&lt;BookmarkMd5&gt;f184eb3347cf94f6ce5f5fc2844e3bdd&lt;/BookmarkMd5&gt;&lt;Description&gt;Developer Forum</Description><Title>Stack Overflow</Title></Bookmark>
A: 

Try setting the Order to 0 in the DataMember attribute (for all members):

[DataMember(Name = "Title", Order = 0)]

Jomit
Thanks for the suggestion. It didn't help unfortunately - it appears that when multiple items have the same ordering they revert to being in alphabetic order, rather than "unordered".
Nick Street
A: 

I haven't tried to do this myself, but I'll take a guess.

Would it help to create a [OnDeserializing] event on your DataContract that would fire just before deserialization? At that point maybe you could reorder the xml however it needs to be ordered so that deserialization would work properly.

If you have Juval Lowy's Programming WCF Services 2nd Edition, that's covered starting on page 107.

Here's the MSDN help page.

Terry Donaghe
Well, the more I look at it, I'm not sure you can get to the passed in XML at that point, but maybe you can use the hook somehow...
Terry Donaghe
+1  A: 

The DataContractSerializer requires strict ordering of elements for both versioning and performance reasons.

There are some options I can think of,

  1. write a message inspector to re-order the raw XML elements in AfterReceivedRequest before it's deserialized by dataContractSerializer.

  2. using the XmlSerializer for your services.

  3. develop HTTP raw XML message process service instead.

  4. pass the object as a dictionary (not recommended)

codemeit
I like the idea of using the XMLSerializer.
Terry Donaghe
Thanks for the help and clear answer!
Nick Street
A: 

If you are not going to specify Order in your DataMember attribute to reflect the order of the nodes then you must alphabetize the nodes in your xml.

Andrew Hare