7.1WebApi2的异常处理
这篇文章描述错误和异常处理在 ASP.NET Web API。
HttpResponseException
如果 Web API 控制器引发未捕获的异常,会发生什么?默认情况下,大多数异常被转译为 HTTP 响应状态代码 500,内部服务器错误。
HttpResponseException类型是一种特殊情况。此异常返回您在异常构造函数中指定的所有 HTTP 状态代码。例如,下面的方法返回 404,找不到,如果id参数无效。
1 public Product GetProduct(int id) 2 { 3 Product item = repository.Get(id); 4 if (item == null) 5 { 6 throw new HttpResponseException(HttpStatusCode.NotFound); 7 } 8 return item; 9 }
如果你想进行更多控制的响应,你也可以构造整个响应消息,包括它与HttpResponseException:
1 public Product GetProduct(int id) 2 { 3 Product item = repository.Get(id); 4 if (item == null) 5 { 6 var resp = new HttpResponseMessage(HttpStatusCode.NotFound) 7 { 8 Content = new StringContent(string.Format("No product with ID = {0}", id)), 9 ReasonPhrase = "Product ID Not Found" 10 } 11 throw new HttpResponseException(resp); 12 } 13 return item; 14 }
异常过滤器
您可以自定义 Web API 如何处理异常通过编写的异常筛选器。当控制器方法引发任何未处理的异常时执行异常筛选器就是HttpResponseException异常。HttpResponseException型是一种特殊的情况,因为它特别针对返回的 HTTP 响应。
异常筛选器实现System.Web.Http.Filters.IExceptionFilter接口。写异常筛选器的最简单方法是从System.Web.Http.Filters.ExceptionFilterAttribute类派生和重写OnException方法。
注意:
在 ASP.NET Web API 的异常筛选器是类似于那些在 ASP.NET MVC 中。然而,他们分别在一个单独的命名空间和函数声明。尤其是,在 MVC 中使用的HandleErrorAttribute类并不处理由 Web API 控制器引发的异常。
这里是一个过滤器,转换未实现的 HTTP 状态代码 501, NotImplementedException例外 ︰
1 namespace ProductStore.Filters 2 { 3 using System; 4 using System.Net; 5 using System.Net.Http; 6 using System.Web.Http.Filters; 7 8 public class NotImplExceptionFilterAttribute : ExceptionFilterAttribute 9 { 10 public override void OnException(HttpActionExecutedContext context) 11 { 12 if (context.Exception is NotImplementedException) 13 { 14 context.Response = new HttpResponseMessage(HttpStatusCode.NotImplemented); 15 } 16 } 17 } 18 }
HttpActionExecutedContext对象的响应属性包含将发送到客户端的 HTTP 响应消息。
注册异常过滤器
有几种方法来注册 Web API 异常筛选器 ︰
1.action
2.控制器
3.全局注册
若要将筛选器应用于具体的行动,在Action上贴上特性标签 ︰
1 public class ProductsController : ApiController 2 { 3 [NotImplExceptionFilter] 4 public Contact GetContact(int id) 5 { 6 throw new NotImplementedException("This method is not implemented"); 7 }
若要将筛选器应用于在控制器上的操作,在控制器类上贴上特性标签 ︰
1 [NotImplExceptionFilter] 2 public class ProductsController : ApiController 3 { 4 // ... 5 }
要将筛选器应用全局 Web API 的所有控制器,请将该筛选器的一个实例添加到GlobalConfiguration.Configuration.Filters集合。核发此集合中的筛选器适用于任何 Web API 控制器动作。
1 GlobalConfiguration.Configuration.Filters.Add( 2 new ProductStore.NotImplExceptionFilterAttribute());
如果你使用"ASP.NET MVC 4 Web 应用程序"项目模板来创建您的项目,把里面的WebApiConfig
类,位于 App_Start 文件夹中的 Web API 配置代码 ︰
1 public static class WebApiConfig 2 { 3 public static void Register(HttpConfiguration config) 4 { 5 config.Filters.Add(new ProductStore.NotImplExceptionFilterAttribute()); 6 7 // Other configuration code... 8 } 9 }
HttpError
HttpError对象提供一致的方法来响应正文中返回错误的信息。下面的示例演示如何返回 HTTP 状态代码 404 (未找到) 与HttpError在响应正文中。
1 public HttpResponseMessage GetProduct(int id) 2 { 3 Product item = repository.Get(id); 4 if (item == null) 5 { 6 var message = string.Format("Product with id = {0} not found", id); 7 return Request.CreateErrorResponse(HttpStatusCode.NotFound, message); 8 } 9 else 10 { 11 return Request.CreateResponse(HttpStatusCode.OK, item); 12 } 13 }
CreateErrorResponse是在System.Net.Http.HttpRequestMessageExtensions类中定义的扩展方法。在内部, CreateErrorResponse创建一个HttpError实例,然后创建包含HttpError的HttpResponseMessage.
在此示例中,如果该方法是成功的它返回的 HTTP 响应中的产品。但如果找不到要求的产品,HTTP 响应包含HttpError请求主体中。响应可能如下所示 ︰
1 HTTP/1.1 404 Not Found 2 Content-Type: application/json; charset=utf-8 3 Date: Thu, 09 Aug 2012 23:27:18 GMT 4 Content-Length: 51 5 6 { 7 "Message": "Product with id = 12 not found" 8 }
HttpError被序列化为 JSON 在此示例中的通知。使用HttpError的优点之一是它穿过任何其他强类型的模型相同的内容协商和序列化进程。
HttpError 和模型验证
对于模型验证,可以将模型状态传递给CreateErrorResponse,要在响应中包含验证错误 ︰
1 public HttpResponseMessage PostProduct(Product item) 2 { 3 if (!ModelState.IsValid) 4 { 5 return Request.CreateErrorResponse(HttpStatusCode.BadRequest, ModelState); 6 } 7 8 // Implementation not shown... 9 }
此示例可能会返回以下响应 ︰
1 HTTP/1.1 400 Bad Request 2 Content-Type: application/json; charset=utf-8 3 Content-Length: 320 4 5 { 6 "Message": "The request is invalid.", 7 "ModelState": { 8 "item": [ 9 "Required property 'Name' not found in JSON. Path '', line 1, position 14." 10 ], 11 "item.Name": [ 12 "The Name field is required." 13 ], 14 "item.Price": [ 15 "The field Price must be between 0 and 999." 16 ] 17 } 18 }
关于模型验证的详细信息,请参见ASP.NET Web API 中的模型验证.
使用 HttpResponseException HttpError
前面的示例返回HttpResponseMessage消息从控制器的操作,但您也可以使用HttpResponseException返回HttpError。这允许您返回一个强类型的模型中正常成功的情况,同时还返回HttpError ,如果有错误 ︰
1 public Product GetProduct(int id) 2 { 3 Product item = repository.Get(id); 4 if (item == null) 5 { 6 var message = string.Format("Product with id = {0} not found", id); 7 throw new HttpResponseException( 8 Request.CreateErrorResponse(HttpStatusCode.NotFound, message)); 9 } 10 else 11 { 12 return item; 13 } 14 }