一尘不染

在ASP.NET Web API中返回错误的最佳实践

c#

我对我们向客户返回错误的方式感到担忧。

当我们收到错误消息时,是否通过抛出HttpResponseException立即返回错误消息:

public void Post(Customer customer)
{
    if (string.IsNullOrEmpty(customer.Name))
    {
        throw new HttpResponseException("Customer Name cannot be empty", HttpStatusCode.BadRequest) 
    }
    if (customer.Accounts.Count == 0)
    {
         throw new HttpResponseException("Customer does not have any account", HttpStatusCode.BadRequest) 
    }
}

否则我们会累积所有错误,然后发回给客户:

public void Post(Customer customer)
{
    List<string> errors = new List<string>();
    if (string.IsNullOrEmpty(customer.Name))
    {
        errors.Add("Customer Name cannot be empty"); 
    }
    if (customer.Accounts.Count == 0)
    {
         errors.Add("Customer does not have any account"); 
    }
    var responseMessage = new HttpResponseMessage<List<string>>(errors, HttpStatusCode.BadRequest);
    throw new HttpResponseException(responseMessage);
}

这只是一个示例代码,与验证错误或服务器错误无关,我只想了解最佳实践,每种方法的优缺点。


阅读 270

收藏
2020-05-19

共1个答案

一尘不染

对我来说,我通常会发回一个,HttpResponseException并根据抛出的异常设置相应的状态代码,如果异常是致命的,将决定我是否HttpResponseException立即将其发回。

归根结底,这是一个API发送回响应而不是视图,因此我认为可以将带有异常和状态代码的消息发送回消费者。我目前不需要累积错误并将其发送回去,因为大多数异常通常是由于不正确的参数或调用等导致的。

我的应用程序中的一个示例是,有时客户端会要求数据,但是没有可用的数据,因此我抛出了一个自定义,NoDataAvailableException并让它冒泡到Web
API应用程序,然后在我的自定义过滤器中捕获它,并发送回一个相关消息以及正确的状态代码。

我不确定100%的最佳做法是什么,但这目前对我有用,所以这就是我正在做的事情。

更新

自从我回答了这个问题以来,就此主题写了一些博客文章:

https://weblogs.asp.net/fredriknormen/asp-net-web-api-exception-
handling

(这在每晚的版本中都有一些新功能) https://docs.microsoft.com/archive/blogs/youssefm/error-
handling-in-asp-net-
webapi

更新2

更新我们的错误处理过程,我们有两种情况:

  1. 对于未找到的一般错误或传递给操作的无效参数,我们将返回a HttpResponseException以立即停止处理。此外,对于操作中的模型错误,我们会将模型状态字典移至Request.CreateErrorResponse扩展名并将其包装为HttpResponseException。添加模型状态字典会在响应正文中发送一个模型错误列表。

  2. 对于更高层发生的错误(服务器错误),我们让异常冒泡到Web API应用程序,这里我们有一个全局异常过滤器,该过滤器查看异常,使用ELMAH记录该异常,并尝试合理地设置正确的HTTP状态代码和相关的友好错误信息再次出现在正文中HttpResponseException。对于某些例外情况,我们预计客户端不会收到默认的500内部服务器错误,但由于安全原因,会收到一条通用消息。

更新3

最近,在选择了Web API
2之后,为了发送回一般错误,我们现在使用IHttpActionResult接口,特别是在System.Web.Http.Results名称空间中内置的类(如NotFound,BadRequest),如果合适的话,例如,如果它们不适合我们,则对其进行扩展。带有响应消息的NotFound结果:

public class NotFoundWithMessageResult : IHttpActionResult
{
    private string message;

    public NotFoundWithMessageResult(string message)
    {
        this.message = message;
    }

    public Task<HttpResponseMessage> ExecuteAsync(CancellationToken cancellationToken)
    {
        var response = new HttpResponseMessage(HttpStatusCode.NotFound);
        response.Content = new StringContent(message);
        return Task.FromResult(response);
    }
}
2020-05-19