並不是全部的異常都須要 try-catch 進行重複的處理,這會致使大量的重複性代碼,一旦後續系統出現異常處理機制的修改,隨着代碼量增多,修改也會變的更加困難。css
ASP.NET Web API 中特別增長了全局異常過濾器功能,諸如於此的還有不少過濾器可供開發者選擇,以實現面向切面編程,它們在取代重複性編碼這一目標的路上,做出不少貢獻,同時下降了後期維護代碼的難度,提高了可讀性。編程
大多數異常處理的 try-catch 都一般是一樣的寫法(記錄異常日誌、返回錯誤信息等),所以咱們能夠將他們統一寫在一個過濾器中,讓 API 在出現異常時,即便沒有使用 try-catch 嵌套異常位置和解決方案,也可以自動進入指望的異常處理方法。服務器
注意:這是專門針對 Web API 所使用的全局異常處理器。若是是 Controller,則它有另一套全局異常處理機制,由於一般狀況下 MVC 的控制器不僅返回Json字符串,一般要涉及頁面View,文件File,Json字符串等。ide
Get Start工具
下面咱們以一個最簡單的異常處理過濾器代碼爲例,來講明應當如何使全局異常處理器生效:編碼
1.建立一個類 MyExceptionFilterAttribute,繼承 ExceptionFilterAttribute, System.Web.Mvc.IExceptionFilter 並實現接口方法spa
using Newtonsoft.Json;
using System.Net.Http;
using System.Web.Http.Filters;
using System.Web.Mvc;日誌
namespace WebAPITest.Filters
{
public class MyExceptionFilterAttribute : ExceptionFilterAttribute, System.Web.Mvc.IExceptionFilter
{
//MVC過濾器要求必須繼承此接口才容許註冊,但咱們能夠繼承、實現但不寫它。
public void OnException(ExceptionContext filterContext)
{
throw new NotImplementedException();
}繼承
//真正能讓API全局異常過濾器在出現異常時生效的是這個傢伙:
public override void OnException(HttpActionExecutedContext actionExecutedContext)
{
base.OnException(actionExecutedContext);接口
actionExecutedContext.Response = new HttpResponseMessage() { Content = new StringContent("出現異常") };
return;
}
}
2.爲此全局異常處理器進行註冊:
打開文件夾 App_Start 下的 FilterConfig.cs 爲過濾器註冊,由此才能使得過濾器生效。
特別說明:一旦進行了全局註冊,則全部方法出現異常時,過濾器都會生效。
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new MyExceptionFilterAttribute());
}
做爲特性標籤使用
固然,上述 MyExceptionFilterAttribute 除了可註冊爲全局異常過濾器之外,也能夠單獨爲 API 中的某些方法使用:(注意,方法自己就是"try",過濾器是"catch"。因此再也不須要在方法體內再次 try-catch)
using System.Net.Http;
using System.Web.Http;
using WebAPITest.Filters;
using WebAPITest.Models;
namespace WebAPITest.Controllers
{
//你也能夠把過濾器標籤打在這個地方,這表明該API類下的全部接口均接受[MyExceptionFilter]接管異常處理。
public class TestController : ApiController
{
[MyExceptionFilter] //特性標籤打在此處,則 UserException 方法出現異常時會觸發 MyExceptionFilterAttribute 中的異常處理方法。
public HttpResponseMessage UserException()
{
throw new UserException("用戶異常");
}
[MyExceptionFilter] //同上,這一特性標籤將幫助 SystemException 方法處理異常。
public HttpResponseMessage SystemException()
{
throw new Exception();
}
}
}
標籤與全局註冊的優先級問題
多個特性標籤,能夠全局註冊,能夠單獨在方法名稱上、類名上混合使用,那麼若是一個標籤被全局註冊,另外一個標籤被單獨打在方法名上或者類名上,則最終哪個處理器的方法會被觸發?
這些傢伙的優先級其實和 css 層疊樣式表的優先級相仿。
即:若是咱們全局註冊過一個過濾器A,又在 ApiController 類的最頂端打了另一個B、又在Action方法上打了第三個異常處理器C,那麼默認只會執行最靠近 Action 的C處理器,也就是說:ActionFilter > ClassFilter > GlobalFilter。
另外若是須要屢次執行所有生效,即:全局一次,Controller類一次,Action一次,那麼則須要爲過濾器頂端加那麼一個標籤 [AttributeUsage(AttributeTargets.All,AllowMultiple = true)],而後當異常觸發時,他們就可以支持屢次執行。
固然,真正的異常處理還會涉及不少複雜的內容,這只是一個概覽。例如返回值須要被標準化(包含狀態碼、消息、響應流等內容),調用異常處理工具向服務器發送異常信息記錄,記錄請求參數,對GET/POST請求致使異常的差別化處理方法等。
但咱們在這裏提供的是一個思路,讓你知道,精簡代碼、提高開發效率其實能夠有更多的方法和可能性。而沒必要非要使用同一種方式,當你以爲某些步驟一直在不斷重複,則應當已經有早期的開發者給出瞭解決方案,而你須要去發現他們。