【问题标题】:ef4 cause Circular reference in web serviceef4 导致 Web 服务中的循环引用
【发布时间】:2011-08-11 08:28:16
【问题描述】:

我有一个 Reason 对象:

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

我正在使用实体框架 4,Company 是 Company 的导航属性。
我还使用网络服务将数据返回给客户端。
我有返回原因的网络方法:

  [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 编写特定的序列化程序,但我有很多类,我在我的 Web 服务中使用了很多类,并且为所有这些类编写一个序列化程序是很多工作。

我该如何解决这个异常?..

【问题讨论】:

    标签: c# .net web-services entity-framework serialization


    【解决方案1】:

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

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

    所有其他方法都基于 @Haz 建议的 tweeking 序列化:

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

    【讨论】:

    • 多么痛苦的方法。至少你可以做到。
    【解决方案2】:

    我通常为 web 服务编写特定的类。虽然这是一些额外的工作,但它的优势在于 Web 服务变得更加健壮,因为您的实体中的小变化不会被忽视,并且不会在消费者/javascript 方面静默失败。例如,如果我更改属性的名称。

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

    【讨论】:

      【解决方案3】:

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

      在 SOA 环境中延迟加载实际上并不奏效。您不能对序列化类进行无限制的惰性导航,一旦您离开 webmethod,您就无法从 webmethod 使用者回调原始数据上下文以查找属性……因此序列化程序将尝试访问所有属性,包括序列化时的惰性属性。

      您需要在循环引用的一部分上禁用序列化,无论是在 Company 类中的 Reason 集合上,还是在 Reason 类中的 Company 上。

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2016-07-10
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-04-23
        • 1970-01-01
        相关资源
        最近更新 更多