其實對於C#異常處理大家都不陌生,但是對於在WeiApi上的異常處理實際上也和傳統異常處理區別不大,但是卻經過封裝可以讓異常更加友好,https://docs.microsoft.com/en-us/aspnet/web-api/overview/error-handling/exception-handling,通過微軟的官方介紹,我們可以知道WeiApi可以簡單概述為三種異常,接下來我們圍繞這三種異常給出例子,如何封裝和處理以上三種異常
異常過濾
異常過濾器實現了System.Web.Http.Filters.IExceptionFilter接口。編寫異常過濾器最簡單的方法是從System.Web.Http.Filters.ExceptionFilterAttribute類派生並重寫OnException方法。Microsoft給出的關於異常過濾器解釋,那么如何實現呢?通過閱讀《Asp.NET WEB API2 框架揭秘》,我們知道每一次客戶端請求API都會通過HTTP請求,服務端得到結果輸出response到客戶端。這個過程中,一旦服務端發生異常,會統一向客戶端返回500的錯誤。
那么在Web API中如何定義NotImplementedException類?首先在App_Start里面新建一個類WebApiExceptionFilterAttribute.cs,繼承ExceptionFilterAttribute,重寫OnException方法,代碼如下

1 public class WebApiExceptionFilterAttribute : ExceptionFilterAttribute 2 { 3 //重寫基類的異常處理方法 4 public override void OnException(HttpActionExecutedContext actionExecutedContext) 5 { 6 //1.異常日志記錄(正式項目里面一般是用log4net記錄異常日志) 7 Console.WriteLine(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + "——" + 8 actionExecutedContext.Exception.GetType().ToString() + ":" + actionExecutedContext.Exception.Message + "——堆棧信息:" + 9 actionExecutedContext.Exception.StackTrace); 10 11 //2.返回調用方具體的異常信息 12 if (actionExecutedContext.Exception is NotImplementedException) 13 { 14 actionExecutedContext.Response = new HttpResponseMessage(HttpStatusCode.NotImplemented); 15 } 16 else if (actionExecutedContext.Exception is TimeoutException) 17 { 18 actionExecutedContext.Response = new HttpResponseMessage(HttpStatusCode.RequestTimeout); 19 } 20 //.....這里可以根據項目需要返回到客戶端特定的狀態碼。如果找不到相應的異常,統一返回服務端錯誤500 21 else 22 { 23 actionExecutedContext.Response = new HttpResponseMessage(HttpStatusCode.InternalServerError); 24 } 25 26 base.OnException(actionExecutedContext); 27 } 28 }
代碼解析:通過判斷異常的具體類型,向客戶端返回不同的http狀態碼,示例里面寫了兩個,可以根據項目的實際情況加一些特定的我們想要捕獲的異常,然后將對應的狀態碼寫入http請求的response里面,對於一些我們無法判斷類型的異常,統一返回服務端錯誤500。Microsoft也有一個代碼實現,但是沒有封裝
注冊異常過濾
- 接口級別
- 控制器級別
- 全局配置
要將過濾器應用於特定操作,請將過濾器作為屬性添加到操作中:
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());
如果需要,甚至可以向Status Code里面寫入自定義的描述信息,並且還可以向我們的Response的Content里面寫入我們想要的信息。我們稍微改下OnException方法:
if (actionExecutedContext.Exception is NotImplementedException) { var oResponse = new HttpResponseMessage(HttpStatusCode.NotImplemented); oResponse.Content = new StringContent("方法不被支持"); oResponse.ReasonPhrase = "This Func is Not Supported"; actionExecutedContext.Response = oResponse; }
HttpResponseException自定義異常信息
異常過濾器是針對接口控制器以及全局定義,一般返回的都是服務器級別的錯誤,但是有的時候我們需要定義業務異常的代碼,那么如果是業務異常的情況下我們就可以使用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("沒有找到產品ID = {0}的產品", id)), ReasonPhrase = "Product ID Not Found" } throw new HttpResponseException(resp); } return item; }
可以看到具體的業務異常信息是通過HttpResponseMessage封裝,最后由HttpResponseException拋出,Microsoft沒有解釋HttpResponseMessage是什么,起初筆者以為這是一個HttpResponseException的子類,但是跟蹤了后發現HttpResponseMessage 繼承了IDisposable接口,而IDisposable接口的主要用途是釋放非托管的資源。 垃圾回收器自動釋放不再使用該對象時分配給托管對象的內存。 但是,不可能預測將發生垃圾回收。 此外,垃圾回收器具有不知道如窗口句柄的非托管資源,或打開文件和流。從描述上來看使用HttpResponseMessage時就代表發生了異常並且進行一次資源管理的回收,所以筆者認為,使用HttpResponseMessage可以更清晰的描述業務中所發生的 異常,並且在返回異常的時候進行一次垃圾回收,減少程序資源浪費
HttpError
HttpError對象提供了一個一致的方式在回應主體中返回的錯誤信息。以下示例顯示如何在響應正文中使用HttpError返回HTTP狀態碼404(Not Found)。通過Microsoft的解釋就可以知道HttpError提供的是狀態碼返回,那么實際應用上更多的是將其和HttpResponseException一起使用。
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; } }
總結
借鑒(Microsoft官網)ASP.NET Web API中的異常處理
在一般的項目中,可以定義好一些全體的關於服務器端的異常處理,並且封裝好一個HttpResponseException自定義異常的處理,無需捕獲HttpResponseException異常,Api會自己處理這個異常的,並且最好為每個異常給出更加詳細的HTTP狀態碼,可以讓異常更加精細友好