我有一个Reason对象:
public class Reason
{
public virtual long Id { get; set; }
public virtual string Name { get; set; }
public virtual Company Company {get;set;}
}
我使用实体框架4,公司是公司的导航属性 我还使用webservices将数据返回给客户端 我有web方法返回原因:
[WebMethod]
public Reason[] GetCallReasons()
{
IReasonRepository rep =
ObjectFactory.GetInstance<IReasonRepository>();
return rep.GetReasonsList().ToArray();
}
由于ef4,我在执行Web方法时遇到以下异常:
A circular reference was detected while serializing an object of type 'System.Data.Entity.DynamicProxies.Reason_24A0E4BBE02EE6BC2CF30BB56CFCB670C7D9D96D03D40AF4D174B89C9D3C5537'
问题是因为ef4添加了无法序列化的属性:
为了解决这个问题并消除错误,我可以通过不使虚拟或删除导航属性来禁用导航属性。但我知道它并希望使用延迟加载功能。
我也可以为Reason编写特定的序列化程序但是我在我的网络服务中使用了许多类,并为所有这些编写了一个序列化程序是很多工作。
如何解决此异常?..
答案 0 :(得分:11)
您的问题有多种解决方案,它们实际上取决于您使用的服务类型和序列化类型:
所有其他方法都是基于@Haz建议的推文序列化:
DataContractSerializer
:使用DataContract[IsReference=true]
明确标记您的实体,并使用[DataMember]
属性明确标记所有属性。这将允许您使用循环引用。如果您使用T4模板生成实体,则必须对其进行修改以为您添加这些属性。DataContractSerializer
:隐式序列化。使用[IgnoreDataMember]
属性标记其中一个相关导航属性,以便不对该属性进行序列化。XmlSerializer
:使用[XmlIgnore]
属性[NonSerialized]
标记其中一个相关的导航属性(对于常见的序列化标记为第一个提及此内容的+1)或对于某些与JSON相关的序列化标记为[ScriptIgnore]
。答案 1 :(得分:8)
我通常会为webservice编写特定的类。虽然这是一些额外的工作,但它具有以下优势:web服务变得更加健壮,因为实体中的小变化不会消失,并且在消费者/ javascript方面无声地失败。例如,如果我更改属性的名称。
您可以采取一些措施来减少工作,其中一项是使用可以自动在对象之间进行映射的AutoMapper。
答案 2 :(得分:4)
您尚未提供公司类的定义....但我猜您有一个Reason作为财产的集合。
SOA环境中的延迟加载并不真正起作用。您不能在序列化类上进行无限的延迟导航,一旦离开web方法,您无法从web方法使用者回调到原始datacontext以查找属性...因此序列化程序将尝试访问所有属性,包括序列化时的惰性属性。
您需要在循环引用的一部分上禁用序列化,可以是公司类中的Reason集合,也可以是Reason类中的Company。
您可以使用“NotSerialized”属性禁用特定字段的序列化。