GET запрос в WEB-API?

Здравствуйте!
Есть модель User:
public class User
    {
        public User()
        {
            this.Accounts = new HashSet<Account>();
        }
        public int Id { get; set; }
        public string TelegramId { get; set; } = null!;
        public virtual ICollection<Account> Accounts { get; set; }
    }


Вторая модель Account:
public class Account
    {
        public int Id { get; set; }
        public string SteamId { get; set; } = null!;
        public User? User { get; set; }
        public int? UserId { get; set; }
    }


Связь между таблицами следующая : Один юзер может иметь множество аккаунтов, а у аккаута может быть только один юзер.

DbContext
public class MyContext : DbContext
    {
        public DbSet<User> Users { get; set; } = null!;
        public DbSet<Account> Accounts { get; set; } = null!;
        public MyContext(DbContextOptions<MyContext> options)
        : base(options)
        {
            Database.EnsureCreated();
        }

        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            modelBuilder.Entity<User>()
                .HasMany(s => s.Accounts)
                .WithOne(s => s.User);
        }
    }


Есть апи контроллер метод ПОСТ : Он работает, я отправил данные и они выглядят следующим образом

Таблица User:

id telegramId
1 user1
2 user2
3 user3

Таблица Account:

Id SteamId UserId
1 steamid1 1
2 steamid2 1
3 steamid3 2
4 steamid4 3
5 steamid5 3
6 steamid6 3

АПИ КОНТРОЛЛЕР ПОСТА ВЫГЛЯДИТ СЛЕД ОБРАЗОМ:

[HttpPost]
        public async Task<IActionResult> Register([FromBody] User user)
        {
            await _context.Users.AddAsync(user);
            await _context.SaveChangesAsync();
            return new OkObjectResult("test msg");
        }


И Теперь моя проблема:
Хочу сделать так, чтобы при запросе гет оутпут выглядел след образом

[
  {
    "id": 1,
    "telegramId": "user1",
    "accounts": [
      {
        "id": 1,
        "SteamId": "steamid1",
        "UserId": 1
      },
      {
        "id": 2,
        "SteamId": "steamid2",
        "UserId": 1
      }
    ]
  },
  {
    "id": 2,
    "telegramId": "user2",
    "accounts": [
      {
        "id": 3,
        "SteamId": "steamid3",
        "UserId": 2
      }
    ]
  },
  {
    "id": 3,
    "telegramId": "user3",
    "accounts": [
      {
        "id": 4,
        "SteamId": "steamid4",
        "UserId": 3
      },
      {
        "id": 5,
        "SteamId": "steamid5",
        "UserId": 3
      },
      {
        "id": 6,
        "SteamId": "steamid6",
        "UserId": 3
      }
    ]
  }
]


Делаю вот так в апи контроллере метода гет:

[HttpGet]
        public async Task<IEnumerable<User>> GetUsers()
        {

            return await _context.Users.Include(s => s.Accounts).ToListAsync();
        }


НО оутпут вот такой получается :
500 ошибка с ошибкой System.Text.Json.JsonException: A possible object cycle was detected. This can either be due to a cycle or if the object depth is larger than the maximum allowed depth of 32. Consider using ReferenceHandler.Preserve on JsonSerializerOptions to support cycles. Path: $.Accounts.User.Accounts.User.Accounts.User.Accounts.User.Accounts.User.Accounts.User.Accounts.User.Accounts.User.Accounts.User.Accounts.User.Id.

Делаю вот так:
[HttpGet]
        public async Task<IEnumerable<User>> GetUsers()
        {

            return await _context.Users.ToListAsync();
        }


НО оутпут вот такой получается :
[
  {
    "id": 1,
    "telegramId": "user1",
    "accounts": []
  },
  {
    "id": 2,
    "telegramId": "user2",
    "accounts": []
  },
  {
    "id": 3,
    "telegramId": "user3",
    "accounts": []
  }
]
без учета данных с таблицы Accounts получается.
Помогите пожалуйста, как сделать так, чтобы при гет запросе чтобы показывались все данные.

Еще хочу получить все аккаунты определенного юзера по его айди номеру.
[HttpGet]
        [Route("{id}")]
        public async Task<IEnumerable<User>> GetUserById(int id)
        {
            return await _context.Users.Include(s => s.Accounts).Where(s => s.Id == id && s.Accounts.UserId == id).ToListAsync();
        }

в оутпуте получаю 500 ошибку. Помогите, пожалуйста, как мне сделать правильно. Ломаю голову целый день, нервничаю сильно.
  • Вопрос задан
  • 203 просмотра
Решения вопроса 2
vabka
@vabka Куратор тега C#
Токсичный шарпист
System.Text.Json.JsonException: A possible object cycle was detected. This can either be due to a cycle or if the object depth is larger than the maximum allowed depth of 32. Consider using ReferenceHandler.Preserve on JsonSerializerOptions to support cycles. Path:

Дело в том, что у тебя в объекте есть циклические ссылки.
Чтобы от этой ошибки избавиться есть два варианта:
1. Руками смаппить модель из базы в модель для фронта (что очень рекомендую. Возвращать модели напрямую из DbContext не безопасно)
2. Настроить jsonserializer, чтобы он при обранужении циклических ссылок заменял их на null.
Сделать это можно так:
// Там где ты регистрируешь сервисы
services
    .AddMvcCore() // или .AddMvc()
    .AddJsonOptions(options =>
    {
        options.JsonSerializerOptions = new JsonSerializerOptions(JsonSerializerDefaults.Web)
        {
            ReferenceHandler = ReferenceHandler.IgnoreCycles // или ReferenceHandler.Preserve
        };
    });
Ответ написан
Комментировать
@Clutchmeister
.NET Backend Developer
Слепи модель с пользователями и их аккаунтами, заполни ее и сделай возвращаемым значением.
Ответ написан
Комментировать
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы