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
}
}