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

2023-11-26

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

我的项目有 2 个类,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; }
}

评论类:

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; }
}

我的问题是,当我尝试通过 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.

如果我用以下注释 Comment 类

[DataContract(IsReference = true)]

错误消失,但序列化仅返回评论的 ID,而忽略其他字段。

关于如何解决这个问题有什么建议吗?

提前致谢,

Léster


这里有2个解决方案

解决方案#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
    }
}

MetadataType本质上会添加来自Metadata好友类别中的同名成员Comment(不是直接的,但就我们的目的而言,它足够接近......这是另一篇文章的主题)。当然,如果你的Comment实体发生变化,您需要相应地更新它。

解决方案#2:

每次进行更改时都必须编辑第二个文件,这与直接编辑自动生成的文件相比只是一个微小的改进。幸运的是,还有另一种更容易维护的方法。详情可查here但总而言之,您所需要做的就是装饰您的OperationContract那是消耗Comment具有附加属性,ReferencePreservingDataContractFormat。请注意,该页面上提供的代码中有一个轻微错误,可能会导致无限递归。如中所述this帖子,修复非常简单:根本不用递归,只需创建一个新的DataContractSerializer

这种方法的优点是无论你改变多少Comment,您仍然不需要更新任何内容。

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

[OperationContract]
Comment FindComment(string criteria);

您需要做的就是添加

[OperationContract]
[ReferencePreservingDataContractFormat]
Comment FindComment(string criteria);

然后你需要在其他地方定义ReferencePreservingDataContractFormat看起来像这样:

//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
            );
    }
}

就是这样!

两种方法都可以,选择适合您的方法。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

在 ASP.NET Web API 中序列化对象时出现循环引用错误 的相关文章

随机推荐

  • 视口标签在 Chrome 上不起作用

    我正在 Chrome 中使用设备指标覆盖来测试较小分辨率 本例中为 320x480 的响应式网站 在这种情况下 我的视口元标记不会对页面产生任何影响 徽标会显得很小 而且完全无法辨认 或多或少 我会说我看到的一切都是 0 5 比例的 这是我
  • 谷歌地图,cellid 到位置

    根据这个样本 http www codeproject com KB mobile DeepCast aspx 发送 cellid 信息 MCC MNC towerid 等 时可以请求 GPS 坐标 经度和纬度 包括范围 有人可以告诉我请求
  • chrome localstorage 中的 google_experiment_mod 是什么意思

    我正在 Chrome 本地存储中存储一些项目 连同我的变量我可以看到 google experiment mod 335 我想知道这意味着什么 下面是存储项目的代码 我使用 chrome 开发人员工具来查看内容 localStorage s
  • 在 C# 中访问成员时,“this”关键字是可选的吗?

    我注意到 如果类中有私有成员 则只需引用它的名称即可在类方法中访问它 你不需要说this memberName just memberName作品 那么 this 关键字在成员访问的上下文中是可选的吗 我确实认为当您想要澄清范围时 当您有两
  • 如何异步调用 WebViewClient.shouldInterceptRequest

    我想创建一个 Intranet 应用程序 该应用程序将显示通常只能在我们的内部环境中访问的内容 例如http intranet ourfirm com 现在我们可以从外部访问此内容 例如https ourproxy com ourIntra
  • 如何从 Azure 应用服务设置 mailSettings - 应用程序设置

    电子邮件服务器的当前设置已签入版本控制
  • kotlin int 盒装身份

    在文档中我们有 请注意 数字装箱不会保留身份 但接下来的例子给出了不同的结果 val number1 127 val b1 Int number1 val b2 Int number1 print b1 b2 this prints tru
  • 如何使用express 4.x获取ip客户端

    我想获取客户端的 IP 我正在尝试使用 localhost 127 0 0 1 但我总是得到 1 我正在尝试使用 app enable trust proxy app set trust proxy loopback app get fun
  • 分支预测与分支目标预测

    我理解得对吗 if语句更依赖于分支预测 v表查找更依赖于分支目标预测 关于v表 没有 分支预测 只有目标预测 尝试了解 CPU 如何处理 v 表 分支预测是预测分支是否会出现taken 分支目标预测就是预测where分行要去 这两件事是独立
  • 如何在 MySQL 中执行 FULL OUTER JOIN?

    我想做一个完全外连接在 MySQL 中 这可能吗 是一个完全外连接MySQL 支持吗 你没有完全连接在 MySQL 中 但你可以确定效仿他们 求一个代码sample转录自这个堆栈溢出问题你有 有两个表 t1 t2 SELECT FROM t
  • 类似于iPhone上的短信应用程序的文本输入框

    我在尝试获取像短信应用程序中那样的输入框时遇到了麻烦 任何人都可以提供一些关于如何构建其中之一并使其看起来不错的指导吗 我需要一个形状与 UITextfield 类似的输入框 但在打字时会垂直拉伸 我假设我需要计算文本的宽度并在文本换行时垂
  • UIButton按下后弹出UIDatePicker

    如何在按下 UIButton 后使 UIDatePicker 弹出 动画 然后在选择日期后再次关闭 这是在 iPhone 上 canihazcode 是的先生 谢谢你帮我拖延时间 void changeDate UIDatePicker s
  • 由于上传亚马逊服务项目而出现 SSLException

    我将文件从 android 上传到 aws 服务 我这样配置 AwsMetadata awsMetadata resultData getParcelable Params CommandMessage EXTRA MESSAGE AWSC
  • 寻求有关 SICP 练习 1.5 的一些解释

    问题可以找到here 在书中 我发现对正常订单评估的描述是 另一种评估模型在需要操作数的值之前不会评估操作数 相反 它会首先用操作数表达式替换参数 直到获得仅涉及原始运算符的表达式 然后执行评估 我还发现了另一个简短的描述 充分扩展然后缩小
  • 如何在 cakephp 上实现 facebook 之类的通知?

    有人知道如何实现类似 facebook 的通知吗 这个想法是在选项卡上放置通知 与数据库中所做的更改并行 而不刷新站点 如果数据被添加到数据库中 站点应该对其做出反应 谢谢 干杯 Facebook 风格的通知是在 Web 应用程序中使用以下
  • jQuery 验证插件:如何将错误视为警告并允许表单提交?

    正如主题所示 我正在使用 bassistance de 验证插件 http docs jquery com Plugins Validation 即使存在验证错误 我也希望能够提交表单 基本上 我们只想使用该插件来警告用户潜在的问题 我知道
  • 用boto设置hadoop参数?

    我正在尝试在我的 Amazon Elastic MapReduce 作业上启用错误输入跳过 我正在遵循这里描述的美妙食谱 http devblog factual com practical hadoop streaming dealing
  • jQuery mobile 是与 PhoneGap 集成的最佳 UI 框架吗?或者我应该使用离子? [关闭]

    Closed 这个问题是基于意见的 目前不接受答案 我想使用 PhoneGap 启动企业应用程序 但不知道所有移动 UI 框架中哪一个最适合与该项目集成 我是 PhoneGap 的新手 如果您想在 jQuery Mobile 和 Ionic
  • 检查一个字符串中的单词是否在另一个字符串中的最快方法是什么?

    我有一串文字 让我们称呼他们吧bad bad foo bar baz 我可以将此字符串保留为空格分隔的字符串 或作为列表 bad bad split 如果我有另一个字符串 如下所示 str This is my first foo stri
  • 在 ASP.NET Web API 中序列化对象时出现循环引用错误

    我正在用 C 编写一个 Web API 项目 该项目使用实体框架从数据库中提取数据 将其序列化并将其发送到客户端 我的项目有 2 个类 Post 和 Comment 来自 Post 的外键 这些是我的课程 岗位课程 public parti