DataContractSerializer: Working with class inheritence and circular references

DataContractSerializer is the default serializer used by WCF Services. Typically, we transmit data objects generated via Entity Framework or LINQ To SQL and do not get any serialization issues as the generated classes are ready to handle various serialization scenarios. Some days back, I needed to transmit my own business objects on the wire; encountered a few issues and learned how to handle them. This post will highlight two such issues that may happen when we transmit our own classes via WCF service.

  1. Dealing with inheritance hierarchies
  2. Dealing with circular references

1. Dealing with inheritance hierarchies
Suppose we have a Fruit class with derived classes Orange and Apple. Now, we need to return a list of fruits from a WCF service method like this:

public List<Fruit> GetSomeFruits()
{
  List<Fruit> list = new List<Fruit>;
  list.Add( new Orange() };
  list.Add( new Apple() };
  list.Add( new Mango() };
  return list;
}

If we try to call the above method from a client, it will throw a communication exception. Using the test method described in this post, we can see that the DataContractSerializer was unable to serialize the result throwing a System.Runtime.Serialization.SerializationException:

Type 'WebApplication1.CustomBO.Orange' with data contract name 'Orange:http://schemas.datacontract.org/2004/07/WebApplication1.CustomBO' is not expected. Consider using a DataContractResolver or add any types not known statically to the list of known types - for example, by using the KnownTypeAttribute attribute or by adding them to the list of known types passed to DataContractSerializer.

So the serializer does not know how to serialize a derived object (Orange) as a base object (Fruit). The exception message is quite detailed and presents us a few ways to tackle such situation. Here’s a quick list:

1. Add KnownTypeAttribute to the Fruit class
2. Add ServiceKnownTypeAttribute to the WCF method
3. Add KnownType entries to web.config
4. Create a DataContractResolver and associate it using a custom service host.

These methods are very well described in this, and this post by Youssef, as well as this post by Sowmy. Checkout the links for some detailed analysis.

2. Dealing with circular references
Assume we have a FruitBasket class that contains a collection of Fruit objects. If such relation is bi-directional (like the navigational properties Entity Framework creates), we will have a List property in our FruitBasket class and a FruitBasket property in our Fruit class:

public class FruitBasket
{
  List<Fruit> fruitCollection;
  public List<Fruit> FruitCollection
  {
    get { return this.fruitCollection; }
    set { this.fruitCollection = value; }
  }
}

public class Fruit
{
  FruitBasket basketContainer;
  public FruitBasket BasketContainer
  {
    get { return this.basketContainer; }
    set { this.basketContainer = value; }
  }
}

When we try to send such bi-directionally related objects with multiple Fruit objects containing a reference to the same FruitBasket object, we will get a SerializationException:

Object graph for type 'WebApplication1.CustomBO.Orange' contains cycles and cannot be serialized if reference tracking is disabled.

To solve this, we need to explicitly tell the DataContractSerializer that a single FruitBasket can be referenced by multiple Fruit objects. This can be done by decorating FruitBasket object with [DataContract(IsReference=true)]. For some more details, check out this MSDN document and this blog post by Zulfiqar. If our data classes share some base class (which is always a good idea), then we may simply decorate the top-level base class with such attribute and enjoy the beauty of referential serialization.

About these ads

5 Responses to “DataContractSerializer: Working with class inheritence and circular references”

  1. DotNetShoutout Says:

    DataContractSerializer: Working with class inheritence and circular references « Mehroz’s Experiments…

    Thank you for submitting this cool story – Trackback from DotNetShoutout…

  2. mrali Says:

    The [DataContract (IsReference = true)] part helped me solve my problem. Thanks for submitting this and helping out with my problem.

  3. Pierre Says:

    Hi,
    DataContractSerializer works perfectly on server side, but how can i use it on silverlith client (when data back to server)?
    thanks!

  4. relationships quotes Says:

    That is very fascinating, You are an excessively skilled blogger.
    I have joined your rss feed and look ahead
    to searching for extra of your fantastic post.
    Also, I have shared your web site in my social networks

  5. AngusP Says:

    So… how would I have to tackle this problem if I am deriving from a framework class, say “MarshalByRefObject” (or whatever class really)? If I set the IsReference property to true on my derived class, VS asks me to do so for every parent class of the derived object. Is there a global setting to achieve the same?


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.

Join 57 other followers

%d bloggers like this: