지원되지 않는 .Net Core 3.0 가능한 개체주기가 감지되었습니다.


22

일대 다로 관련된 2 개의 엔티티가 있습니다.

public class Restaurant {
   public int RestaurantId {get;set;}
   public string Name {get;set;}
   public List<Reservation> Reservations {get;set;}
   ...
}
public class Reservation{
   public int ReservationId {get;set;}
   public int RestaurantId {get;set;}
   public Restaurant Restaurant {get;set;}
}

내 API를 사용하여 예약 된 레스토랑을 얻으려고하면

   var restaurants =  await _dbContext.Restaurants
                .AsNoTracking()
                .AsQueryable()
                .Include(m => m.Reservations).ToListAsync();
    .....

객체에 서로 참조가 포함되어 있기 때문에 응답으로 오류가 발생합니다. 별도의 모델을 작성 하거나 NewtonsoftJson 구성을 추가 하도록 권장 하는 관련 게시물이 있습니다.

문제는 별도의 모델을 만들고 싶지 않으며 두 번째 제안이 도움이되지 않는다는 것입니다. 주기적인 관계없이 데이터를로드하는 방법이 있습니까? *

System.Text.Json.JsonException : 지원되지 않는 가능한 오브젝트주기가 발견되었습니다. 주기 때문이거나 오브젝트 깊이가 최대 허용 깊이 인 32보다 큽니다. System.Text.Json.ThrowHelper.ThrowInvalidOperationException_SerializerCycleDetected (Int32 maxDepth)에서 System.Text.Json.JsonSerializer.Write (Utf8JsonWriter writer) System.Text.Json.JsonSerializer.WriteAsyncCore (Stream utf8Json, Object value, Type inputType, JsonSerializerOptions 옵션, CancellationToken CancellationToken)에서 System.Text.JsonSerializerOptions 옵션, WriteStack 및 state)의 Int32 originalWriterDepth, Int32 flushThreshold, JsonSerializerOptions 옵션, WriteStack 및 상태). Microsoft.AspNetCore.Mvc에서 WriteResponseBodyAsync (OutputFormatterWriteContext 컨텍스트, Encoding selectedEncoding).

*


Reservation 클래스의 Restaurant 속성을 무시하도록 요청하십시오.
Lasse V. Karlsen

6
실제로 API에서 직접 DB 엔터티를 반환해서는 안됩니다. API 별 DTO를 만들고 그에 따라 매핑하는 것이 좋습니다. 당신이 그렇게하고 싶지 않다고 말했지만 API와 지속성 내부를 분리하는 것이 일반적인 모범 사례라고 생각합니다.
mackie

"그리고 두 번째 제안은 도움이되지 않았다"는 세부 사항이 필요하다.
Henk Holterman

"문제는 별도의 모델을 만들고 싶지 않다는 것입니다." 그렇게하지 않으면 디자인에 근본적인 결함이 있습니다. API는 인터페이스와 같은 계약입니다 (문자 그대로 애플리케이션 프로그래밍 인터페이스 임). 게시 된 후에는 변경해서는 안되며, 모든 변경에는 새 버전이 필요하며 이전 버전과 동시에 실행해야합니다 (이는 더 이상 사용되지 않으며 향후 제거 될 예정 임). 이를 통해 클라이언트는 구현을 업데이트 할 수 있습니다. 엔터티를 직접 반환하면 데이터 계층이 밀접하게 연결됩니다.
Chris Pratt

그런 다음 해당 데이터 계층을 변경하면 API를 즉시 되돌릴 수없는 변경이 필요하므로 구현을 업데이트 할 때까지 모든 클라이언트가 즉시 중단됩니다. 분명하지 않은 경우, 그것은 나쁜 것입니다. 한마디로 : API에서 엔터티를 수락하거나 반환하지 마십시오. 당신은해야한다 항상 DTO들을 사용합니다.
Chris Pratt

답변:


32

새 프로젝트에서 코드를 시험해 보았고 두 번째 방법은 Microsoft.AspNetCore.Mvc.NewtonsoftJson 3.0을 처음 설치 한 후 잘 작동하는 것 같습니다

services.AddControllerWithViews()
    .AddNewtonsoftJson(options =>
    options.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore
);

새 프로젝트를 시도하고 차이점을 비교하십시오.


1
여기서 중요한 순간은 올바른 버전의 Microsoft.AspNetCore.Mvc.NewtonsoftJson을 다시 설치하는 것입니다.이 패키지는 오류 및 경고없이 상자에서 사용할 수 있으므로 버전에주의를 기울이지 않았습니다! 대답 해줘서 고마워요 ! 모든 것이 예상대로 작동합니다!
Nazar Pylyp

1
시스템 json의 성능이 향상되면 NewtonsoftJson을 사용해야한다는 것이 잘못이 아닙니까? : /
Marek Urbanowicz

40

.NET Core 3.1 Microsoft.AspNetCore.Mvc.NewtonsoftJson 패키지 설치

Startup.cs 서비스 추가

services.AddControllers().AddNewtonsoftJson(options =>
    options.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore
);

1
응답을 형식화하고 세부 사항을 추가 할 수 있습니까? 읽을 수 없습니다.
시드

자세한 내용은 다음을 확인하십시오 : thecodebuzz.com/…
Diego Venâncio

4

시작시 JSON 직렬화 옵션을 설정하면 나중에 비슷한 경우가 발생할 수 있으므로 선호되는 방법 일 수 있습니다. 그러나 그 동안 모델에 데이터 속성을 추가하여 직렬화되지 않도록 할 수 있습니다. https://www.newtonsoft.com/json/help/html/PropertyJsonIgnore.htm

public class Reservation{ 
    public int ReservationId {get;set;} 
    public int RestaurantId {get;set;} 
    [JsonIgnore]
    public Restaurant Restaurant {get;set;} 
}

이것도 작동합니다. 그러나 언급했듯이 모든 모델을 업데이트해야하므로 services.AddControllers (). AddNewtonsoftJson (options => options.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore)을 선호합니다.
Nantharupan

1
public class Reservation{ 
public int ReservationId {get;set;} 
public int RestaurantId {get;set;} 
[JsonIgnore]
public Restaurant Restaurant {get;set;} 

위도 작동했습니다. 그러나 나는 다음을 선호한다

services.AddControllers().AddNewtonsoftJson(options =>
    options.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore
);

먼저 모든 모델에 속성을 추가해야하므로 순환 참조가있을 수 있습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.