我对我们向客户返回错误的方式有顾虑。

当我们得到一个错误时,我们是否通过抛出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);
}

这只是一个示例代码,无论是验证错误还是服务器错误都不重要,我只是想知道最佳实践,每种方法的优点和缺点。


当前回答

使用内置的"InternalServerError"方法(在ApiController中可用):

return InternalServerError();
//or...
return InternalServerError(new YourException("your message"));

其他回答

对于Web API 2,我的方法始终返回IHttpActionResult,所以我使用…

public IHttpActionResult Save(MyEntity entity)
{
    ....
    if (...errors....)
        return ResponseMessage(
            Request.CreateResponse(
                HttpStatusCode.BadRequest, 
                validationErrors));

    // otherwise success
    return Ok(returnData);
}

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

在一天结束的时候,它是一个返回响应而不是视图的API,所以我认为向使用者发送带有异常和状态代码的消息是很好的。我目前还不需要积累错误并将它们发送回来,因为大多数异常通常是由于不正确的参数或调用等。

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

我不是100%确定这方面的最佳实践是什么,但这对我来说目前是有效的,所以这就是我正在做的。

更新:

自从我回答了这个问题,就有一些关于这个话题的博客文章:

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

(这个版本在夜间版本中有一些新特性) https://learn.microsoft.com/archive/blogs/youssefm/error-handling-in-asp-net-webapi

更新2

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

For general errors like not found, or invalid parameters being passed to an action we return a HttpResponseException to stop processing immediately. Additionally for model errors in our actions we will hand the model state dictionary to the Request.CreateErrorResponse extension and wrap it in a HttpResponseException. Adding the model state dictionary results in a list of the model errors sent in the response body. For errors that occur in higher layers, server errors, we let the exception bubble to the Web API app, here we have a global exception filter which looks at the exception, logs it with ELMAH and tries to make sense of it setting the correct HTTP status code and a relevant friendly error message as the body again in a HttpResponseException. For exceptions that we aren't expecting the client will receive the default 500 internal server error, but a generic message due to security reasons.

更新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);
    }
}

如果您正在使用ASP。NET Web API 2,最简单的方法是使用ApiController Short-Method。这将导致一个BadRequestResult。

return BadRequest("message");

ASP。NET Web API 2确实简化了它。例如,以下代码:

public HttpResponseMessage GetProduct(int id)
{
    Product item = repository.Get(id);
    if (item == null)
    {
        var message = string.Format("Product with id = {0} not found", id);
        HttpError err = new HttpError(message);
        return Request.CreateResponse(HttpStatusCode.NotFound, err);
    }
    else
    {
        return Request.CreateResponse(HttpStatusCode.OK, item);
    }
}

当没有找到该项时,返回以下内容到浏览器:

HTTP/1.1 404 Not Found
Content-Type: application/json; charset=utf-8
Date: Thu, 09 Aug 2012 23:27:18 GMT
Content-Length: 51

{
  "Message": "Product with id = 12 not found"
}

建议:除非有灾难性错误(例如WCF Fault Exception),否则不要抛出HTTP Error 500。选择一个表示数据状态的适当HTTP状态代码。(请参阅下面的apigee链接。)

链接:

ASP中的异常处理。NET Web API (asp.net) 而且 RESTful API设计:错误怎么办?(apigee.com)

只是更新一下ASP的当前状态。净之前。接口现在被称为IActionResult,实现没有太大变化:

[JsonObject(IsReference = true)]
public class DuplicateEntityException : IActionResult
{        
    public DuplicateEntityException(object duplicateEntity, object entityId)
    {
        this.EntityType = duplicateEntity.GetType().Name;
        this.EntityId = entityId;
    }

    /// <summary>
    ///     Id of the duplicate (new) entity
    /// </summary>
    public object EntityId { get; set; }

    /// <summary>
    ///     Type of the duplicate (new) entity
    /// </summary>
    public string EntityType { get; set; }

    public Task ExecuteResultAsync(ActionContext context)
    {
        var message = new StringContent($"{this.EntityType ?? "Entity"} with id {this.EntityId ?? "(no id)"} already exist in the database");

        var response = new HttpResponseMessage(HttpStatusCode.Ambiguous) { Content = message };

        return Task.FromResult(response);
    }

    #endregion
}