ef4导致Web服务中的循环引用

我有一个Reason对象:

public class Reason { public virtual long Id { get; set; } public virtual string Name { get; set; } public virtual Company Company {get;set;} } 

我使用entity framework4,公司是公司的导航属性。
我还使用webservices将数据返回给客户端。
我有web方法返回原因:

  [WebMethod] public Reason[] GetCallReasons() { IReasonRepository rep = ObjectFactory.GetInstance(); return rep.GetReasonsList().ToArray(); } 

由于ef4,我在执行web方法时遇到以下exception:

 A circular reference was detected while serializing an object of type 'System.Data.Entity.DynamicProxies.Reason_24A0E4BBE02EE6BC2CF30BB56CFCB670C7D9D96D03D40AF4D174B89C9D3C5537' 

问题是因为ef4添加了无法序列化的属性: rep.GetReasonsList()上的监视面板图像.ToArray()

为了解决这个问题并消除错误,我可以通过不使虚拟或删除导航属性来禁用导航属性。 但我知道它并想要使用延迟加载function。

我也可以为Reason编写特定的序列化器,但是我在我的web服务中使用了许多类,并为所有这些编写序列化器是很多工作。

我怎样才能解决这个exception?

您的问题有多种解决方案,它们实际上取决于您使用的服务类型和序列化类型:

  • 正如@Mikael已经建议的那样,干净的方法正在使用DTO(数据传输对象)。 DTO是一个特殊的对象,可以准确传输您所需要的内容,仅此而已。 您可以简单地创建DTO以不包含循环引用,并使用AutoMapper在实体和DTO之间进行映射,反之亦然。 为@Mikael +1,因为他是第一个提到这个的人。

所有其他方法都基于推文序列化,如@Haz建议:

  • WCF和DataContractSerializer :使用DataContract[IsReference=true]显式标记您的实体,使用[DataMember]属性显式标记所有属性。 这将允许您使用循环引用。 如果您使用T4模板生成实体,则必须对其进行修改以为您添加这些属性。
  • WCF和DataContractSerializer :隐式序列化。 使用[IgnoreDataMember]属性标记其中一个相关导航属性,以便不对该属性进行序列化。
  • XmlSerializer :使用[XmlIgnore]属性标记一个相关的导航属性
  • 其他序列化:使用[NonSerialized]标记其中一个相关的导航属性(对于常见的序列化,他是第一个提到这个的Haz,或者对于某些与JSON相关的序列化的[ScriptIgnore]

我经常为webservice编写特定的类。 虽然这是一些额外的工作,但它具有以下优势:web服务变得更加健壮,因为实体中的小变化不会消失,并且在消费者/ javascript方面无声地失败。 例如,如果我更改属性的名称。

您可以做一些事情来减少工作,一个是使用可以自动在对象之间映射的AutoMapper。

您还没有为您的公司类提供定义….但我猜您有一个Reason作为属性的集合。

SOA环境中的延迟加载并不真正起作用。 您不能在序列化类上进行无限的延迟导航,一旦离开web方法,您无法从webmethod使用者回调到原始datacontext中以查找属性…因此序列化程序将尝试访问所有属性,包括序列化时的惰性属性。

您需要在循环引用的一部分上禁用序列化,可以是公司类中的Reason集合,也可以是Reason类中的Company。

您可以使用“NotSerialized”属性禁用特定字段的序列化。