サポートされていない.Net Core 3.0の可能なオブジェクトサイクルが検出されました


22

1対多に関連する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構成を追加することを推奨する関連する投稿があります

問題は、別のモデルを作成したくなく、2番目の提案が役に立たなかったことです。循環関係なしにデータをロードする方法はありますか?*

System.Text.Json.JsonException:サポートされていない可能性のあるオブジェクトサイクルが検出されました。これは、サイクルが原因であるか、オブジェクトの深度が最大許容深度である32よりも大きい場合に発生します。System.Text.Json.ThrowHelper.ThrowInvalidOperationException_SerializerCycleDetected(Int32 maxDepth)at System.Text.Json.JsonSerializer.Write(Utf8JsonWriter writer 、Int32 originalWriterDepth、Int32 flushThreshold、JsonSerializerOptionsオプション、WriteStack&状態)System.Text.Json.JsonSerializer.WriteAsyncCore(Stream utf8Json、Object value、Type inputType、JsonSerializerOptions options、CancellationToken cancelToken)at Microsoft.AspNetCore.Mvc.Formatters.SystemTextJ Microsoft.AspNetCore.MvcのWriteResponseBodyAsync(OutputFormatterWriteContext context、Encoding selectedEncoding)。

*


ReservationクラスのRestaurantプロパティを無視するように要求します。
Lasse V. Karlsen、

6
実際、APIから直接DBエンティティを返すことはできません。API固有のDTOを作成し、それに応じてマッピングすることをお勧めします。そうしたくないと言っていたとしても、APIと永続性の内部を分離しておくことは、一般的には良い習慣だと思います。
Mackie、

「そして2番目の提案は役に立たなかった」には詳細が必要です。
Henk Holterman、

「別のモデルを作りたくないのが問題」。あなたがそうしなければ、あなたのデザインは根本的に欠陥があります。APIはインターフェースのようなコントラクトです(文字通りアプリケーションプログラミングインターフェースです)。公開後は変更しないでください。変更を加えると、新しいバージョンが必要になります。このバージョンは古いバージョンと同時に実行する必要があります(非推奨になり、最終的には削除される予定です)。これにより、クライアントは実装を更新することができます。エンティティを直接返す場合は、データ層を密結合しています。
クリスプラット

そのデータレイヤーに変更を加えると、APIに即座に元に戻せない変更が必要になり、すべてのクライアントが実装を更新するまですぐに中断します。それが明らかでない場合、それは悪いことです。つまり、APIからエンティティを受け入れたり、返したりしないでください。常に DTO 使用する必要があります。
Chris Pratt

回答:


32

私は新しいプロジェクトであなたのコードを試しました、そして最初に3.0のためにパッケージMicrosoft.AspNetCore.Mvc.NewtonsoftJsonをインストールした後、2番目の方法はうまくいくようです

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/...は
ディエゴ・ヴェナンシオ

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.