.Net Core 3.0 có thể phát hiện chu kỳ đối tượng không được hỗ trợ


22

Tôi có 2 thực thể có liên quan từ một đến nhiều

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

Nếu tôi cố gắng để có được nhà hàng với đặt phòng bằng api của tôi

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

Tôi nhận được lỗi trong phản hồi, bởi vì các đối tượng chứa các tham chiếu cho nhau. Có những bài viết liên quan đề xuất tạo mô hình riêng biệt hoặc thêm cấu hình NewtonsoftJson

Vấn đề là tôi không muốn tạo mô hình riêng biệt và đề xuất thứ 2 không giúp được gì. Có cách nào để tải dữ liệu mà không cần quan hệ theo chu kỳ không? *

System.Text.Json.JsonException: Một chu kỳ đối tượng có thể được phát hiện không được hỗ trợ. Điều này có thể là do một chu kỳ hoặc nếu độ sâu đối tượng lớn hơn độ sâu tối đa cho phép là 32. tại System.Text.Json.ThrowHelper.ThrowInvalidOperationException_SerializerCyclDetected (Int32 maxDepth) tại System.Text.Json.JsonSer , Int32 gốcWriterDepth, Int32 flushThrưỡng, JsonSerializerOptions tùy chọn, WriteStack & state) tại System.Text.Json.JsonSerializer.WriteAsyncCore (Stream utf8Json, Giá trị đối tượng, loại bỏ tùy chọn của mình WriteResponseBodyAsync (bối cảnh đầu raFormatterWriteContext, mã hóa được chọn Mã hóa) tại Microsoft.AspNetCore.Mvc.

*


Yêu cầu nó bỏ qua thuộc tính Nhà hàng của lớp Đặt chỗ.
Lasse V. Karlsen

6
Thực sự bạn không nên trả lại các thực thể DB trực tiếp từ API của mình. Tôi khuyên bạn nên tạo các DTO dành riêng cho API và ánh xạ phù hợp. Cấp cho bạn nói rằng bạn không muốn làm điều đó nhưng tôi coi đó là cách thực hành tốt chung để tách biệt các API và nội bộ kiên trì.
mackie

"và đề nghị thứ 2 không giúp" cần chi tiết.
Henk Holterman

"Vấn đề là tôi không muốn tạo mô hình riêng biệt". Thiết kế của bạn về cơ bản là thiếu sót trừ khi bạn làm điều đó. API là một hợp đồng giống như một giao diện (nghĩa đen là giao diện lập trình ứng dụng ). Nó không bao giờ thay đổi, một khi được xuất bản và bất kỳ thay đổi nào cũng cần một phiên bản mới, sẽ cần phải chạy đồng thời với phiên bản cũ (sẽ bị loại bỏ và cuối cùng sẽ bị xóa trong tương lai). Điều đó cho phép khách hàng có thời gian để cập nhật việc thực hiện của họ. Nếu bạn trả lại một thực thể trực tiếp, bạn sẽ liên kết chặt chẽ lớp dữ liệu của mình.
Chris Pratt

Bất kỳ thay đổi nào đối với lớp dữ liệu đó sau đó đều cần một thay đổi ngay lập tức và không thể đảo ngược đối với API, phá vỡ tất cả các máy khách ngay lập tức cho đến khi chúng cập nhật các triển khai của chúng. Trong trường hợp không rõ ràng, đó là một điều xấu. Tóm lại: không bao giờ chấp nhận hoặc trả lại các thực thể từ API. Bạn nên luôn luôn sử dụng DTO.
Chris Pratt

Câu trả lời:


32

Tôi đã thử mã của bạn trong một dự án mới và cách thứ hai có vẻ hoạt động tốt sau khi cài đặt gói Microsoft.AspNetCore.Mvc.NewtonsoftJson trước tiên cho 3.0

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

Hãy thử với một dự án mới và so sánh sự khác biệt.


1
Thời điểm quan trọng ở đây là cài đặt lại phiên bản Microsoft.AspNetCore.Mvc.NewtonsoftJson Tôi không chú ý đến phiên bản vì gói này có sẵn trong hộp mà không có bất kỳ lỗi và cảnh báo nào! Cảm ơn về câu trả lời ! Tất cả mọi thứ hoạt động chính xác như tôi mong đợi!
Nazar Pylyp

1
Không phải là sai khi cải thiện hệ thống json, chúng ta phải sử dụng NewtonsoftJson sao? : /
Marek Urbanowicz

40

.NET Core 3.1 Cài đặt gói Microsoft.AspNetCore.Mvc.NewtonsoftJson

Startup.cs Thêm dịch vụ

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

1
Bạn có thể định dạng câu trả lời của bạn và thêm một số chi tiết? Nó không thể đọc được.
Sid

Để biết thêm chi tiết, hãy kiểm tra: thecodebuzz.com/ từ
Diego Venâncio

4

Bắt các thiết lập tùy chọn tuần tự hóa JSON khi khởi động hoạt động có lẽ là một cách ưa thích vì bạn có thể sẽ gặp trường hợp tương tự trong tương lai. Tuy nhiên, trong thời gian chờ đợi, bạn có thể thử thêm các thuộc tính dữ liệu vào mô hình của mình để nó không được tuần tự hóa: https://www.newtonsoft.com/json/help/html/PropertyJsonIgnore.htmlm

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

Điều này làm việc quá. Nhưng như bạn đã đề cập, với điều này, bạn phải cập nhật tất cả các mô hình, tôi thích dịch vụ.AddControllers (). AddNewtonsoftJson (tùy chọn => tùy chọn.SerializerSinstall.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;} 

Ở trên cũng làm việc. Nhưng tôi thích những điều sau đây

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

Bởi vì trước tiên chúng ta cần thêm thuộc tính cho tất cả các mô hình mà chúng ta có thể có tham chiếu theo chu kỳ.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.