【问题标题】:ASP.NET Core API only returning first result of listASP.NET Core API 仅返回列表的第一个结果
【发布时间】:2016-08-18 17:37:52
【问题描述】:

我创建了一个团队 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 属性为空,因为 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 中只得到一个结果,但在断点处它有所有结果吗?

【问题讨论】:

  • 我尝试了您的代码,但使用了我可用的 Users 表,它适用于两种情况...var teams = await _context.Users.Include(u =&gt; u.Roles).ToListAsync(); 它只是序列化了 JSON 中的所有项目...:(跨度>
  • @GerardoGrignoli 真的吗?您使用的是 Entity Framework Core 还是 Entity Framework 6?
  • 我正在使用 EF Core。
  • 你试过services.AddMvc().AddJsonOptions(options =&gt; { options.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore; }); 吗?
  • 您可以尝试将循环标记为 [JsonIgnore] 吗? [JsonIgnore] public Team Team { get;放; }

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


【解决方案1】:

将此添加到 Startup.cs 中的 public void ConfigureServices(IServiceCollection services) 方法中:

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

该问题已在https://github.com/aspnet/Mvc/issues/4160https://github.com/aspnet/EntityFramework/issues/4646 进行了讨论,另请参阅circular reference

【讨论】:

  • 非常感谢。这让我发疯了。
  • 有史以来最令人沮丧的错误
【解决方案2】:

值得注意的是,如果您确实使用内联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 嵌套返回。我本来想要一个公寓Game&gt;Teams,但最终会得到Games&gt;Teams&gt;Players。这是一个简单的示例,但很容易看出如何从几 KB 的数据转到永无止境的循环,从而扼杀使用结果的客户端。

这意味着您需要自己控制这种流动。要获得预期的更平坦的 json 返回,您还需要在 .Include(x =&gt; x.Games) 上合并 .AsNoTracking()

作为一个非常简单的示例,您需要执行以下操作:

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-12-23
    • 1970-01-01
    • 2015-07-12
    相关资源
    最近更新 更多