[json] 유형에 대해 JSON.NET 오류 자체 참조 루프가 발견되었습니다.
Entity Data Model .edmx에서 자동으로 생성 된 POCO 클래스를 직렬화하려고했습니다.
JsonConvert.SerializeObject
다음과 같은 오류가 발생했습니다.
오류 System.data.entity 유형에 대해 자체 참조 루프가 발견되었습니다.
이 문제를 어떻게 해결합니까?
답변
이것이 최고의 솔루션이었습니다
https://code.msdn.microsoft.com/Loop-Reference-handling-in-caaffaf7
수정 1 : 전체적으로 순환 참조 무시
(다른 많은 사람들과 마찬가지로 이것을 선택 / 시도했습니다)
json.net 시리얼 라이저에는 순환 참조를 무시하는 옵션이 있습니다. 다음 코드를 WebApiConfig.cs파일에 넣으십시오 .
config.Formatters.JsonFormatter.SerializerSettings.ReferenceLoopHandling
= Newtonsoft.Json.ReferenceLoopHandling.Ignore;
간단한 수정으로 인해 serializer가 루프를 유발하는 참조를 무시하게됩니다. 그러나 다음과 같은 제한이 있습니다.
- 데이터에서 루핑 참조 정보가 손실됩니다
- 수정 사항은 JSON.net에만 적용됩니다.
- 딥 레퍼런스 체인이있는 경우 레퍼런스 레벨을 제어 할 수 없습니다
비 api ASP.NET 프로젝트에서이 수정 프로그램을 사용하려면 위의 행을에 추가 할 수 Global.asax.cs있지만 먼저 다음을 추가하십시오.
var config = GlobalConfiguration.Configuration;
.Net Core 프로젝트 에서 이것을 사용하려면 다음과 Startup.cs같이 변경할 수 있습니다 .
var mvc = services.AddMvc(options =>
{
...
})
.AddJsonOptions(x => x.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore);
수정 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 : 참조 속성 무시 및 보존
이 수정 사항은 모델 또는 속성 수준에서 직렬화 동작을 제어하기 위해 모델 클래스의 특성을 장식합니다. 속성을 무시하려면
public class Category
{
public int Id { get; set; }
public string Name { get; set; }
[JsonIgnore]
[IgnoreDataMember]
public virtual ICollection<Product> Products { get; set; }
}
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)]JSON.NET [DataContract(IsReference = true)]용이며 XmlDCSerializer 용입니다. DataContract클래스에 적용한 후 DataMember직렬화 할 속성 에 추가해야합니다 .
속성은 json 및 xml serializer 모두에 적용 할 수 있으며 모델 클래스에 대한 추가 제어를 제공합니다.
답변
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
});
직렬화 할 객체에 적합한 것을 선택하십시오.
답변
수정은 루프 참조를 무시하고 직렬화하지 않는 것입니다. 이 동작은에 지정되어 JsonSerializerSettings있습니다.
JsonConvert과부하가있는 싱글 :
JsonConvert.SerializeObject(YourObject, Formatting.Indented,
new JsonSerializerSettings() {
ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore
}
);
Application_Start()Global.asax.cs에 코드를 사용한 전역 설정 :
JsonConvert.DefaultSettings = () => new JsonSerializerSettings {
Formatting = Newtonsoft.Json.Formatting.Indented,
ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore
};
답변
가장 간단한 방법은 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; }
요즘에는 통과하려는 속성 만 사용하여 모델을 만들므로 더 가볍고 원치 않는 컬렉션이 포함되지 않으며 생성 된 파일을 다시 빌드 할 때 변경 사항을 잃지 않습니다 …
답변
.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));
});
}
답변
.NET Core 2.x를 사용하는 경우 Startup.cs에서 ConfigureServices 섹션을 업데이트하십시오.
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
);
...
}
MVC없이 .NET Core 3.x를 사용하는 경우 다음과 같습니다.
services.AddControllers()
.AddNewtonsoftJson(options =>
options.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore
);
이 참조 루프 처리는 Entity Framework 및 데이터베이스 우선 디자인 패턴을 사용하는 경우 거의 필수입니다.
답변
루프 문제가있을 때 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);
