JSON.NET错误检测到types的自我引用循环
我尝试序列化从实体数据模型.edmx自动生成的POCO类,当我使用
JsonConvert.SerializeObject
我得到了以下错误:
错误发生System.data.entitytypes检测到的自回参考循环。
我如何解决这个问题?
这是最好的解决schemehttp://code.msdn.microsoft.com/Loop-Reference-handling-in-caaffaf7
修复1:全局忽略循环引用
(我已经select/尝试过这个,就像其他许多人一样)
json.net序列化程序可以select忽略循环引用。 将下面的代码放在WebApiConfig.cs
文件中:
config.Formatters.JsonFormatter.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore;
简单的修复将使序列化程序忽略将导致循环的引用。 但是它有局限性:
数据丢失循环引用信息修复仅适用于JSON.net如果有深度引用链,引用的级别不能被控制
如果要在非api ASP.NET项目中使用此修补程序,可以将上面的代码行添加到Global.asax.cs
,但首先要添加:
var config = GlobalConfiguration.Configuration;
修复2:保留全局循环引用
第二个修复与第一个类似。 只需将代码更改为:
config.Formatters.JsonFormatter.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Serialize; config.Formatters.JsonFormatter.SerializerSettings.PreserveReferencesHandling = Newtonsoft.Json.PreserveReferencesHandling.Objects;
数据形状将在应用此设置后更改。
[ { "$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" } ]
$ 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序列化器,并且可以对模型类进行更多的控制。
使用JsonSerializerSettings
- 如果遇到参考循环,则
ReferenceLoopHandling.Error
(默认)将会出错。 这就是为什么你会得到一个例外。 - 如果对象是嵌套的,但不是无限的,则
ReferenceLoopHandling.Serialize
非常有用。 -
ReferenceLoopHandling.Ignore
不会序列化一个对象,如果它是它自己的子对象的话。
例:
JsonConvert.SerializeObject(YourPOCOHere, Formatting.Indented, new JsonSerializerSettings { ReferenceLoopHandling = ReferenceLoopHandling.Serialize });
如果你不得不序列化一个嵌套的对象,你可以使用PreserveObjectReferences来避免StackOverflowException。
例:
JsonConvert.SerializeObject(YourPOCOHere, Formatting.Indented, new JsonSerializerSettings { PreserveReferencesHandling = PreserveReferencesHandling.Objects });
select你正在序列化的对象是有意义的。
修复是忽略循环引用,而不是序列化它们。 此行为在JsonSerializerSettings
指定。
带过载的单个JsonConvert
:
JsonConvert.SerializeObject(YourObject, Formatting.Indented, new JsonSerializerSettings() { ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore } );
Global.asax.cs中的Application_Start()
中的代码的全局设置 :
JsonConvert.DefaultSettings = () => new JsonSerializerSettings { Formatting = Newtonsoft.Json.Formatting.Indented, ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore };
参考: https : //github.com/JamesNK/Newtonsoft.Json/issues/78
最简单的方法是将[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; }
虽然现在,我创build了一个只有我想要通过的属性的模型,所以它更轻,不包括不需要的集合,并且在重build生成的文件时不会丢失我的更改…
在.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)); }); }
我们可以将这两行添加到DbContext类构造函数中,以禁用自引用循环
public TestContext() : base("name=TestContext") { this.Configuration.LazyLoadingEnabled = false; this.Configuration.ProxyCreationEnabled = false; }
您也可以将属性应用于属性。 [JsonProperty( ReferenceLoopHandling = ... )]
属性非常适合这个。
例如:
/// <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... }
希望有所帮助,Jaans
要忽略循环引用,而不是在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); }); }
在WebApiConfig.cs
类中使用它:
var json = config.Formatters.JsonFormatter; json.SerializerSettings.PreserveReferencesHandling = Newtonsoft.Json.PreserveReferencesHandling.Objects; config.Formatters.Remove(config.Formatters.XmlFormatter);
对我来说,我必须走另一条路。 而不是试图修复JSON.Net序列化程序,我不得不在我的datacontext上延迟加载。
我刚刚添加到我的基础知识库:
context.Configuration.ProxyCreationEnabled = false;
“context”对象是我在我的基础知识库中使用的构造器参数,因为我使用dependency injection。 您可以改变ProxyCreationEnabled属性,而不是实例化您的datacontext。
http://techie-tid-bits.blogspot.com/2015/09/jsonnet-serializer-and-error-self.html
我有这个例外,我的工作解决scheme是简单,
通过向其添加JsonIgnore属性来忽略引用属性:
[JsonIgnore] public MyClass currentClass { get; set; }
在您反序列化时重置属性:
Source = JsonConvert.DeserializeObject<MyObject>(JsonTxt); foreach (var item in Source) { Source.MyClass = item; }
使用Newtonsoft.Json;
只需将Configuration.ProxyCreationEnabled = false;
在上下文文件中; 这将解决问题。
public demEntities() : base("name=demEntities") { Configuration.ProxyCreationEnabled = false; }
当你有循环问题序列化使用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);
我喜欢Application_Start()
的解决scheme,就像这里的答案一样
显然,我无法使用函数中的configuration访问JavaScript中的json对象,就像在DalSoft的回答中一样,因为返回的对象在对象的(key,val)上有“\ n \ r”。
无论如何,任何作品都是伟大的(因为不同的方法根据所提出的意见和问题在不同的场景下工作),但是通过一些标准的方法来支持这种方法会更好。