前言html
閱讀本文以前,您也能夠到Asp.Net Web API 2 系列導航進行查看 http://www.cnblogs.com/aehyok/p/3446289.htmljson
本文主要來說解Asp.Net Web API中錯誤和異常的處理,包括如下幾點:服務器
1.HttpResponseException——HTTP響應異常app
2.Exception Filters——異常過濾器ide
3.Registering Exception Filters——註冊異常過濾器spa
4.HttpError——HTTP錯誤設計
HttpResponseException——HTTP響應異常code
若是一個Web API 控制器拋出一個未捕獲的異常,會發生什麼?在默認狀況下,大多數異常都被轉換爲一個帶有狀態碼500的內部服務器錯誤的HTTP響應。orm
這個HTTPResponseException類型是一個特殊的類型。這種異常會返回你在異常構造器中指定的任何HTTP狀態碼。例如,在如下方法中,若是這個id參數無效,那麼會返回「404——未找到」。htm
public Product GetProduct(int id) { Product item = repository.Get(id); if (item == null) { throw new HttpResponseException(HttpStatusCode.NotFound); } return item; }
爲了對響應進行更多的控制,你也能夠構造整個響應消息,並用HTTPResponseException來包含它:
public Product GetProduct(int id) { Product item = repository.Get(id); if (item == null) { var resp = new HttpResponseMessage(HttpStatusCode.NotFound) { Content = new StringContent(string.Format("No product with ID = {0}", id)), ReasonPhrase = "Product ID Not Found" } throw new HttpResponseException(resp); } return item;
Exception Filters——異常過濾器
經過編寫一個異常過濾器,你能夠定製Web API如何處理異常。當一個控制器拋出一個未處理的異常,且這個異常不是一個HttpResponseException異常時,一個異常過濾器會被執行。HttpResponseException類型一個特殊的狀況,由於它是專門設計用來返回一個HTTP響應的。
異常過濾器實現System.Web.Http.Filters.IExceptionFilter接口。編寫異常過濾器最簡單的方式是經過System.Web.Http.Filters.ExceptionFilterAttribute類進行派生,並重寫其OnException方法。
ASP.NET Web API中的異常過濾器與Asp.Net MVC中的是極爲相似的。而後,他們被聲明在不一樣的命名空間中,且功能也是獨立的。特別強調一下,Asp.Net MVC中使用的HandleErrorAttribute類不會處理Web API控制器中拋出的異常。
如下是將NotImplementedException異常轉換成HTTP狀態碼「501 — 未實現」的一個過濾器:
using System; using System.Net; using System.Net.Http; using System.Web.Http.Filters; public class NotImplExceptionFilterAttribute : ExceptionFilterAttribute { public override void OnException(HttpActionExecutedContext context) { if (context.Exception is NotImplementedException) { context.Response = new HttpResponseMessage(HttpStatusCode.NotImplemented); } } }
HttpActionExecutedContext對象的Response屬性含有將發送給客戶端的HTTP響應消息。
Registering Exception Filters——註冊異常過濾器
如下是註冊Web API異常過濾器的幾種方式:
要把過濾應用於特定的動做,在動做上添加該過濾器的註解屬性:
public class ProductsController : ApiController { [NotImplExceptionFilter] public Contact GetContact(int id) { throw new NotImplementedException("This method is not implemented"); } }
要把過濾器運用於一個控制器的全部動做,在控制器上添加該過濾器的註解屬性:
[NotImplExceptionFilter] public class ProductsController : ApiController { // ... }
要全局性地把過濾器運用於全部Web API控制器,將該過濾器的一個實例添加到GlobalConfiguration.Configuration.Filters集合。這個集合中的異常過濾器會運用於任何Web API控制器動做。
GlobalConfiguration.Configuration.Filters.Add( new ProductStore.NotImplExceptionFilterAttribute());
若是你用的是「ASP.NET MVC 4 Web應用程序」項目模板建立的項目,要把你的Web API配置代碼被放在WebApiConfig類中,它位於App_Start文件夾:
public static class WebApiConfig { public static void Register(HttpConfiguration config) { config.Filters.Add(new ProductStore.NotImplExceptionFilterAttribute()); // Other configuration code(其它配置代碼)... } }
HttpError——HTTP錯誤
HttpError對象爲在響應正文中返回錯誤消息提供了相應的方式。如下示例演示瞭如何用HttpError在響應體中返回HTTP狀態碼「404 — 未找到」:
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響應中返回產品。但若是所請求的產品未找到,則HTTP響應會在請求體中包含一個HttpError。該響應看上去大體像這樣:
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" }
注意,在這個例子中,HttpError會被序列化成JSON。使用HttpError的一個好處是,與其它強類型模型同樣,會進行一樣的「content-negotiation」(暫未實現)和序列化過程。
直接替代建立HttpError對象的一種辦法是,你可使用CreateErrorResponse方法:
public HttpResponseMessage GetProduct(int id) { Product item = repository.Get(id); if (item == null) { var message = string.Format("Product with id = {0} not found", id); return Request.CreateErrorResponse(HttpStatusCode.NotFound, message); } else { return Request.CreateResponse(HttpStatusCode.OK, item); } }
CreateErrorResponse在System.Net.Http.HttpRequestMessageExtensions類中被定義爲一個擴展方法。本質上,CreateErrorResponse會建立一個HttpError實例,而後建立一個包含該HttpError的HttpResponseMessage。
HttpError類其實是一個「鍵-值」集合(它派生於Dictionary<string, object>),所以你能夠添加本身的「鍵-值」對:
public HttpResponseMessage GetProduct(int id) { Product item = repository.Get(id); if (item == null) { var message = string.Format("Product with id = {0} not found", id); var err = new HttpError(message); err["error_sub_code"] = 42; return Request.CreateErrorResponse(HttpStatusCode.NotFound, err); } else { return Request.CreateResponse(HttpStatusCode.OK, item); } }
前面的例子是從控制器動做返回一個HttpResponseMessage消息,但你也可使用HttpResponseException來返回一個HttpError。這讓你可以在正常成功狀況下返回強類型模型,而在有錯誤時,仍返回HttpError。
public Product GetProduct(int id) { Product item = repository.Get(id); if (item == null) { var message = string.Format("Product with id = {0} not found", id); throw new HttpResponseException( Request.CreateErrorResponse(HttpStatusCode.NotFound, message)); } else { return item; } }
總結
感受比MVC中的異常處理更爲出色,不知道新版本的MVC中的異常處理機制如何。下一篇文章未來講解Web API2中新增長的一個亮點機制————屬性路由,貌似很牛逼的樣子。