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