Preserving Object Reference in WCF


By default object references are not preserved by the DataContractSerializer; Values of an object referenced multiple times is serialized multiple times. If the object is part of mutual (cyclic) reference (e.g. circular linked list) an exception is thrown during serialization.


 


DataContractSerializer can be made to preserve object reference by passing true for parameter PreserveObjectReference when constructing DataContractSerializer as shown below.


 


new DataContractSerializer(type, name, ns, knownTypes,


                0x7FFF /*maxItemsInObjectGraph*/,


                false/*ignoreExtensionDataObject*/,



                true/*preserveObjectReferences*/,


                null/*dataContractSurrogate*/);


 


Enabling in Service Operation


To enable this option in service operation one must pass an instance of DataContractSerializer to the WCF runtime. This can be done by sub classing DataContractSerializerOperationBehavior and overriding CreateSerializer method as shown below.


 


    class ReferencePreservingDataContractSerializerOperationBehavior


      :DataContractSerializerOperationBehavior


    {


        public ReferencePreservingDataContractSerializerOperationBehavior(


          OperationDescription operationDescription)


          : base(operationDescription) { }


        public override XmlObjectSerializer CreateSerializer(


          Type type, string name, string ns, IList<Type> knownTypes)


        {


            return CreateDataContractSerializer(type, name, ns, knownTypes);


        }


 


        private static XmlObjectSerializer CreateDataContractSerializer(


          Type type, string name, string ns, IList<Type> knownTypes)


        {


            return CreateDataContractSerializer(type, name, ns, knownTypes);


        }


 



        public override XmlObjectSerializer CreateSerializer(


          Type type, XmlDictionaryString name, XmlDictionaryString ns,


          IList<Type> knownTypes)


        {


            return new DataContractSerializer(type, name, ns, knownTypes,


                0x7FFF /*maxItemsInObjectGraph*/,


                false/*ignoreExtensionDataObject*/,


                true/*preserveObjectReferences*/,


                null/*dataContractSurrogate*/);


        }


    }


 


The behavior must be added to all the operations on the server side contract. For a self hosted server it can be done as shown below.


 


        ServiceHost host = new ServiceHost(


                             typeof(FooContractImpl), new Uri(address));


        host.AddServiceEndpoint(typeof(FooContract), binding, address);



        foreach (ServiceEndpoint endpoint in host.Description.Endpoints)


            SetDataContractSerializerBehavior(endpoint.Contract);


        host.Open();


 


Similary the behavior must be added to all the operations on the client side as shown below.


 


        ChannelFactory<FooContract> factory = new ChannelFactory<FooContract>(binding, new EndpointAddress(address));



        SetDataContractSerializerBehavior(factory.Endpoint.Contract);


        FooContract proxy = factory.CreateChannel();


 


The SetDataContractSerializerBehavior is defined as shown below.


    private static void SetDataContractSerializerBehavior(ContractDescription contractDescription)


    {


        foreach (OperationDescription operation in contractDescription.Operations)


        {


            operation.Behaviors.Add(new ReferencePreservingDataContractSerializerOperationBehavior(operation));


        }


    }


Enabling via Attribute


This is all good. However wouldn’t it be great if it is possible avoid all the imperative code and instead define an attribute as shown below?


 


[ServiceContract]


public interface FooContract


{


    [OperationContract]



    [ReferencePreservingDataContractFormat]


    Node EchoNode(Node node);


}


 


Yes this can be done by defining a custom attribute that implements IOperationBehavior as shown below.


 


public class ReferencePreservingDataContractFormatAttribute : Attribute, IOperationBehavior


{


    #region IOperationBehavior Members


    public void AddBindingParameters(OperationDescription description, BindingParameterCollection parameters)


    {


    }


 


    public void ApplyClientBehavior(OperationDescription description,System.ServiceModel.Dispatcher.ClientOperation proxy)


    {



        IOperationBehavior innerBehavior = new ReferencePreservingDataContractSerializerOperationBehavior(description);


        innerBehavior.ApplyClientBehavior(description, proxy);


    }


 


    public void ApplyDispatchBehavior(OperationDescription description,System.ServiceModel.Dispatcher.DispatchOperation dispatch)


    {



        IOperationBehavior innerBehavior = new ReferencePreservingDataContractSerializerOperationBehavior(description);


        innerBehavior.ApplyDispatchBehavior(description, dispatch);


    }


 


    public void Validate(OperationDescription description)


    {


    }


 


    #endregion


}


 


The complete sample is attached.

Program.cs

Comments (22)

  1. My grand boss … if someone had told me this&amp;nbsp;a year back … but it turns out that&amp;nbsp;it is a…

  2. Для тех, кому за 30. Для тех, кто не любит модных технологий. Для тех кто презир

  3. Aunque de manera predeterminada&#160;WCF no soporta el paso de referencias o el preservar grafos de objetos como se lo hac&#237;a con Remoting, esto no significa que no se lo pueda hacer. Si alguno de esto …

  4. Nizar says:

    It would make things easy if this could be configured for an entire app in the runtime.serialization section like so:

    <system.runtime.serialization>

      <dataContractSerializer preserveObjectReferences="true">

      </dataContractSerializer>

    </system.runtime.serialization>

  5. The following links to .NET resources have been collated over time with the assistance of colleagues.&amp;nbsp;…

  6. articles says:

    Introduction La technologie Windows Communication Foundation (WCF) propose deux méthodes en vue de définir

  7. A natural progression from yesterday’s article about creating a new serializer is to put that serializer

  8. Il post è un po vecchiotto ma torna sempre utile: By default object references are not preserved by the

  9. Serialization possibilities in the .NET Framework have been significantly augmented with the advent of

  10. dan_j_thompson@hotmail.com says:

    Why is preserving object references not the default?

  11. ScottVickery says:

    Bump.  Same question.   Why is preserving object references not the default?

  12. Steffen says:

    Some little error in this article. In the 'SetDataContractSerializerBehavior' you must remove the old behavior first. like this:

       private static void SetDataContractSerializerBehavior(ContractDescription contractDescription)

       {

           foreach (OperationDescription operation in contractDescription.Operations)

           {

               operation.Behaviors.Add(new ReferencePreservingDataContractSerializerOperationBehavior(operation));

           }

       }

  13. Steffen says:

    sry wrong code,  i mean this:

    foreach (OperationDescription operation in client.Endpoint.Contract.Operations)

               {

                   operation.Behaviors.Remove(typeof(DataContractSerializerOperationBehavior));

                   operation.Behaviors.Add(new DataContractSerializerOperationBehaviorEx(operation));

               }

  14. Critical error says:

    Why do you give a solution with a recursive stackoverflow function;

    private static XmlObjectSerializer CreateDataContractSerializer(

             Type type, string name, string ns, IList<Type> knownTypes)

           {

               return CreateDataContractSerializer(type, name, ns, knownTypes);

           }

    ?

  15. Bill Woodruff says:

    What is it going to take to get Microsoft to properly document WCF Serialization/Deserialization ?

Skip to main content