Виявлено можливий цикл об'єктів .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

Проблема в тому, що я не хочу створювати окрему модель, і 2-я пропозиція не допомогла. Чи є спосіб завантаження даних без циклічного зв'язку? *

System.Text.Json.JsonException: виявлено можливий цикл об'єктів, який не підтримується. Це може бути пов’язано з циклом або якщо глибина об'єкта перевищує максимально дозволену глибину 32. у System.Text.Json.ThrowHelper.ThrowInvalidOperationException_SerializerCycleDetected (Int32 maxDepth) на System.Text.Json.JsonSerializer.Write (Utf8Jerson , Int32 originalWriterDepth, Int32 flushThreshold, JsonSerializerOptions options, WriteStack & state) на System.Text.Json.JsonSerializer.WriteAsyncCore (Потік utf8Json, Значення об'єкта, Type inputType, JsonSerializerOptions options, CancellationToken canceltenTextTextsetTextsetTextsetTextsett.TextMeatTextMeatTextMeatTextMeatTextMeatSextMee WriteResponseBodyAsync (контекст OutputFormatterWriteContext, кодування вибраногоEncoding) в Microsoft.AspNetCore.Mvc.

*


Попросіть його ігнорувати властивість ресторану класу "Бронювання".
Лассе В. Карлсен

6
Дійсно, ви не повинні повертати суб'єкти DB безпосередньо з вашого API. Я б запропонував створити специфічні для API API і відобразити їх відповідно. Звичайно, ви сказали, що не хочете цього робити, але я вважаю загальноприйнятною практикою відокремлення інтерфейсів API та стійкості.
Mackie

"та 2-я пропозиція не допомогла" потребує деталей.
Хенк Холтерман

"Проблема в тому, що я не хочу створювати окрему модель". Ваш дизайн принципово хибний, якщо ви не робите саме це. API - це контракт на зразок інтерфейсу (це буквально інтерфейс програмування додатків ). Після публікації вона ніколи не повинна змінюватися, і будь-яка зміна потребує нової версії, яка повинна працювати паралельно зі старою версією (яка буде застарілою і згодом видалена в майбутньому). Це дозволяє клієнтам час оновлювати свої реалізації. Якщо ви повертаєте сутність безпосередньо, ви щільно з'єднуєте ваш рівень даних.
Кріс Пратт

Будь-яка зміна цього рівня даних вимагає негайної та незворотної зміни в API, негайно порушуючи всіх клієнтів, поки вони не оновлять свої реалізації. Якщо це не очевидно, це погано. Коротше кажучи: ніколи не приймайте та не повертайте об’єкти з API. Ви завжди повинні використовувати DTO.
Кріс Пратт

Відповіді:


32

Я спробував ваш код у новому проекті, і другий спосіб, здається, працює добре після встановлення пакета Microsoft.AspNetCore.Mvc.NewtonsoftJson спочатку для 3.0

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

Спробуйте з новим проектом і порівняйте відмінності.


1
Ключовим моментом тут є перевстановлення належної версії Microsoft.AspNetCore.Mvc.NewtonsoftJson Я не звернув уваги на версію, оскільки цей пакет був доступний під коробкою без помилок та попереджень! Дякуємо за відповідь! Все працює саме так, як я і очікував!
Назар Пилип

1
Чи не помиляється, що з покращеною perf системи json нам доводиться використовувати NewtonsoftJson? : /
Марек Урбанович

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

Це теж працює. Але як ви вже згадували, з цим вам доведеться оновити всі моделі, я віддаю перевагу сервісам.AddControllers (). AddNewtonsoftJson (options => options.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore);
Нантарупан

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

Тому що спочатку нам потрібно додати атрибут до всіх моделей, які можуть мати циклічне посилання.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.