在ASP.NET MVC中的四大篩選器(Filter),ActionFilter直接應用在某個Action方法上,它在目標Action方法執行前後對調用進行攔截以執行一些額外的操作。這是一種典型的AOP式的設計,如果我們需要在執行某個Action方法的前後執行一些操作,可以通過定義ActionFilter來實現。本篇文章主要講述多一個應用到相同Action方法上的ActionFilter的執行機制。
一、ActionFilter
ActionFilter允許我們在目標Action方法執行前後對調用進行攔截以執行一些額外的操作,所有的ActionFilter實現了具有如下定義的介面IActionFilter。
1: public interface IActionFilter
2: {
3: void OnActionExecuting(ActionExecutingContext filterContext);
4: void OnActionExecuted(ActionExecutedContext filterContext);
5: }
6:
7: public class ActionExecutingContext : ControllerContext
8: {
9: public ActionExecutingContext();
10: public ActionExecutingContext(ControllerContext controllerContext, ActionDescriptor actionDescriptor, IDictionary<string, object> actionParameters);
11:
12: public virtual ActionDescriptor ActionDescriptor { get; set; }
13: public virtual IDictionary<string, object> ActionParameters { get; set; }
14: public ActionResult Result { get; set; }
15: }
16:
17: public class ActionExecutedContext : ControllerContext
18: {
19: public ActionExecutedContext();
20: public ActionExecutedContext(ControllerContext controllerContext, ActionDescriptor actionDescriptor, bool canceled, Exception exception);
21:
22: public virtual ActionDescriptor ActionDescriptor { get; set; }
23: public virtual bool Canceled { get; set; }
24: public virtual Exception Exception { get; set; }
25: public bool ExceptionHandled { get; set; }
26: public ActionResult Result { get; set; }
27: }
如上面的代碼片斷所示,IActionFilter介面中定義了兩個方法OnActionExecuting和OnActionExecuted,這兩個方法分別在目標Action方法執行前後被調用,它們的參數類型分別為ActionExecutingContext和ActionExecutedContext。這兩個上下文了類型均是ControllerContext的子類。
我們可以從ActionExecutingContext對象中擷取到用於描述當前Action的ActionDescriptor,以及參數列表。ActionFilter可以在OnActionExecuting方法中對ActionExecutingContext對象的Result屬性進行賦值來直接響應當前的請求。一旦ActionExecutingContext的Result屬性被成功賦值,將會終止後續ActionFilter和最終目標方法的執行。
ActionExecutedContext具有額外的三個屬性,Exception表示執行Action方法過程中拋出的異常,而ExceptionHandled是一個表示是否對異常已經做出處理的標記。Canceled屬性工作表示沒有完成整個ActionFilter鏈和目標Action方法的執行而中途被終止。
二、ActionFilter的執行機制
當ActionInvoker在執行目標Action方法之前,會根據Order和Scope屬性對用於封裝ActionFilter的Filter對象進行排序。然後根據當前ControllerContext和ActionDescriptro建立一個ActionExecutingContext對象,並將其作為參數依次調用所有ActionFilter的OnActionExecuting方法。
在這之後真正的目標Action方法被執行,ActionInvoker隨後執行後續的篩選操作。具體來說,它根據當前ControllerContext、ActionDescriptro以及Action方法執行過程中拋出的異常建立一個ActionExecutedContext對象。該ActionExecutedContext的Cancel屬性為False,如果Action方法返回一個ActionResult對象,該對象將會作為該ActionExecutedContext的Result屬性。
接下來按照相反的次序依次調用ActionFilter對象的OnActionExecuted方法,執行過程中的ActionFilter可以修改ActionExecutedContext的Result屬性。當整個ActionFilter鏈執行結束之後,ActionExecutedContext的Result屬性返回的ActionResult將會作為對當前請求的響應。右圖基本上反映了連同目標Action在內的整個ActionFilter鏈的執行過程。