Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/entity-framework/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Entity framework 在ASP.NET Web API中序列化对象时出现循环引用错误_Entity Framework_Asp.net Mvc 4_Serialization_Asp.net Web Api_Circular Reference - Fatal编程技术网

Entity framework 在ASP.NET Web API中序列化对象时出现循环引用错误

Entity framework 在ASP.NET Web API中序列化对象时出现循环引用错误,entity-framework,asp.net-mvc-4,serialization,asp.net-web-api,circular-reference,Entity Framework,Asp.net Mvc 4,Serialization,Asp.net Web Api,Circular Reference,我正在用C#编写一个Web API项目,它使用实体框架从数据库中提取数据,将其序列化并发送给客户机 我的项目有两个类,Post和Comment(来自Post的外键) 这些是我的课 邮班: public partial class Post { public Post() { this.Attachment = new HashSet<Attachment>(); this.Comment = new HashSet<Comment

我正在用C#编写一个Web API项目,它使用实体框架从数据库中提取数据,将其序列化并发送给客户机

我的项目有两个类,Post和Comment(来自Post的外键)

这些是我的课

邮班:

public partial class Post
{
    public Post()
    {
        this.Attachment = new HashSet<Attachment>();
        this.Comment = new HashSet<Comment>();
    }

    public int PostId { get; set; }
    public string Title { get; set; }
    public string Content { get; set; }
    public System.DateTime Created { get; set; }
    public Nullable<System.DateTime> Modified { get; set; }

    public virtual ICollection<Attachment> Attachment { get; set; }
    public virtual ICollection<Comment> Comment { get; set; }
}
我的问题是,当我试图通过Web API获取帖子时,它向我抛出以下错误:

Object graph for type 'APIServer.Models.Comment' contains cycles and cannot be serialized if reference tracking is disabled.
当我试图通过Web API获取评论时,错误如下:

Object graph for type 'System.Collections.Generic.HashSet`1[[APIServer.Models.Comment, APIServer, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]]'  contains cycles and cannot be serialized if reference tracking is disabled.
[OperationContract]
Comment FindComment(string criteria);
如果我用

[DataContract(IsReference = true)]
错误消失,但序列化只返回注释的ID,而忽略其他字段

对如何解决这个问题有什么建议吗

提前感谢,


Lester

您可以通过从Post属性定义中删除virtual来禁用注释类上的延迟加载

public partial class Comment
{
    public int CommentId { get; set; }
    public string Content { get; set; }
    public System.DateTime Posted { get; set; }
    public bool Approved { get; set; }
    public int AnswersTo { get; set; }
    public int PostId { get; set; }

    public Post Post { get; set; }
}
这应该可以解决循环引用异常。

这里有两种解决方案 解决方案#1:

我也有同样的问题,所以我用
DataContract
装饰了我的类,并且像你提到的那样用
DataMember
装饰了成员。但是,我不喜欢直接编辑自动生成的代码,因为每次重新生成文件时我都必须重做。为了解决这个问题,我使用了
MetadataType
属性。在你的情况下,看起来是这样的

首先,您将保持自动生成的实体的原样:

public partial class Comment
{
    public int CommentId { get; set; }
    public string Content { get; set; }
    public System.DateTime Posted { get; set; }
    public bool Approved { get; set; }
    public int AnswersTo { get; set; }
    public int PostId { get; set; }

    public virtual Post Post { get; set; }
}
接下来,在另一个文件中,您将创建另一个分部类,并按如下方式装饰它:

[MetadataType(typeof(Metadata))]
[DataContract(IsReference = true)]
public partial class Comment
{
    private class Metadata
    {
        [DataMember]
        public int CommentId { get; set; }
        [DataMember]
        public string Content { get; set; }
        [DataMember]
        public System.DateTime Posted { get; set; }
        [DataMember]
        public bool Approved { get; set; }
        [DataMember]
        public int AnswersTo { get; set; }
        [DataMember]
        public int PostId { get; set; }

        [DataMember]
        public virtual Post Post { get; set; } // you can remove "virtual" if you wish
    }
}
//From http://blogs.msdn.com/b/sowmy/archive/2006/03/26/561188.aspx and https://stackoverflow.com/questions/4266008/endless-loop-in-a-code-sample-on-serialization
public class ReferencePreservingDataContractFormatAttribute : Attribute, IOperationBehavior
{
    public void AddBindingParameters(OperationDescription description, BindingParameterCollection parameters)
    {
    }

    public void ApplyClientBehavior(OperationDescription description, System.ServiceModel.Dispatcher.ClientOperation proxy)
    {
        IOperationBehavior innerBehavior = new ReferencePreservingDataContractSerializerOperationBehavior(description);
        innerBehavior.ApplyClientBehavior(description, proxy);
    }

    public void ApplyDispatchBehavior(OperationDescription description, System.ServiceModel.Dispatcher.DispatchOperation dispatch)
    {
        IOperationBehavior innerBehavior = new ReferencePreservingDataContractSerializerOperationBehavior(description);
        innerBehavior.ApplyDispatchBehavior(description, dispatch);
    }

    public void Validate(OperationDescription description)
    {
    }

}
class ReferencePreservingDataContractSerializerOperationBehavior : DataContractSerializerOperationBehavior
{
    public ReferencePreservingDataContractSerializerOperationBehavior(OperationDescription operationDescription) : base(operationDescription) { }
    public override XmlObjectSerializer CreateSerializer(Type type, string name, string ns, IList<Type> knownTypes)
    {
        return new DataContractSerializer(type, name, ns, knownTypes,
            0x7FFF, //maxItemsInObjectGraph
            false,  //ignoreExtensionDataObject
            true,   //preserveObjectReferences
            null    //dataContractSurrogate
            );
    }

    public override XmlObjectSerializer CreateSerializer(Type type, XmlDictionaryString name, XmlDictionaryString ns, IList<Type> knownTypes)
    {
        return new DataContractSerializer(type, name, ns, knownTypes,
            0x7FFF, //maxItemsInObjectGraph
            false,  //ignoreExtensionDataObject
            true,   //preserveObjectReferences
            null    //dataContractSurrogate
            );
    }
}
MetadataType
基本上会将
元数据
好友类中的属性添加到
注释
中同名的属性中(不是直接添加,但出于我们的目的,它已经足够接近了……这是另一篇文章的主题)。当然,如果您的
注释
实体发生了更改,您需要相应地更新它

解决方案#2:

与直接编辑自动生成的文件相比,每次进行更改时都必须编辑第二个文件只是一个小小的改进。幸运的是,还有另一种更容易维护的方法。可以找到详细信息,但作为一个总结,您需要做的就是使用一个附加属性,
ReferencePreservingDataContractFormat
来修饰您的
OperationContract
。请注意,该页面上提供的代码中有一个微小的错误,它将导致无限递归。正如在文章中所指出的,修复非常简单:只需创建一个新的
DataContractSerializer

这种方法的优点是,无论您对
注释做了多少更改,您仍然不需要更新任何内容

作为代码示例,假设您正在使用
Comment
,如下所示:

Object graph for type 'System.Collections.Generic.HashSet`1[[APIServer.Models.Comment, APIServer, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]]'  contains cycles and cannot be serialized if reference tracking is disabled.
[OperationContract]
Comment FindComment(string criteria);
您只需添加

[OperationContract]
[ReferencePreservingDataContractFormat]
Comment FindComment(string criteria);
然后在其他地方需要定义
ReferencePreservingDataContractFormat
,如下所示:

[MetadataType(typeof(Metadata))]
[DataContract(IsReference = true)]
public partial class Comment
{
    private class Metadata
    {
        [DataMember]
        public int CommentId { get; set; }
        [DataMember]
        public string Content { get; set; }
        [DataMember]
        public System.DateTime Posted { get; set; }
        [DataMember]
        public bool Approved { get; set; }
        [DataMember]
        public int AnswersTo { get; set; }
        [DataMember]
        public int PostId { get; set; }

        [DataMember]
        public virtual Post Post { get; set; } // you can remove "virtual" if you wish
    }
}
//From http://blogs.msdn.com/b/sowmy/archive/2006/03/26/561188.aspx and https://stackoverflow.com/questions/4266008/endless-loop-in-a-code-sample-on-serialization
public class ReferencePreservingDataContractFormatAttribute : Attribute, IOperationBehavior
{
    public void AddBindingParameters(OperationDescription description, BindingParameterCollection parameters)
    {
    }

    public void ApplyClientBehavior(OperationDescription description, System.ServiceModel.Dispatcher.ClientOperation proxy)
    {
        IOperationBehavior innerBehavior = new ReferencePreservingDataContractSerializerOperationBehavior(description);
        innerBehavior.ApplyClientBehavior(description, proxy);
    }

    public void ApplyDispatchBehavior(OperationDescription description, System.ServiceModel.Dispatcher.DispatchOperation dispatch)
    {
        IOperationBehavior innerBehavior = new ReferencePreservingDataContractSerializerOperationBehavior(description);
        innerBehavior.ApplyDispatchBehavior(description, dispatch);
    }

    public void Validate(OperationDescription description)
    {
    }

}
class ReferencePreservingDataContractSerializerOperationBehavior : DataContractSerializerOperationBehavior
{
    public ReferencePreservingDataContractSerializerOperationBehavior(OperationDescription operationDescription) : base(operationDescription) { }
    public override XmlObjectSerializer CreateSerializer(Type type, string name, string ns, IList<Type> knownTypes)
    {
        return new DataContractSerializer(type, name, ns, knownTypes,
            0x7FFF, //maxItemsInObjectGraph
            false,  //ignoreExtensionDataObject
            true,   //preserveObjectReferences
            null    //dataContractSurrogate
            );
    }

    public override XmlObjectSerializer CreateSerializer(Type type, XmlDictionaryString name, XmlDictionaryString ns, IList<Type> knownTypes)
    {
        return new DataContractSerializer(type, name, ns, knownTypes,
            0x7FFF, //maxItemsInObjectGraph
            false,  //ignoreExtensionDataObject
            true,   //preserveObjectReferences
            null    //dataContractSurrogate
            );
    }
}
//来自http://blogs.msdn.com/b/sowmy/archive/2006/03/26/561188.aspx 及https://stackoverflow.com/questions/4266008/endless-loop-in-a-code-sample-on-serialization
公共类ReferencePreservingDataContractFormatAttribute:属性,IOperationBehavior
{
public void AddBindingParameters(操作说明、BindingParameterCollection参数)
{
}
public void ApplyClientBehavior(操作描述,System.ServiceModel.Dispatcher.ClientOperation代理)
{
IOperationBehavior innerBehavior=新引用保留数据契约序列化属性行为(描述);
ApplyClientBehavior(描述,代理);
}
public void ApplyDispatchBehavior(操作描述,System.ServiceModel.Dispatcher.DispatchOperation dispatch)
{
IOperationBehavior innerBehavior=新引用保留数据契约序列化属性行为(描述);
ApplyDispatchBehavior(描述、分派);
}
公共无效验证(操作说明)
{
}
}
类referencePreservingDataContractSerializeRopection行为:DataContractSerializeRopection行为
{
公共引用保留DataContractSerializePropertyBehavior(OperationDescription OperationDescription):基(OperationDescription){}
公共重写XmlObjectSerializer CreateSerializer(类型类型、字符串名称、字符串ns、IList knownTypes)
{
返回新的DataContractSerializer(类型、名称、ns、knownTypes、,
0x7FFF,//maxItemsInObjectGraph
false,//ignoreExtensionDataObject
true,//preserveObjectReferences
null//datacontractsubrogate
);
}
公共重写XmlObjectSerializer CreateSerializer(类型类型、XmlDictionaryString名称、XmlDictionaryString ns、IList knownTypes)
{
返回新的DataContractSerializer(类型、名称、ns、knownTypes、,
0x7FFF,//maxItemsInObjectGraph
false,//ignoreExtensionDataObject
true,//preserveObjectReferences
null//datacontractsubrogate
);
}
}
就这样


任何一种方法都可以很好地工作——选择一种适合您的方法。

解决方案2应该适用于WCF项目,我在这里测试了它不起作用。@IcyBrk-您一定做错了什么,因为我一直在WCF项目中使用它,而且它工作得很好。这解决了自引用导航属性吗?