c# - API do ASP.NET Core apenas retornando primeiro resultado da lista




json entity-framework (2)

Tente isto:

services.AddMvc().AddJsonOptions(options => {
            options.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
        });

O problema foi discutido https://github.com/aspnet/Mvc/issues/4160 e https://github.com/aspnet/EntityFramework/issues/4646 também ver referência circular

Eu criei um controlador de API da web de equipes e tentando chamar o método GET para obter o resultado json de todas as equipes no banco de dados. Mas quando eu faço a ligação, estou apenas recebendo o primeiro time de volta no json, mas quando eu defino um ponto de interrupção na declaração de retorno, ele tem todas as 254 equipes junto com todos os jogos.

Estes são os dois modelos com os quais estou lidando:

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

Quando faço isso:

[HttpGet]
public async Task<List<Team>> Get()
{
    var teams = await _context.Teams.ToListAsync();

    return teams;
}

Eu recebo todas as 254 equipes, mas a propriedade Game é nula porque o EF Core não suporta carregamento lento. Então, o que eu realmente quero fazer é adicionar o .Include () assim:

[HttpGet]
public async Task<List<Team>> Get()
{
    var teams = await _context.Teams.Include(t => t.Games).ToListAsync();

    return teams;
}

Isso retorna a primeira equipe com o primeiro jogo, mas nada mais. Aqui está o 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"
      }
    ]
  }
]

Quando defino um ponto de quebra na declaração de retorno, mostra que existem 254 equipes e cada equipe tem seus jogos preenchidos corretamente ... mas o resultado do json não reflete. Aqui está uma imagem:

Eu tentei fazer isso de forma síncrona e assíncrona, mas obtendo o mesmo resultado. Você sabe por que estou obtendo apenas um resultado no json, mas no breakpoint ele tem todos os resultados?


Vale a pena notar que, se você controlar a saída do json como JsonSerializerSettings opção JsonSerializerSettings linha,

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

Basta colocar a solução sugerida de @ adeam-caglin, o que não está errado na abordagem, não funcionará. Você também deve definir a configuração no seu retorno. Por exemplo.

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

Basicamente anula, não adiciona as configurações definidas no Startup.cs . Isso também fornece um roteiro para não alterar globalmente sua saída, mas sim caso a caso.

EDITAR

Eu também gostaria de ter um momento e esclarecer o que acontece quando você usa ReferenceLoopHandling.Ignore , você está pedindo para beber da mangueira de incêndio, mas esperando que seja um fluxo controlado. Se você tem uma modelagem altamente desenvolvida, provavelmente terá mais um conjunto onde você acha que vai obter a entidade desejada e sua lista de filhos, mas se esses itens da lista também tiverem filhos, ou outros pais, você os carregará. Vamos dizer que você tem

Teams>Players>Contacts
Games>Teams

Isso produziria um retorno aninhado json. Eu estaria querendo um Game>Teams mas acabaria com Games>Teams>Players . Este é um exemplo simples, mas é fácil ver como você poderia passar de um par de dados para um loop sem fim que sufoca o cliente consumindo os resultados.

Isso significa que você precisará controlar o fluxo de si mesmo. Para obter o retorno json mais plano esperado, você também precisará incorporar .AsNoTracking() no .Include(x => x.Games)

Como um exemplo muito simples, você precisaria fazer algo como:

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






asp.net-core