Monday, September 29, 2014

Entity circular reference issue in wcf

WCF Services uses DataContractSerializer by default. when WCF tries to serialize the entities that have relationships with other entities, it embeds them inside each other multiple times by default. When we use Entity Framework and poco entities that have bi-directional relationships, if we need to return those entities from WCF methods, we get exception and circular references cause the serialization to fail. we need to tell DataContractSerializer to preserve the object references and act smarter and link objects together rather than copying multiple times.
There is a parameter in DataContractSerializer constructor that can be set to true to preserve the object references.

I found two ways to fix that issue:

1- using [DataContract(IsReference = true)] attribute on the entity

[DataContract(IsReference = true)]
    public class Customer
    { 
        [DataMember] 
        public string Name { get; set; } 

        [DataMember] 
        public Order Order { get; set; } 
    } 


2- using custom attribute on service operations


using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.ServiceModel;
using System.ServiceModel.Description;
using System.ServiceModel.Channels;
using System.ServiceModel.Dispatcher;
using System.Runtime.Serialization;

namespace MyWcfService
{
    [Serializable]
    public class DataContractSerializerCircularReferenceFixAttribute : Attribute, IOperationBehavior
    {
        private readonly DataContractSerializerCircularReferenceFixOperationBehavior _innerOperationBehavior;

        public DataContractSerializerCircularReferenceFixAttribute()
        {
        }

        public DataContractSerializerCircularReferenceFixAttribute(OperationDescription operation)
        {
            _innerOperationBehavior = new DataContractSerializerCircularReferenceFixOperationBehavior(operation);
        }

        public void AddBindingParameters(OperationDescription operationDescription, BindingParameterCollection bindingParameters)
        {
            if (_innerOperationBehavior == null)
                return;

            (_innerOperationBehavior as IOperationBehavior).AddBindingParameters(operationDescription, bindingParameters);
        }

        public void ApplyClientBehavior(OperationDescription operationDescription, ClientOperation clientOperation)
        {
            ReplaceDataContractSerializerOperationBehavior(operationDescription);
        }

        public void ApplyDispatchBehavior(OperationDescription operationDescription, DispatchOperation dispatchOperation)
        {
            ReplaceDataContractSerializerOperationBehavior(operationDescription);
        }

        public void Validate(OperationDescription operationDescription)
        {
            if (_innerOperationBehavior == null)
                return;

            (_innerOperationBehavior as IOperationBehavior).Validate(operationDescription);
        }

        private void ReplaceDataContractSerializerOperationBehavior(OperationDescription description)
        {
            var operationBehavior = description.Behaviors.Find<DataContractSerializerOperationBehavior>();

            if (operationBehavior == null)
                return;

            description.Behaviors.Remove(operationBehavior);
            description.Behaviors.Add(new DataContractSerializerCircularReferenceFixOperationBehavior(description));
        }
    }

    class DataContractSerializerCircularReferenceFixOperationBehavior : DataContractSerializerOperationBehavior
    {

        public DataContractSerializerCircularReferenceFixOperationBehavior(OperationDescription operation)
            : base(operation)
        {

        }

        public override XmlObjectSerializer CreateSerializer(Type type, string name, string ns, IList<Type> knownTypes)
        {

            return new DataContractSerializer(type, name, ns, knownTypes, this.MaxItemsInObjectGraph, this.IgnoreExtensionDataObject, true, this.DataContractSurrogate);

        }

        public override XmlObjectSerializer CreateSerializer(Type type, System.Xml.XmlDictionaryString name, System.Xml.XmlDictionaryString ns, IList<Type> knownTypes)
        {

            return new DataContractSerializer(type, name, ns, knownTypes, this.MaxItemsInObjectGraph, this.IgnoreExtensionDataObject, true, this.DataContractSurrogate);

        }

    } 
}


// WCF Service--------------------------------------


[ServiceContract]
public class MyService
{
    [OperationContract]
    [DataContractSerializerCircularReferenceFix]
    public Customer GetCustomer(string id){
      //code here
    }
}


4 comments:

Admin said...

I think you did an awesome job explaining it. Sure beats having to research it on my own. Thanks
BCOM 1st, 2nd & Final Year TimeTable 2020

Blog27999 said...

As stated by Stanford Medical, It is in fact the SINGLE reason women in this country get to live 10 years more and weigh 19 kilos lighter than we do.

(Just so you know, it is not related to genetics or some hard exercise and really, EVERYTHING about "how" they eat.)

P.S, I said "HOW", not "WHAT"...

Click this link to discover if this brief questionnaire can help you unlock your true weight loss possibility

brijesh kumar said...

led lights under bed can definitely add a wow factor to your bedroom, but it's also very practical and can bring great functionality.

Aida Vroman said...

Do you want to increase your blog traffic and reach out the target customers? Watch this video: https://www.youtube.com/watch?v=4aBp2WshNkM

Post a Comment