JSON.NET的Self referencing loop detected with type的原因以及解决办法

模型中有循环引用是很常见的。例如,以下模型显示双向导航属性:

   1: public class Category
   2: {
   3:     public Category()
   4:     {
   5:         Products = new Collection<Product>();
   6:     }
   7:
   8:     public int Id { get; set; }
   9:     public string Name { get; set; }
  10:     public virtual ICollection<Product> Products { get; set; }
  11: }
  12:
  13: public class Product
  14: {
  15:     public int Id { get; set; }
  16:     public string Name { get; set; }
  17:     public virtual Category Category { get; set; }
  18: } 

通过生成EF API控制器与Web API一起使用时,默认情况下不起作用。使用json.net序列化器序列化时会发生以下错误:

Self referencing loop detected for property ‘Category‘ with type 
‘System.Data.Entity.DynamicProxies.Category_A97AC61AD05BA6A886755C779FD3F96E86FE903ED7C9BA9400E79162C11BA719‘. 
Path ‘[0].Products[0]‘ 

发生此错误是因为序列化程序不知道如何处理循环引用。(在xml序列化程序中也出现类似的错误)

禁用代理并包含引用

EF代理不适用于POCO数据序列化。有几种  解决方法。为了简单起见,我们只是在数据上下文类中禁用它:

   1: public CircularReferenceSampleContext() : base("name=CircularReferenceSampleContext")
   2: {
   3:     Database.SetInitializer(new CircularReferenceDataInitializer());
   4:     this.Configuration.LazyLoadingEnabled = false;
   5:     this.Configuration.ProxyCreationEnabled = false;
   6: } 

但是,在禁用代理之后,导航属性不会被延迟加载。因此,从数据库中检索数据时必须包含参考。将脚手架控制器代码更改为:

   1: public IEnumerable <Product> GetProducts()
   2: {
   3:     return db.Products.Include(p => p.Category).AsEnumerable();
   4: } 

包含调用将包含所有记录的参考数据。

修复1:全局忽略循环引用

json.net序列化器支持忽略全局设置的循环引用。一个快速解决方案是将下面的代码放在WebApiConfig.cs文件中:

   1: config.Formatters.JsonFormatter.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore;

简单的修复将使序列化程序忽略会导致循环的引用。但是,它有局限性:

  • 数据丢失循环参考信息
  • 该修补程序仅适用于JSON.net
  • 如果存在深度参考链,则无法控制参考级别

修复2:保留全局循环引用

第二个修复与第一个类似。只需将代码更改为:

   1: config.Formatters.JsonFormatter.SerializerSettings.ReferenceLoopHandling
   2:      = Newtonsoft.Json.ReferenceLoopHandling.Serialize;
   3: config.Formatters.JsonFormatter.SerializerSettings.PreserveReferencesHandling
   4:      = Newtonsoft.Json.PreserveReferencesHandling.Objects;

数据形状将在应用此设置后更改。

   1: [{ “$ ID” :“1” , “类别”:{ “$ ID” :“2” , “产品”:[{ “$ ID” :“3” , “类别”:{ “$ REF “:”2“ },”ID“:2, ” 名称“:”酸奶“ },{ ”$ REF“ :”1“ }],”ID“:1, ” 名称“:”日记“ }, ” Id“:1,“名称”:“全脂牛奶” },{ “$ ref”:“3” }]

$ id和$ ref保留所有引用,并使对象图级别保持不变,但客户端代码需要知道形状更改以消费数据,并且它仅适用于JSON.NET序列化程序。

修复3:忽略并保留参考属性

此修补程序在模型类上装饰属性以控制模型或属性级别上的序列化行为。忽略该属性:

   1: public class Category
   2: {
   3:     public int Id { get; set; }
   4:     public string Name { get; set; }
   5:
   6:     [JsonIgnore]
   7:     [IgnoreDataMember]
   8:     public virtual ICollection<Product> Products { get; set; }
   9: } 

JsonIgnore用于JSON.NET,IgnoreDataMember用于XmlDCSerializer。 
为了保持参考:

   1: // Fix 3
   2: [JsonObject(IsReference = true)]
   3: public class Category
   4: {
   5:     public int Id { get; set; }
   6:     public string Name { get; set; }
   7:
   8:     // Fix 3
   9:     //[JsonIgnore]
  10:     //[IgnoreDataMember]
  11:     public virtual ICollection<Product> Products { get; set; }
  12: }
  13:
  14: [DataContract(IsReference = true)]
  15: public class Product
  16: {
  17:     [Key]
  18:     public int Id { get; set; }
  19:
  20:     [DataMember]
  21:     public string Name { get; set; }
  22:
  23:     [DataMember]
  24:     public virtual Category Category { get; set; }
  25: } 

[JsonObject(IsReference = true)]适用于JSON.NET,[DataContract(IsReference = true)]适用于XmlDCSerializer。请注意:在类上应用DataContract后,您需要将DataMember添加到要序列化的属性。

这些属性可以应用于json和xml序列化器,并且可以为模型类提供更多的控制。

参考官方解决方案:https://code.msdn.microsoft.com/Loop-Reference-handling-in-caaffaf7

原文地址:https://www.cnblogs.com/hemajia/p/8555709.html

时间: 2024-08-02 10:45:22

JSON.NET的Self referencing loop detected with type的原因以及解决办法的相关文章

EF关于报错Self referencing loop detected with type的原因以及解决办法

1)具体报错 { "Message": "出现错误.", "ExceptionMessage": ""ObjectContent`1"类型未能序列化内容类型"application/json; charset=utf-8"的响应正文.", "ExceptionType": "System.InvalidOperationException", &q

错误:【Self referencing loop detected with type】

Newtonsoft环境:LINQ+Newtonsoft 问题:若两表间有外键,如图 如果代码按如下写法则会报错:[Self referencing loop detected with type] var result = db.T_ZiGeJingLi.Where(p => p.ID == Convert.ToInt32(ZGZSID)); string json = JsonConvert.SerializeObject(result); 经如下修改语句则会正常: var result =

EF实体生成关系导致相互循环取数据出现异常&quot;Self referencing loop detected for property &quot;

异常信息: Self referencing loop detected for property 'md_agent' with type 'System.Data.Entity.DynamicProxies.md_agent_5F7CB7C257B9164D0D18D2B3E8DA3838A3ED1C7F5D326A56B71D51234B89C401'. Path '[1].md_design[0]'. at Newtonsoft.Json.Serialization.JsonSerial

ef entity转json引起的Self referencing loop

问题简介:前段时间做项目时,将取到的entity往Redis cache里存放时报多重引用的错误. Self referencing loop detected for property 'CheckItemCategory' with type. 一.问题详情 1.chectItemCategory与CheckItem实体介绍 2.我们用ef取了List<CheckItemCategory>,以Json的形式存放到redis中.但在JsonConvert.SerializeObject时报多

json 得到时分秒为00:00:00,拿不到时分秒 解决办法

数据库查询时间没有了时分秒的解决办法        问题出处,公司一个项目中使用动态sql方式查询Oracle数据库,在展示时Date类型字段只展示日期,无时分秒.        分析:        1.众所周知Oralce的日期类型有很多种,Date ,Timestamp等.其中Date类型对用的是java.sql.Date类型,Timestamp对用的是java.sql.Timestamp类型.这两个类型均继承自java.util.Date,其中java.sql.Date是没有时分秒的大家

Delphi的idhttp报508 Loop Detected错误的原因

一般是访问https时才出现"508 Loop Detected",idhttp+IdSSLIOHandlerSocketOpenSSL,这个在上篇文章中讲过了. 由于该问题网上资料极少,连外文资料也没卵用,起初我也以为是idhttp的重定向设置问题,但确认过没设置错. idHttp.HandleRedirects := True; 不过相比https,http的话不会出现这个问题,这就很奇怪了,继续测试... 那么发现,访问普通的https是有返回数据的并且没有报"508

使用mysql innodb 使用5.7的json类型遇到的坑和解决办法

---------------------------------------------- #查询JSON的某个字段 select data -> '$.Host' from temp #创建虚拟列 ALTER TABLE temp ADD host varchar(128) GENERATED ALWAYS AS (json_extract(data,'$.Host')) VIRTUAL; #给虚拟列创建索引 ALTER TABLE temp ADD INDEX index_temp_hos

关于SSH 持久对象转Json双向关联解析过度的解决办法

小弟是一名被部分程序员所鄙视的培训狗,昨天做项目遇到一个问题,在SSH框架通过ajax向界面传递数据的时候,由于对象之间双向关联导致json解析过度,造成内存溢出,网上搜索了解决办法除了过滤某些关联对象之外就没有别的办法了,我的想法是通过设置解析深度来解决过度抓取的问题,开始也考虑性能问题,最好的解决办法就是做一个视图,单独写一个model .但是又不希望这样繁琐,后来发现换个观点一想,能解决这个过度解析的问题对系统的性能的提升其实也很大了,所以就自己动手准备写一个转换工具类,办法也很明了递归.

FastJson将json解析成含有泛型对象,内部泛型对象再次解析出错的解决办法(Android)

折腾小半天的问题,这里先感谢一下深圳的小伙子,远程帮我搞,虽然也没有搞出来==========FUCK 声明:Android开发下发生此异常,Java开发下并不会有这个问题 异常重现 简单说一下抛出异常的代码: (1)解析json代码如下: RecommendBean<RecommendListBean> obj = JSON.parseObject(jsonString, new TypeReference<RecommendBean<RecommendListBean>&