MaxItemsInObjectGraph and keeping references when serializing in WCF

Yesterday when I was implementing a new WCF service I encountered a problem that the response of the service contained too much items ("System.Runtime.Serialization.SerializationException : Maximum number of items that can be serialized or deserialized in an object graph is '65536'. Change the object graph or increase the MaxItemsInObjectGraph quota."). Items will probably also include types such as string, I only had about 2000 real object that needed to be returned.

After some searching I found a solution on http://blogs.inetium.com/blogs/dmork/archive/2007/02/27/896.aspx. In short what you need to do is to tell the DataContractSerializer that it should allow more items in the object graph but you can only set this value in the constructor of the DataContractSerializer.

A first possibility is that you create service and/or endpoint behaviors in the configuration of your WCF service:

<behaviors>
  <serviceBehaviors>
    <behavior name="LargeServiceBehavior">
      <dataContractSerializer maxItemsInObjectGraph="100000"/>
    </behavior>
  </serviceBehaviors>
</behaviors>

and

<behaviors>
  <endpointBehaviors>
    <behavior name="LargeEndpointBehavior">
      <dataContractSerializer maxItemsInObjectGraph="100000"/>
    </behavior>
  </endpointBehaviors>
</behaviors>

You add these in the <system.serviceModel> element. Don’t forget to set the "behaviorConfiguration" attribute in the configuration of your service or endpoint.

For most implementations this will work, of course for me it didn’t :-).

After a lot of trying and searching I realized that I already created a custom initialized DataContractSerializer. On the methods (OperationContract) of my service (ServiceContract) I already added a custom attribute to preserve references between objects when serializing. This attribute creates a DataContractSerializer with one of the constructors that allows you to preserve references. Because I created the DataContractSerializer myself the configuration was never taken into account. So in my solution I created new attribute that can take 2 parameters (a bool to preserve references and an integer to set the limit of the object grap).

code for the attribute :
public class CustomDataContractSerializerAttribute : Attribute, IOperationBehavior
{
   private bool _preserveReferences = false;
   private int _maxItemsInObjectGraph = 65536;

   public CustomDataContractSerializerAttribute(bool preserveReferences, int maxItemsInObjectGraph)
   {
      _preserveReferences = preserveReferences;
      _maxItemsInObjectGraph = maxItemsInObjectGraph;
   }

   public void AddBindingParameters(OperationDescription description, BindingParameterCollection parameters)
   {}

   public void ApplyClientBehavior(OperationDescription description, ClientOperation proxy)
   {
      IOperationBehavior innerBehavior = new CustomDataContractSerializerOperationBehavior(description, _preserveReferences, _maxItemsInObjectGraph);
      innerBehavior.ApplyClientBehavior(description, proxy);
   }
  
   public void ApplyDispatchBehavior(OperationDescription description, DispatchOperation dispatch)
   {
      IOperationBehavior innerBehavior = new CustomDataContractSerializerOperationBehavior(description, _preserveReferences, _maxItemsInObjectGraph);
      innerBehavior.ApplyDispatchBehavior(description, dispatch);
   }
  
   public void Validate(OperationDescription description)
   { }
}

code for the operation behavior :
public class CustomDataContractSerializerOperationBehavior : DataContractSerializerOperationBehavior
{
   private bool _preserveReferences = false;
   private int _maxItemsInObjectGraph = 65536;

   public CustomDataContractSerializerOperationBehavior(OperationDescription operationDescription, bool preserveReferences, int maxItemsInObjectGraph)
      : base(operationDescription)
   {
      _preserveReferences = preserveReferences;
      _maxItemsInObjectGraph = maxItemsInObjectGraph;
   }
  
   public override XmlObjectSerializer CreateSerializer(Type type, string name, string ns, IList knownTypes)
   {
      return new DataContractSerializer(type, name, ns, knownTypes, this.MaxItemsInObjectGraph, this.IgnoreExtensionDataObject, _preserveReferences, this.DataContractSurrogate);
   }

   public override XmlObjectSerializer CreateSerializer(Type type, XmlDictionaryString name, XmlDictionaryString ns, IList knownTypes)
   {
      return new DataContractSerializer(type, name, ns, knownTypes, _maxItemsInObjectGraph, this.IgnoreExtensionDataObject, _preserveReferences, this.DataContractSurrogate);
   }
}

and now I write my service contract like this :
[ServiceContract(Namespace = "urn:SomeNamespace/IServiceIntervace")]
public interface IServiceInterface
{
   [OperationContract(Name = "MyOperation", Action = "urn:SomeNamespace/IServiceIntervace/MyOperation")]
   [CustomDataContractSerializer(true, 100000)] /* preserve references and maximum 100000 items in the object graph */  
   MyReturnType MyOperation();
}

The original code of the attribute to preserve references comes from http://blogs.msdn.com/drnick/archive/2007/05/15/replacing-the-serializer-part-1.aspx, this article also explains some problems with previous versions of the code examples to create a custom initialized DataContractSerializer.

If you have problems with you services, don’t forget to enable tracing.

Other WCF articles:
- Tracing WCF messages
- WCF Routing
- Use your WCF proxies in a safe way

About these ads
This entry was posted in WCF and tagged , . Bookmark the permalink.

4 Responses to MaxItemsInObjectGraph and keeping references when serializing in WCF

  1. Pingback: Remote Server does not found MaxItemsInObjectGraph « Jitendra Kumar Sahoo

  2. Pingback: Remote Server does not found Part 1-MaxItemsInObjectGraph « Jitendra Kumar Sahoo

  3. Pingback: Reporting Services SharePoint Large Parameter List Issue & Fix « Dan English's BI Blog

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