ASP.NET Core API возвращает только первый результат списка
Я создал контроллер веб-API команд и пытаюсь вызвать метод GET, чтобы получить результат json для всех команд в базе данных. Но когда я делаю колл, я возвращаю только первую команду в json, но когда я устанавливаю точку останова в операторе return, в ней участвуют все 254 команды вместе со всеми играми.
Вот две модели, с которыми я имею дело:
public class Team
{
public string Id { get; set; }
public string Name { get; set; }
public string Icon { get; set; }
public string Mascot { get; set; }
public string Conference { get; set; }
public int NationalRank { get; set; }
public List<Game> Games { get; set; }
}
public class Game
{
public string Id { get; set; }
public string Opponent { get; set; }
public string OpponentLogo { get; set; }
public string GameDate { get; set; }
public string GameTime { get; set; }
public string TvNetwork { get; set; }
public string TeamId { get; set; }
public Team Team { get; set; }
}
Когда я делаю это:
[HttpGet]
public async Task<List<Team>> Get()
{
var teams = await _context.Teams.ToListAsync();
return teams;
}
Я получаю все 254 команды, но свойство Game равно нулю, потому что EF Core не поддерживает отложенную загрузку. Итак, что я действительно хочу сделать, это добавить.Include() следующим образом:
[HttpGet]
public async Task<List<Team>> Get()
{
var teams = await _context.Teams.Include(t => t.Games).ToListAsync();
return teams;
}
Это возвращает первую команду с первой игрой, но больше ничего. Вот JSON:
[
{
"id": "007b4f09-d4da-4040-be3a-8e45fc0a572b",
"name": "New Mexico",
"icon": "lobos.jpg",
"mascot": "New Mexico Lobos",
"conference": "MW - Mountain",
"nationalRank": null,
"games": [
{
"id": "1198e6b1-e8ab-48ab-a63f-e86421126361",
"opponent": "vs Air Force*",
"opponentLogo": "falcons.jpg",
"gameDate": "Sat, Oct 15",
"gameTime": "TBD ",
"tvNetwork": null,
"teamId": "007b4f09-d4da-4040-be3a-8e45fc0a572b"
}
]
}
]
Когда я устанавливаю точку останова в операторе return, это показывает, что в команде 254 команды, и каждая команда правильно заполняет их игры... но результат json не отражает. Вот изображение:
Я пытался делать это как синхронно, так и асинхронно, но получал один и тот же результат. Знаете ли вы, почему я получаю только один результат в json, но в точке останова он дает все результаты?
2 ответа
Попробуй это:
services.AddMvc().AddJsonOptions(options => {
options.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
});
Эта проблема обсуждалась https://github.com/aspnet/Mvc/issues/4160 и https://github.com/aspnet/EntityFramework/issues/4646 также см. Циркулярную ссылку
Стоит отметить, что если вы управляете выводом json, как с помощью inline JsonSerializerSettings
вариант,
[HttpGet]
public async Task<IActionResult> Get([FromForm]bool strip_nulls = true)
{
var teams = await _context.Teams.Include(t => t.Games).ToListAsync();
return Json(teams, new JsonSerializerSettings() {
NullValueHandling = strip_nulls ? NullValueHandling.Ignore : NullValueHandling.Include
});
}
Простое предложение предложенного решения от @ adeam-caglin, которое не является неправильным в подходе, не сработает. Вы также должны установить настройки в вашем возвращении. Например.
[HttpGet]
public async Task<IActionResult> Get([FromForm]bool strip_nulls = true)
{
var teams = await _context.Teams.Include(t => t.Games).ToListAsync();
return Json(teams, new JsonSerializerSettings() {
NullValueHandling = strip_nulls ? NullValueHandling.Ignore : NullValueHandling.Include,
ReferenceLoopHandling = ReferenceLoopHandling.Ignore
});
}
Это в основном обнуляется, а не добавляет к настройкам, которые вы установили на Startup.cs
, Это также дает вам дорожную карту, чтобы не глобально изменить ваши результаты, а сделать это в каждом конкретном случае.
РЕДАКТИРОВАТЬ
Я также хотел бы воспользоваться моментом и уточнить, что происходит, когда вы используете ReferenceLoopHandling.Ignore
Вы просите пить из пожарного шланга, но надеетесь, что это будет контролируемый поток. Если у вас высокоразвитое моделирование, у вас, скорее всего, будет набор, в котором, как вы думаете, вы собираетесь получить свою предполагаемую сущность и ее дочерний список, но если у этих элементов списка также есть дети или другие родители, вы их загрузите. Допустим, у вас есть
Teams>Players>Contacts
Games>Teams
Это даст чертовски вложенный возврат json. Я бы хотел квартиру Game>Teams
но в конечном итоге Games>Teams>Players
, Это простой пример, но легко увидеть, как можно перейти от пары килобайт данных к бесконечному циклу, который перекрывает клиента, потребляющего результаты.
Это означает, что вам нужно будет контролировать этот поток себя. Чтобы получить более ожидаемое возвращение JSON, вам также нужно будет включить .AsNoTracking()
на .Include(x => x.Games)
В качестве очень простого примера вам нужно сделать что-то вроде:
[HttpGet]
public async Task<IActionResult> Get([FromForm]bool strip_nulls = true)
{
var teams = _context.Teams.AsQueryable();
teams = teams.Include(t => t.Games).AsNoTracking();
Teams _return = await teams.ToListAsync();
return Json(_return, new JsonSerializerSettings() {
NullValueHandling = strip_nulls ? NullValueHandling.Ignore : NullValueHandling.Include,
ReferenceLoopHandling = ReferenceLoopHandling.Ignore
});
}