我担心我们返回错误给客户的方式。
我们是否在收到错误时通过抛出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);
}
这只是一个示例代码,验证错误或服务器错误都无关紧要,我只是想知道最佳实践,每种方法的优缺点。
对我来说,我通常会发送回
在一天结束时,它是一个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
null
null
对于发生在较高层的错误,即服务器错误,我们让异常冒泡到Web API应用程序,这里我们有一个全局异常过滤器,它查看异常,用ELMAH记录它,并尝试理解它,在
更新3
null
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 API2确实简化了它。例如,以下代码:
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错误例外),否则不要抛出HTTP错误500。选择一个适当的HTTP状态代码来表示数据的状态。(请参阅下面的apigee链接。)
链接:
看起来验证比错误/异常更麻烦,所以我将对这两个问题都说一下。
null
null
public class Customer
{
[Require]
public string Name { get; set; }
}
然后您可以使用一个
public class ValidationActionFilter : ActionFilterAttribute
{
public override void OnActionExecuting(HttpActionContext actionContext)
{
var modelState = actionContext.ModelState;
if (!modelState.IsValid) {
actionContext.Response = actionContext.Request
.CreateErrorResponse(HttpStatusCode.BadRequest, modelState);
}
}
}
有关此文件的详细信息,请访问http://ben.onfabrik.com/posts/automatic-modelstate-validation-in-aspnet-mvc
错误处理
最好向客户机返回一条表示发生的异常的消息(带有相关的状态代码)。
如果要指定消息,就必须立即使用
我通常创建我自己类型的“安全”异常,我希望客户机知道如何处理并用一个通用的500错误包装所有其他异常。
使用操作筛选器处理异常如下所示:
public class ApiExceptionFilterAttribute : ExceptionFilterAttribute
{
public override void OnException(HttpActionExecutedContext context)
{
var exception = context.Exception as ApiException;
if (exception != null) {
context.Response = context.Request.CreateErrorResponse(exception.StatusCode, exception.Message);
}
}
}
然后您可以在全球范围内注册它。
GlobalConfiguration.Configuration.Filters.Add(new ApiExceptionFilterAttribute());
这是我的自定义异常类型。
using System;
using System.Net;
namespace WebApi
{
public class ApiException : Exception
{
private readonly HttpStatusCode statusCode;
public ApiException (HttpStatusCode statusCode, string message, Exception ex)
: base(message, ex)
{
this.statusCode = statusCode;
}
public ApiException (HttpStatusCode statusCode, string message)
: base(message)
{
this.statusCode = statusCode;
}
public ApiException (HttpStatusCode statusCode)
{
this.statusCode = statusCode;
}
public HttpStatusCode StatusCode
{
get { return this.statusCode; }
}
}
}
我的API可以抛出的示例异常。
public class NotAuthenticatedException : ApiException
{
public NotAuthenticatedException()
: base(HttpStatusCode.Forbidden)
{
}
}