检测到类型的 JSON.NET 错误自引用循环
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/7397207/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
JSON.NET Error Self referencing loop detected for type
提问by NevenHuynh
I tried to serialize POCO class that was automatically generated from Entity Data Model .edmx and when I used
我试图序列化从实体数据模型 .edmx 和当我使用时自动生成的 POCO 类
JsonConvert.SerializeObject
I got the following error:
我收到以下错误:
Error Self referencing loop detected for type System.data.entity occurs .
检测到类型 System.data.entity 的错误自引用循环发生。
How do I solve this problem?
我该如何解决这个问题?
采纳答案by Bishoy Hanna
That was the best solution https://code.msdn.microsoft.com/Loop-Reference-handling-in-caaffaf7
这是最好的解决方案 https://code.msdn.microsoft.com/Loop-Reference-handling-in-caaffaf7
Fix 1: Ignoring circular reference globally
修复 1:全局忽略循环引用
(I have chosen/tried this one, as have many others)
(我已经选择/尝试过这个,还有很多其他的)
The json.net serializer has an option to ignore circular references. Put the following code in WebApiConfig.csfile:
json.net 序列化程序可以选择忽略循环引用。将以下代码放入WebApiConfig.cs文件:
config.Formatters.JsonFormatter.SerializerSettings.ReferenceLoopHandling
= Newtonsoft.Json.ReferenceLoopHandling.Ignore;
The simple fix will make serializer to ignore the reference which will cause a loop. However, it has limitations:
简单的修复将使序列化程序忽略将导致循环的引用。但是,它有局限性:
- The data loses the looping reference information
- The fix only applies to JSON.net
- The level of references can't be controlled if there is a deep reference chain
- 数据丢失循环参考信息
- 该修复仅适用于 JSON.net
- 如果有很深的引用链,就无法控制引用的级别
If you want to use this fix in a non-api ASP.NET project, you can add the above line to Global.asax.cs, but first add:
如果要在非 api ASP.NET 项目中使用此修复程序,可以将上述行添加到Global.asax.cs,但首先添加:
var config = GlobalConfiguration.Configuration;
If you want to use this in .Net Coreproject, you can change Startup.csas:
如果你想在.Net Core项目中使用它,你可以更改Startup.cs为:
var mvc = services.AddMvc(options =>
{
...
})
.AddJsonOptions(x => x.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore);
Fix 2: Preserving circular reference globally
修复 2:全局保留循环引用
This second fix is similar to the first. Just change the code to:
第二个修复类似于第一个。只需将代码更改为:
config.Formatters.JsonFormatter.SerializerSettings.ReferenceLoopHandling
= Newtonsoft.Json.ReferenceLoopHandling.Serialize;
config.Formatters.JsonFormatter.SerializerSettings.PreserveReferencesHandling
= Newtonsoft.Json.PreserveReferencesHandling.Objects;
The data shape will be changed after applying this setting.
应用此设置后,数据形状将发生变化。
[
{
"$id":"1",
"Category":{
"$id":"2",
"Products":[
{
"$id":"3",
"Category":{
"$ref":"2"
},
"Id":2,
"Name":"Yogurt"
},
{
"$ref":"1"
}
],
"Id":1,
"Name":"Diary"
},
"Id":1,
"Name":"Whole Milk"
},
{
"$ref":"3"
}
]
The $id and $ref keeps the all the references and makes the object graph level flat, but the client code needs to know the shape change to consume the data and it only applies to JSON.NET serializer as well.
$id 和 $ref 保留所有引用并使对象图级别平坦,但客户端代码需要知道形状更改才能使用数据,并且它也仅适用于 JSON.NET 序列化程序。
Fix 3: Ignore and preserve reference attributes
修复 3:忽略并保留引用属性
This fix is decorate attributes on model class to control the serialization behavior on model or property level. To ignore the property:
此修复是在模型类上装饰属性以控制模型或属性级别的序列化行为。要忽略该属性:
public class Category
{
public int Id { get; set; }
public string Name { get; set; }
[JsonIgnore]
[IgnoreDataMember]
public virtual ICollection<Product> Products { get; set; }
}
JsonIgnore is for JSON.NET and IgnoreDataMember is for XmlDCSerializer. To preserve reference:
JsonIgnore 用于 JSON.NET,IgnoreDataMember 用于 XmlDCSerializer。保留参考:
// Fix 3
[JsonObject(IsReference = true)]
public class Category
{
public int Id { get; set; }
public string Name { get; set; }
// Fix 3
//[JsonIgnore]
//[IgnoreDataMember]
public virtual ICollection<Product> Products { get; set; }
}
[DataContract(IsReference = true)]
public class Product
{
[Key]
public int Id { get; set; }
[DataMember]
public string Name { get; set; }
[DataMember]
public virtual Category Category { get; set; }
}
JsonObject(IsReference = true)]is for JSON.NET and [DataContract(IsReference = true)]is for XmlDCSerializer. Note that: after applying DataContracton class, you need to add DataMemberto properties that you want to serialize.
JsonObject(IsReference = true)]适用于 JSON.NET 和[DataContract(IsReference = true)]XmlDCSerializer。需要注意的是:应用DataContract到class后,需要添加DataMember要序列化的属性。
The attributes can be applied on both json and xml serializer and gives more controls on model class.
这些属性可以应用于 json 和 xml 序列化程序,并提供对模型类的更多控制。
回答by DalSoft
Use JsonSerializerSettings
使用 JsonSerializerSettings
ReferenceLoopHandling.Error(default) will error if a reference loop is encountered. This is why you get an exception.ReferenceLoopHandling.Serializeis useful if objects are nested but not indefinitely.ReferenceLoopHandling.Ignorewill not serialize an object if it is a child object of itself.
ReferenceLoopHandling.Error(默认)如果遇到引用循环会出错。这就是为什么你会得到一个例外。ReferenceLoopHandling.Serialize如果对象是嵌套的但不是无限期的,则很有用。ReferenceLoopHandling.Ignore如果对象是其自身的子对象,则不会序列化该对象。
Example:
例子:
JsonConvert.SerializeObject(YourPOCOHere, Formatting.Indented,
new JsonSerializerSettings {
ReferenceLoopHandling = ReferenceLoopHandling.Serialize
});
Should you have to serialize an object that is nested indefinitely you can use PreserveObjectReferencesto avoid a StackOverflowException.
如果您必须序列化无限嵌套的对象,您可以使用PreserveObjectReferences来避免 StackOverflowException。
Example:
例子:
JsonConvert.SerializeObject(YourPOCOHere, Formatting.Indented,
new JsonSerializerSettings {
PreserveReferencesHandling = PreserveReferencesHandling.Objects
});
Pick what makes sense for the object you are serializing.
选择对您正在序列化的对象有意义的内容。
Reference http://james.newtonking.com/json/help/
回答by smockle
The fix is to ignore loop references and not to serialize them. This behaviour is specified in JsonSerializerSettings.
解决方法是忽略循环引用而不是序列化它们。此行为在 中指定JsonSerializerSettings。
Single JsonConvertwith an overload:
SingleJsonConvert过载:
JsonConvert.SerializeObject(YourObject, Formatting.Indented,
new JsonSerializerSettings() {
ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore
}
);
Global Settingwith code in Application_Start()in Global.asax.cs:
Application_Start()在 Global.asax.cs 中使用代码进行全局设置:
JsonConvert.DefaultSettings = () => new JsonSerializerSettings {
Formatting = Newtonsoft.Json.Formatting.Indented,
ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore
};
Reference: https://github.com/JamesNK/Newtonsoft.Json/issues/78
回答by Sam Jones
The simplest way to do this is to install Json.NET
from nuget and add the [JsonIgnore]attribute to the virtual property in the class, for example:
最简单的方法是从 nuget安装Json.NET
并将该[JsonIgnore]属性添加到类中的虚拟属性中,例如:
public string Name { get; set; }
public string Description { get; set; }
public Nullable<int> Project_ID { get; set; }
[JsonIgnore]
public virtual Project Project { get; set; }
Although these days, I create a model with only the properties I want passed through so it's lighter, doesn't include unwanted collections, and I don't lose my changes when I rebuild the generated files...
尽管这些天,我创建了一个仅包含我想要传递的属性的模型,因此它更轻巧,不包含不需要的集合,并且在重建生成的文件时我不会丢失更改...
回答by Caleb
In .NET Core 1.0, you can set this as a global setting in your Startup.cs file:
在 .NET Core 1.0 中,您可以将其设置为 Startup.cs 文件中的全局设置:
using System.Buffers;
using Microsoft.AspNetCore.Mvc.Formatters;
using Newtonsoft.Json;
// beginning of Startup class
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc(options =>
{
options.OutputFormatters.Clear();
options.OutputFormatters.Add(new JsonOutputFormatter(new JsonSerializerSettings(){
ReferenceLoopHandling = ReferenceLoopHandling.Ignore,
}, ArrayPool<char>.Shared));
});
}
回答by Dave Skender
If you're using .NET Core 2.x, update your ConfigureServices section in Startup.cs
如果您使用的是 .NET Core 2.x,请更新 Startup.cs 中的 ConfigureServices 部分
https://docs.microsoft.com/en-us/ef/core/querying/related-data#related-data-and-serialization
https://docs.microsoft.com/en-us/ef/core/querying/related-data#related-data-and-serialization
public void ConfigureServices(IServiceCollection services)
{
...
services.AddMvc()
.AddJsonOptions(
options => options.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore
);
...
}
If you're using .NET Core 3.x without MVC, it would be:
如果您使用没有 MVC 的 .NET Core 3.x,它将是:
services.AddControllers()
.AddNewtonsoftJson(options =>
options.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore
);
This reference loop handling is almost mandatory if you're using Entity Framework and database-first design pattern.
如果您使用实体框架和数据库优先设计模式,则此参考循环处理几乎是强制性的。
回答by Carlos Barini
To serialize usin NEWTONSOFTJSON when you have loop issue, in my case I did not need modify global.asax or either apiconfig. I just use JsonSerializesSettings ignoring Looping handling.
要在出现循环问题时使用 NEWTONSOFTJSON 进行序列化,就我而言,我不需要修改 global.asax 或 apiconfig。我只是使用 JsonSerializesSettings 忽略循环处理。
JsonSerializerSettings jss = new JsonSerializerSettings();
jss.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
var lst = db.shCards.Where(m => m.CardID == id).ToList();
string json = JsonConvert.SerializeObject(lst, jss);
回答by Sanjay Nishad
We can add these two lines into DbContext class constructor to disable Self referencing loop, like
我们可以将这两行添加到 DbContext 类构造函数中以禁用自引用循环,例如
public TestContext()
: base("name=TestContext")
{
this.Configuration.LazyLoadingEnabled = false;
this.Configuration.ProxyCreationEnabled = false;
}
回答by Jaans
You can apply an attribute to the property too.
The [JsonProperty( ReferenceLoopHandling = ... )]attribute is well suited to this.
您也可以将属性应用于属性。该[JsonProperty( ReferenceLoopHandling = ... )]属性非常适合于此。
For example:
例如:
/// <summary>
/// Represents the exception information of an event
/// </summary>
public class ExceptionInfo
{
// ...code omitted for brevity...
/// <summary>
/// An inner (nested) error.
/// </summary>
[JsonProperty( ReferenceLoopHandling = ReferenceLoopHandling.Ignore, IsReference = true )]
public ExceptionInfo Inner { get; set; }
// ...code omitted for brevity...
}
Hope that helps, Jaans
希望有帮助,Jaans
回答by GerardBeckerleg
To ignore loop references and not to serialize them globally in MVC 6 use the following in startup.cs:
要忽略循环引用而不是在 MVC 6 中全局序列化它们,请在 startup.cs 中使用以下内容:
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc().Configure<MvcOptions>(options =>
{
options.OutputFormatters.RemoveTypesOf<JsonOutputFormatter>();
var jsonOutputFormatter = new JsonOutputFormatter();
jsonOutputFormatter.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore;
options.OutputFormatters.Insert(0, jsonOutputFormatter);
});
}

