ef4 cause Circular reference in web service
I have a Reason object:
public class Reason
{
public virtual long Id { get; set; }
public virtual string Name { get; set; }
public virtual Company Company {get;set;}
}
I am using entity framework 4 and Company is navigation property to Company.
I also use webservices in order to return data to the client. I have web method that returns Reasons: [WebMethod]
public Reason[] GetCallReasons()
{
IReasonRepository rep =
ObjectFactory.GetInstance<IReasonRepository>();
return rep.GetReasonsList().ToArray();
}
Because of the ef4 I get the following exception for executing the web method:
A circular reference was detected while serializing an object of type 'System.Data.Entity.DynamicProxies.Reason_24A0E4BBE02EE6BC2CF30BB56CFCB670C7D9D96D03D40AF4D174B89C9D3C5537'
The problem accurs because ef4 adds property that can't be serialized:
In order to solve this and eli开发者_StackOverflow中文版minate the error, I can disable the navigation property by not making it virtual or by remove the navigation property. But I neet it and want to use the lazy loading feature.
I also can write spesific serializer for Reason but I have many many classes the I used in my web-services and write a serializer for all of them is a lot of work.
How can I solve this exception?..
There are multiple solutions for your problem and they really depend on the type of service you are using and on the type of serialization:
- The clean approach is using DTO (data transfer objects) as @Mikael already suggested. DTO is special object which transfers exactly what you need and nothing more. You can simply create DTOs to not contain circular references and use AutoMapper to map between entities and DTOs and vice versa. +1 for @Mikael because he was the first to mentioned this.
All other approaches are based on tweeking serialization as @Haz suggested:
- WCF and
DataContractSerializer
: explicitly mark your entities withDataContract[IsReference=true]
and all properties with[DataMember]
attributes. This will allow you to use circular references. If you are using T4 template to generate entities you must modify it to add these attributes for you. - WCF and
DataContractSerializer
: implicit serialization. Mark one of related navigation properties with[IgnoreDataMember]
attribute so that property is not serialized. XmlSerializer
: mark one fo related navigation properties with[XmlIgnore]
attribute- Other serializations: mark one of related navigation properties with
[NonSerialized]
(+1 for Haz he was the first to mention this) for common serialization or[ScriptIgnore]
for some JSON related serialization.
I usually write specific classes for the webservice. While this is some extra work it has the advantage that the webservice gets more robust as small changes in your entities won't go unoticed and silently fail on the side of the consumer/javascript. For example if I change the name of a property.
There are a few things you can do to reduce the work and one is to use AutoMapper which can automatically map between objects.
You haven't supplied the definition for your company class.... But I'm guessing you have a collection of Reason as a property.
Lazy loading in an SOA Enviroment doesn't really work. You can't have unlimited lazy navigation over a serialized class, once you leave the webmethod you have no way to call back into the original datacontext from the webmethod consumer to lookup the properites... so the serializer will try and visit all properties, including lazy properties at the time of serialization.
You need to disable serialization on one part of the circular reference, either on the Reason collection in Company class, or the Company in Reason class.
You can use the "NotSerialized" attribute to disable serialization of a particular field.
精彩评论