Asp.Net Web API 2第七課——Web API異常處理

前言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異常過濾器的幾種方式:

  1. 經過動做進行註冊
  2. 經過控制器進行註冊
  3. 全局註冊

要把過濾應用於特定的動做,在動做上添加該過濾器的註解屬性:

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

CreateErrorResponseSystem.Net.Http.HttpRequestMessageExtensions類中被定義爲一個擴展方法。本質上,CreateErrorResponse會建立一個HttpError實例,而後建立一個包含該HttpErrorHttpResponseMessage

Adding Custom Key-Values to HttpError把自定義的鍵值添加到HTTPError

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

 

Using HttpError with HttpResponseException以HttpResponseException的方式來使用HttpError

 前面的例子是從控制器動做返回一個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中新增長的一個亮點機制————屬性路由,貌似很牛逼的樣子。

相關文章
相關標籤/搜索