前言:上篇C#進階系列——WebApi接口傳參不再困惑:傳參詳解介紹了WebApi參數的傳遞,這篇來看看WebApi裡面異常的處理。關于異常處理,作為程式員的我們肯定不陌生,記得在介紹 AOP 的時候,我們講過通過AOP可以統一截獲異常。那麼在我們的WebApi裡面一般是怎麼處理異常的呢,今天這一篇,部落客帶着大家一起來實踐下WebApi的異常處理。
WebApi系列文章
C#進階系列——WebApi接口測試工具:WebApiTestClient
C#進階系列——WebApi 跨域問題解決方案:CORS
C#進階系列——WebApi身份認證解決方案:Basic基礎認證
C#進階系列——WebApi接口傳參不再困惑:傳參詳解
C#進階系列——WebApi接口傳回值不困惑:傳回值類型詳解
C#進階系列——WebApi異常處了解決方案
C#進階系列——WebApi區域Area使用小結
為什麼說是實踐?因為在http://www.asp.net裡面已經明确給出WebApi的異常處理機制。光有理論還不夠,今天我們還是來試一把。通過實踐,我們可能發現一些更詳盡的用法。
我們知道,一般情況下,WebApi作為服務使用,每次用戶端發送http請求到我們的WebApi服務裡面,服務端得到結果輸出response到用戶端。這個過程中,一旦服務端發生異常,會統一向用戶端傳回500的錯誤。
我們來看看http請求
而有些時候,我們用戶端需要得到更加精确的錯誤碼來判斷異常類型,怎麼辦呢?
記得在介紹AOP的時候,我們介紹過MVC裡面的IExceptionFilter接口,這個接口用于定義異常篩選器所需的方法,在WebApi裡面,也有這麼一個異常篩選器,下面我們通過一個執行個體來看看具體如何實作。
首先在App_Start裡面建立一個類WebApiExceptionFilterAttribute.cs,繼承ExceptionFilterAttribute,重寫OnException方法
代碼解析:通過判斷異常的具體類型,向用戶端傳回不同的http狀态碼,示例裡面寫了兩個,可以根據項目的實際情況加一些特定的我們想要捕獲的異常,然後将對應的狀态碼寫入http請求的response裡面,對于一些我們無法判斷類型的異常,統一傳回服務端錯誤500。關于http的狀态碼,framework裡面定義了一些常見的類型,我們大概看看:
Http狀态碼
定義好了異常處理方法,剩下的就是如何使用了。可以根據實際情況,在不同級别使用統一的異常處理機制。
執行到異常後,會先進到OnException方法:
執行完成之後浏覽器檢視:
如果需要,甚至可以向Status Code裡面寫入自定義的描述資訊,并且還可以向我們的Response的Content裡面寫入我們想要的資訊。我們稍微改下OnException方法:
看看ReasonPhrase描述資訊
看看Response的描述資訊
如果想要某一個或者多個控制器裡面的所有接口都使用異常過濾,直接在控制器上面标注特性即可。
某一個控制器上面啟用異常過濾
多個控制器上面同時啟用異常過濾
這樣,所有繼承BaseApiController的子類都會啟用異常過濾。
如果需要對整個應用程式都啟用異常過濾,則需要做如下兩步:
1、在Global.asax全局配置裡面添加 GlobalConfiguration.Configuration.Filters.Add(new WebApiExceptionFilterAttribute()); 這一句,如下:
2、在WebApiConfig.cs檔案的Register方法裡面添加 config.Filters.Add(new WebApiExceptionFilterAttribute()); 這一句,如下:
上面說的是全局的異常捕獲以及處理方式,在某些情況下,我們希望以異常的方式向用戶端發送相關資訊,可能就需要用到我們的HttpResponseException。比如:
執行之後浏覽器裡面檢視結果:
代碼釋疑:細心的朋友可能,發現了,這裡既使用了HttpResponseMessage,又使用了HttpResponseException,那麼,像這種可控的異常,我們是否可以直接以HttpResponseMessage的形式直接傳回到用戶端而不用抛出異常呢?這裡就要談談這兩個對象的差別了,部落客的了解是HttpResonseMessage對象用來響應訊息并包含狀态碼及資料内容,HttpResponseException對象用來向用戶端傳回包含錯誤訊息的異常。
在網上看到一篇 文章 這樣描述兩者的差別:當呼叫 Web API 服務時發生了與預期上不同的錯誤時,理當應該中止程式傳回錯誤訊息,這時對于錯誤的傳回就該使用 HttpResponseException,而使用 HttpResponseMessage 則是代表着當用戶端發送了一個工作請求而 Web API 正确的完成了這個工作,就能夠使用 HttpResponseMessage 傳回一個 201 的訊息,是以 HttpResponseMessage 與 HttpResponseException 在使用上根本的目标就是不同的,用 HttpResponseMessage 去傳回一個例外錯誤也會讓程式結構難以辨識且不夠清晰。
HttpError對象提供一緻的方法來響應正文中傳回錯誤的資訊。準确來說,HttpError并不是一個異常,隻是用來包裝錯誤資訊的一個對象。其實在某一定的程度上,HttpError和HttpResponseMessage使用比較相似,二者都可以向用戶端傳回http狀态碼和錯誤訊息,并且都可以包含在HttpResponseException對象中發回到用戶端。但是,一般情況下,HttpError隻有在向用戶端傳回錯誤訊息的時候才會使用,而HttpResponseMessage對象既可以傳回錯誤訊息,也可傳回請求正确的消息。其實關于HttpError沒什麼特别好講的,我們來看一個例子就能明白:
假如現在在執行try裡面複雜業務邏輯的時候發生了異常,我們捕獲到了異常然後向用戶端傳回HttpError對象,這個對象裡面包含我們自定義的錯誤訊息,如果正常則傳回HttpResponseMessage對象。
如果請求異常:
如果請求正常
以上三種異常的處理方法,可以根據不同的場景選擇使用。
如果項目對異常處理要求并不高,隻需要記錄好異常日志即可,那麼使用異常篩選器就能夠搞定
如果項目需要對不同的異常,用戶端做不同的處理。而這個時候使用異常篩選器不能詳盡所有的異常,可能使用HttpResponseException對象是更好的選擇,定義更加精細的異常和異常描述。
對于何時使用HttpError,又何時使用HttpResponseMessage,可以參考上文三裡面用法。
當然實際項目中很可能以上兩種或者三種同時使用。
上文通過一些簡單的示例介紹了下WebApi裡面異常的處理機制,可能不夠深入,但對于一般項目的異常處理基本夠用。其實有一點部落客還沒有想明白,對于構造函數裡面的異常該如何統一捕獲呢?通過異常篩選器是捕獲不到的,不知道園友們有沒有什麼更好的辦法,不吝賜教,感謝感謝!如果本文能幫到你,不妨推薦下,您的推薦是部落客繼續總結的動力!