ASP.NET Web API中处理错误的最佳实践

30

你能否澄清Web API错误管理的最佳实践是什么?实际上,我不知道在我的Api请求中使用try catch是否是一个好习惯。

public Vb.Order PostOrderItem(Vb.Order order)
{
    if (OAuth.isValid(Request.Headers.GetValues("Token").Single()) != true)
    {
        HttpResponseMessage httpResponseMessage = new HttpResponseMessage(HttpStatusCode.Unauthorized);
        throw new HttpResponseException(httpResponseMessage);
    }
    if (!ModelState.IsValid)
    {
        HttpResponseMessage httpResponseMessage = new HttpResponseMessage(HttpStatusCode.BadRequest);
        throw new HttpResponseException(httpResponseMessage);
    }

    try
    {
        return Vb.Document.Generate(order);
    }
    catch (Exception ex)
    {
        logger.Error(ex);
        HttpResponseMessage httpResponseMessage = new HttpResponseMessage(HttpStatusCode.BadRequest);
        httpResponseMessage.Content = new StringContent(ex.Message);
        throw new HttpResponseException(httpResponseMessage);
    }

}

我有这样一种感觉,使用try catch来处理服务器端代码并不是一个好的实践,因为我只是记录了异常并重新抛出它。

3个回答

44

Web API中的错误处理被视为横跨多个方面的关注点,应该放置在管道的其他位置,这样开发人员就不需要专注于横跨多个方面的关注点。

您应该阅读ASP.NET Web API中的异常处理

如果Web API控制器引发未捕获的异常会发生什么?默认情况下,大多数异常将转换为带有状态代码500的HTTP响应,即“内部服务器错误”。

另外还有ASP.NET Web API 2中的全局错误处理

尽可能使您的控制器保持简洁。像您原来的代码一样进行错误处理只会导致代码重复和开发人员需知道的不必要问题。开发人员应专注于核心关注点,而不是横跨多个方面的关注点。通过只关注核心问题,上述代码将如下所示:

[MyAuthentication]
[MyValidateModel]
public Vb.Order PostOrderItem(Vb.Order order)
{    
    return Vb.Document.Generate(order);
}

为什么这么瘦?

因为:

if (OAuth.isValid(Request.Headers.GetValues("Token").Single()) != true)
{
    HttpResponseMessage httpResponseMessage = new HttpResponseMessage(HttpStatusCode.Unauthorized);
    throw new HttpResponseException(httpResponseMessage);
}

可以移动到ASP.NET Web API 2身份验证过滤器中,可以在控制器/操作本地应用或全局返回相关响应。

ASP.NET Web API中的模型验证就像这样。

if (!ModelState.IsValid)
{
    HttpResponseMessage httpResponseMessage = new HttpResponseMessage(HttpStatusCode.BadRequest);
    throw new HttpResponseException(httpResponseMessage);
}

也可以移到过滤器中,例如: .

public class MyValidateModelAttribute : ActionFilterAttribute
{
    public override void OnActionExecuting(HttpActionContext actionContext)
    {
        if (!actionContext.ModelState.IsValid)
        {
            actionContext.Response = actionContext.Request.CreateErrorResponse(
                HttpStatusCode.BadRequest, actionContext.ModelState);
        }
    }
}

谢谢您的回答。只有一个奖励问题:elmah怎么办?这个工具已经很久没有更新了。根据您的说法,我们不再需要它了,是吗? - Bastien Vandamme
你仍然可以使用它,而且它仍然是一个有用的工具。它可以补充答案中提供的链接中提到的策略,因为你可以将错误传递/记录到位于外围的ELMAH中。ELMAH的可插拔性证明了它如何专注于解决横切关注点。 - Nkosi
那么问题中的 logger.Error(ex); 代码如何呢?假设 Vb.Document.Generate(order) 是一个数据库调用,如果出现异常,我想记录下来。并将错误消息返回到 JSON 响应中。 - ca9163d9
@dc7a9163d9 这个应该在错误处理程序中完成。您需要消耗错误并返回一个用户友好的JSON响应。请查看提供的关于异常处理的链接。 - Nkosi
虽然这是一个好建议,但在我看来它太过模糊。是的,这是一个横切关注点。是的,它应该放在控制器操作之外。但是这个建议适用于任何API框架。这个问题特别涉及ASP.NET Web API。答案可能在链接中,但仅有链接的答案是不好的。在我看来,关于保持控制器精简的其余部分完全可以被删除。 - Josh Noe

26
请参考这个链接ASP.NET Web API 中的异常处理 - 一次指导之旅,其中有4个级别的异常处理流程:
  • 第一级 - HttpResponseException
  • 第二级 - 异常过滤器
  • 第三级 - 日志记录
  • 第四级 - 异常处理程序

Web API 在异常处理方面提供了极大的灵活性。 总结一下:

  • 在操作级别上使用HttpResponseException或快捷方法处理未处理的异常。
  • 使用异常过滤器来处理多个操作和控制器上的特定未处理异常。
  • 使用 ExceptionLogger 记录任何未处理的异常。
  • 使用异常处理程序(每个应用程序一个)来处理任何应用程序范围内的未处理异常。

0

2
这是关于MVC的,不是Web API。 - Bastien Vandamme

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接