我对我们向客户返回错误的方式感到担忧。
当我们收到错误消息时,是否通过抛出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); }
这只是一个示例代码,与验证错误或服务器错误无关,我只想了解最佳实践,每种方法的优缺点。
对我来说,我通常会发回一个,HttpResponseException并根据抛出的异常设置相应的状态代码,如果异常是致命的,将决定我是否HttpResponseException立即将其发回。
HttpResponseException
归根结底,这是一个API发送回响应而不是视图,因此我认为可以将带有异常和状态代码的消息发送回消费者。我目前不需要累积错误并将其发送回去,因为大多数异常通常是由于不正确的参数或调用等导致的。
我的应用程序中的一个示例是,有时客户端会要求数据,但是没有可用的数据,因此我抛出了一个自定义,NoDataAvailableException并让它冒泡到Web API应用程序,然后在我的自定义过滤器中捕获它,并发送回一个相关消息以及正确的状态代码。
NoDataAvailableException
我不确定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
更新我们的错误处理过程,我们有两种情况:
对于未找到的一般错误或传递给操作的无效参数,我们将返回a HttpResponseException以立即停止处理。此外,对于操作中的模型错误,我们会将模型状态字典移至Request.CreateErrorResponse扩展名并将其包装为HttpResponseException。添加模型状态字典会在响应正文中发送一个模型错误列表。
Request.CreateErrorResponse
对于更高层发生的错误(服务器错误),我们让异常冒泡到Web API应用程序,这里我们有一个全局异常过滤器,该过滤器查看异常,使用ELMAH记录该异常,并尝试合理地设置正确的HTTP状态代码和相关的友好错误信息再次出现在正文中HttpResponseException。对于某些例外情况,我们预计客户端不会收到默认的500内部服务器错误,但由于安全原因,会收到一条通用消息。
更新3
最近,在选择了Web API 2之后,为了发送回一般错误,我们现在使用IHttpActionResult接口,特别是在System.Web.Http.Results名称空间中内置的类(如NotFound,BadRequest),如果合适的话,例如,如果它们不适合我们,则对其进行扩展。带有响应消息的NotFound结果:
System.Web.Http.Results
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); } }