Geeks With Blogs

The Life and Times of a Dev Yes, we're really that weird

Ran into a serialization problem with WCF the other day that was rather interesting to find and fix.  It wasn't a problem with WCF, in the end, but rather with what we were telling WCF to do.

So we have some complex entities that we're shoving through the serialization layer.  We also send through lists of these entities, and the list may have references to itself.  To keep our list sizes small, we've implemented a DataContractSerializerOperationBehavior where when we create the data serializer, we set preserve references to true (it's just a variable below, but its set to true elsewhere):

        private static XmlObjectSerializer CreateDataContractSerializer(Type type, string name, string Notification Services, IList<Type> knownTypes)
        {
            return new DataContractSerializer
            (
                type, 
                name, 
                Notification Services, 
                knownTypes,
                maxItemsInObjectGraph /*maxItemsInObjectGraph*/,
                ignoreExtensionDataObject/*ignoreExtensionDataObject*/,
                preserveObjectReferences/*preserveObjectReferences*/,
                surrogate/*dataContractSurrogate*/
            );
        }

To make things more complicated, we have some custom lists of our entities that have properties on them.  As you may not know, when serializing a custom collection, the object is treated as a collection and any custom properties are ignored and are not serialized, even if you mark them as a DataMember.  Rather annoying.  To get around this, we implemented an IDataContractSurrogate, which you can see is passed into the data serializer above.  In GetObjectToSerialize method of the surrogate class that we created, we look to see what type we're trying to serialize and if it's one of our custom collections, we create a new instance of a surrogate that has an internal list, but is not a collection class itself, populate it with the contents and properties of the object that is to be serialized and then pass the surrogate back to the serializer.  Since our surrogate class is not a collection, WCF detects it correctly and serializes it correctly.  Then, on deserialization, we create a new instance of the collection, set it's properties, and then iterate through the surrogate's list and add the items to the new custom collections list.

Everything's happy, right?

Nope.  Our custom collection requires that objects of the same type are added to it.  The objects themselves have a Name that tells us what they are.  Our objects also have children that can be of the same type as the parent and are stored in the same type of class.  More precisely:

<Set>
    <SetItem Name="AParentThing">
        <Children>
            <Set>
                <SetItem Name="AChildThing">
                    <ParentSetItem ref="AParentThing[0]"></ParentSetItem>
                    ... (Perhaps even more sets and set items)
                </SetItem>
            </Set>
        </Children>
    </SetItem>
    <SetItem Name="AParentThing">
        ...(May have many layers)
    </SetItem>
</Set>

The problem appeared when we tried to serialize the cases where a child set referred back to a parent set.  We were getting weird errors, caused by the constraint that required that all items in a set be of the same type.  For some reason, the Name wasn't being serialized, or so we thought.  And what was weird is that it worked right most of the time, but then would occasionally fail, and what's worse, if we ignored the error, everything would work like we thought it should.  We were sure we'd just found a bug with WCF.

Turns out that name just hadn't YET be serialized.

I'm not sure about the order of serialization with data members, but it appears to be pretty arbitrary, unless you set the order on the data member.  We'd done two things incorrectly.  1.  We didn't set IsRequired on all of our DataMembers, and since this is a version 1 product, all of our interface elements should be present.  In future versions, maybe that'll change, but for now, they should all be there.  2.  We assumed that the deserialization of child collections wouldn't happen until after all of the members of the entity containing that collection were serialized, which is not the case.  As a result, the collections, which had a reference back to the parent, would attempt to deserialize BEFORE the name property had deserialized.

To fix, we changed all of our data members to look like this:

        [DataMember(Order=0, IsRequired = true)]

Note that order is 0 based.  At first, we only put the order property on the Name element, but that just caused it to fail every time, since WCF appears to serialize everything without an order first, then follow the order priority second.  After updating the other methods to also have an order, the problem has disappeared.  The name is always serialized first.  Note however, that even though the message contains the data, the resulting object may not contain the data.

Fun, Fun, Fun!

Technorati Tags: ,,
Posted on Friday, August 15, 2008 11:38 AM | Back to top


Comments on this post: WCF Serialization and the empty object bug

# re: WCF Serialization and the empty object bug
Requesting Gravatar...
.Net 3.5 may have a better way of handling this

http://www.zamd.net/2008/05/20/DataContractSerializerAndIsReferenceProperty.aspx

Rick
Left by Rick on Jan 02, 2009 12:02 PM

# re: WCF Serialization and the empty object bug
Requesting Gravatar...
After a few hours looking for a solution to why my custom class wouldn't deserialize properly over wcf I read the first few paragraphs of your article and find the problem. My class T contains a List<T> and a parent reference typeof(T). I removed this and huzzah!

I was beginning to think I'd have to write my own xml serialize/deserialize logic, bleh. Thank you much!
Left by Digitalboon on Nov 24, 2009 10:11 PM

# re: WCF Serialization and the empty object bug
Requesting Gravatar...
This worked.. thank you so much!!
Left by Claude on Mar 21, 2013 1:51 AM

# re: WCF Serialization and the empty object bug
Requesting Gravatar...
Hi All,
I am running through the same problem where my Lists are getting initialized to Null at the client side.
Please suggest a solution. I have posted my query on this.

http://www.codeproject.com/Questions/634664/Generic-List-in-WCF-intialized-to-Null

Thanks in advance
Left by TU on Aug 10, 2013 12:07 AM

Your comment:
 (will show your gravatar)


Copyright © Robert May | Powered by: GeeksWithBlogs.net