Programing

유형에 대해 JSON.NET 오류 자체 참조 루프가 발견되었습니다.

lottogame 2020. 2. 17. 22:06
반응형

유형에 대해 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
});

직렬화 할 객체에 적합한 것을 선택하십시오.

참조 http://james.newtonking.com/json/help/


수정은 루프 참조를 무시하고 직렬화하지 않는 것입니다. 이 동작은에 지정되어 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
};

참조 : https://github.com/JamesNK/Newtonsoft.Json/issues/78


이를 수행하는 가장 간단한 방법은 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));
        });
    }

이 두 줄을 DbContext 클래스 생성자에 추가하여 다음과 같이 자체 참조 루프를 비활성화 할 수 있습니다.

public TestContext()
        : base("name=TestContext")
{
    this.Configuration.LazyLoadingEnabled = false;
    this.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);

.NET Core 2.0을 사용하는 경우 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
    );

...
}

속성에도 속성을 적용 할 수 있습니다. [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...    
}

도움이 되길 바랍니다


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 직렬 변환기를 수정하는 대신 데이터 컨텍스트에서 지연 로딩을 수행해야했습니다.

방금 이것을 기본 저장소에 추가했습니다.

context.Configuration.ProxyCreationEnabled = false;

"context"객체는 의존성 주입을 사용하기 때문에 기본 저장소에서 사용하는 생성자 매개 변수입니다. 대신 데이터 컨텍스트를 인스턴스화하는 모든 곳에서 ProxyCreationEnabled 속성을 변경할 수 있습니다.

http://techie-tid-bits.blogspot.com/2015/09/jsonnet-serializer-and-error-self.html


나는이 예외가 있었고 작업 솔루션은 쉽고 간단합니다.

JsonIgnore 속성을 추가하여 Referenced 속성을 무시하십시오.

[JsonIgnore]
public MyClass currentClass { get; set; }

역 직렬화 할 때 속성을 재설정하십시오.

Source = JsonConvert.DeserializeObject<MyObject>(JsonTxt);
foreach (var item in Source)
        {
            Source.MyClass = item;
        }

Newtonsoft.Json 사용;


팀:

이것은 ASP.NET Core에서 작동합니다. 위의 과제는 '설정을 무시하도록 설정하는 방법'입니다. 응용 프로그램 설정 방법에 따라 매우 어려울 수 있습니다. 여기 나를 위해 일한 것이 있습니다.

이것은 공공 void ConfigureServices (IServiceCollection services) 섹션에 배치 할 수 있습니다.

services.AddMvc().AddJsonOptions(opt => 
        { 
      opt.SerializerSettings.ReferenceLoopHandling =
      Newtonsoft.Json.ReferenceLoopHandling.Ignore;
        });

사람들은 이미 클래스의 가상 속성에 [JsonIgnore]가 추가되는 것에 대해 이야기했습니다.

[JsonIgnore]
public virtual Project Project { get; set; }

또한 다른 옵션 인 [JsonProperty (NullValueHandling = NullValueHandling.Ignore)]를 공유하여 속성이 null 인 경우에만 직렬화에서 속성을 생략합니다.

[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
public virtual Project Project { get; set; }

간단하게 배치 Configuration.ProxyCreationEnabled = false;상황에 맞는 파일 내부; 문제가 해결됩니다.

public demEntities()
    : base("name=demEntities")
{
    Configuration.ProxyCreationEnabled = false;
}

사용자 정의 구성 JsonSerializer 설정으로 문제가 해결되었습니다.

services.AddMvc(
  // ...
               ).AddJsonOptions(opt =>
                 {
                opt.SerializerSettings.ReferenceLoopHandling =
                    Newtonsoft.Json.ReferenceLoopHandling.Serialize;
                opt.SerializerSettings.PreserveReferencesHandling =
                    Newtonsoft.Json.PreserveReferencesHandling.Objects;
                 });

반복하지 않기 위해 이것은 나를 위해 일했습니다.
ReferenceLoopHandling = ReferenceLoopHandling.Ignore,

.Net Core 2 WebAPI로 Entity Framework 어린이 직렬화 https://gist.github.com/Kaidanov/f9ad0d79238494432f32b8407942c606

모든 의견을 부탁드립니다. 누군가가 언젠가 그것을 사용할 수있을 것입니다.


나는에서 그것을 수행하는 솔루션 좋아 Application_Start()대답에서와 같이 여기를

분명히 반환 된 객체가 객체의 (키, val) 전체에 "\ n \ r"을 가지고 있기 때문에 DalSoft의 답변에서와 같이 내 함수 내 구성을 사용하여 JavaScript의 json 객체에 액세스 할 수 없었습니다.

어쨌든 모든 작업은 훌륭합니다 (다른 의견은 질문과 질문에 따라 다른 시나리오에서 작동하기 때문에). 표준 작업 방식은 접근 방식을 지원하는 훌륭한 문서로 선호됩니다.

참고 URL : https://stackoverflow.com/questions/7397207/json-net-error-self-referencing-loop-detected-for-type


반응형