ASP.NET Core API仅返回列表的第一个结果

时间:2016-08-18 17:37:53

标签: c# json entity-framework asp.net-web-api asp.net-core

我创建了一个团队web 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属性为null,因为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结果没有反映出来。这是一张图片:

enter image description here

我已尝试同步和异步执行此操作,但获得相同的结果。你知道为什么我只在json中得到一个结果但在断点处它有所有结果吗?

2 个答案:

答案 0 :(得分:50)

试试这个:

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

讨论了问题https://github.com/aspnet/Mvc/issues/4160https://github.com/aspnet/EntityFramework/issues/4646也看到了circular reference

答案 1 :(得分:1)

值得注意的是,如果您使用内联JsonSerializerSettings选项控制json输出,

[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嵌套返回的heck。我本来想要一个单位Game>Teams,但最终会Games>Teams>Players。这是一个简单的例子,但很容易看出你如何从几KB的数据转到永无止境的循环,这会阻塞消费结果的客户端。

这意味着您需要控制自己的流量。为了获得更平坦的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
    });
}