WebApi2 GET 总是说发生了错误

WebApi2 GET always says error has occurred

我的 Web API 2 项目中有一个简单的 GET 方法,它通过 Entity Framework 查询我的 Microsof tSQL 数据库,但总是 returns 出错。如果我在调试器中逐步执行它,则不会命中异常。它实际上看起来很干净地离开了方法。我很困惑。

    [Route("ar")]
    public IHttpActionResult GetAuditArs(int auditId)
    {
        using (var context = new LabSOREntities()) {
            try {
                var ars = from r in context.SMBWA_Audit_AR
                          where r.SMBWA_Audit_Id == auditId
                          select r;

                var ret = Ok(ars.ToArray());

                return ret;
            } catch (Exception ex) {
                return BadRequest($"Something went wrong: {ex.Message}");
            }
        }
    }

数据库中有一行,我看到我的 ars.ToArray() 说其中只有一个元素。我该如何调试它,因为它在爆炸时离开了我的方法?

如果我只是通过浏览器访问该端点,我会得到:

<Error>
<Message>An error has occurred.</Message>
</Error>

问题在于您正在从 API 调用中 returning 实体。在幕后,WebAPI 必须序列化正在 returned 的数据,因为它这样做会命中任何延迟加载引用属性并尝试加载它们。由于您在 using 块中实例化范围内的数据库上下文,实体将在序列化之前从上下文中孤立出来,因此 EF 将抛出数据库上下文不可用的异常。

验证行为的选项 - 急切加载 "SMBWA_Audit_AR" class 中的所有参考资料。这应该可以消除错误并确认延迟加载序列化问题。

var ars = context.SMBWA_Audit_AR
    .Include(x => x.Reference1)
    .Include(x => x.Reference2) // etc. where Reference1/2 are related entites to your audit record. If you have a lot of references, that is a lot of includes...
    .Where(x => x.SMBWA_Audit_Id = auditId)
    .ToArray();

为了避免这样的问题,并且 cost/time 预先加载我推荐的所有内容,我建议使用 POCO DTO/ViewModel 来 return 有关这些审计记录的详细信息。然后你可以 .Select() POCO需要的字段。这避免了延迟加载序列化问题,并且将您从 EF 的查询优化为 return 仅需要的数据,而不是整个对象图。

例如: 如果您需要审计编号、名称和备注字段显示在审计摘要列表中:

public class AuditSummary
{
  public int AuditID {get; set;}
  public string AuditorName {get; set;}
  public string Notes {get; set;}
  // You can add whatever fields are needed from the Audit or related entities... Including collections of other DTOs for related entites, or summary details like Counts etc..
}

var ars = context.SMBWA_Audit_AR
    .Where(x => x.SMBWA_Audit_Id = auditId)
    .Select(x => new AuditSummary 
       {
         AuditId = x.AuditId,
         AuditorName = x.AuditedBy.Name, //Example getting reference details..
         Notes = x.Notes
       }).ToArray();

Return 反映消费者需求的模型。这可以避免 EF 出现问题并确保您的查询高效。

  • 使用 IoC 容器(Unity/Autofac 等)将 DbContext 限定在请求范围内。这似乎是一个可行的选择,但不推荐这样做。虽然它会避免错误,但当序列化程序遍历您的实体时,您的 DbContext 将通过 ID 一次查询每个单独的依赖项。当应用程序 运行 检测延迟加载调用时,您可以通过 运行 针对数据库的分析器看到此行为。它最终会起作用,但是会很慢。

作为一般规则,不要 return 来自 Web API 或 MVC 控制器方法的实体,以避免序列化程序出现错误和性能问题。