WCF and IList<T>

Here's an interesting problem I encountered recently with a WCF based web service and the humble IList<T> interface.

I'm working on a classic 3-teir system: Client/Application/Database. The Client and Application are using Windows Communication Foundation (WCF) to interact. For convenience, we have an assembly of Data Transfer Objects (or DTOs) which is shared across both the client and the server.

While working on a recent system enhancement, I encountered an odd error - a NotSupportedException with the message "Collection was of a fixed size".

The exception was thrown from this line of code:

fullReturn.Responses.Add(response);

Given that Responses is typed as an IList<Response>, this error didn't make a lot of sense to me.

Turns out that the culprit is the serialisation technique used by WCF. When the property is of type IList<T> the content is handled as an array - specifically a Response[]!! While Arrays implement the interface, they don't do so properly, throwing exceptions when you try to Add/Remove items:

In the .NET Framework version 2.0, the Array class implements the System.Collections.Generic.IList generic interface. ... when you cast an array to one of these interfaces is that members which add, insert, or remove elements throw NotSupportedException.
-- http://msdn.microsoft.com/en-us/library/system.array.aspx

Fixing the problem involved two steps - changing the serializer and converting the data.

By default (if you make no choice), the serializer used by WCF works by sending the private member variables of the object. When deserialized, the private members are set directly, bypassing all of your own code on the object. The DataContract serializer works by sending the public properties of the object, and uses the property set methods to write the information into the object when deserialized.

In my case, I needed to switch to the DataContract serializer so that I could easily get my code into the flow to convert the data received. Adding the necessary DataContract and DataMember attributes onto the DTO was straightforward. Next, I converted my Responses property from an auto-property into one with a backing field and some conversion code for the inbound value in the set method.

[DataMember]
public IList<Response> Responses
{
    get { return mResponses; }
    set { mResponses = new List<Response>(value);
}
 
private List<Response> mResponses;

Now, it doesn't matter that the serializer chooses to use a Response[] to send the data across the wire - the array is converted into the required list automatically on reception.

Blog Tags: 

Comments

WCF IList

Great post! Saved me some time.

Thank you!

Saved me a bunch of time, too.

Thanks..worked for me...Did

Thanks..worked for me...Did not save me time but I was looking in all the wrong places

ty

+1

Check out the parameters to svcutil

Irantha, the code discussed here isn't mine to share.

However, the only piece not already covered by the post is the change of arguments to the svcutil tool that is used to generate your WCF proxies. By default, svcutil uses Xml serialization; you need to add an argument to specify use of DataContract serialization.

Hope this helps,
Bevan.

Thanks!

Awesome post thanks for a quick solution to a problem that really shouldn't exist in the first place.