Asp.net MVC源码分析--Action Filter的链式调用
上一篇中我们介绍了asp.net MVC 的Filter的种类,以及调用的时点.今天我们来看一下ActionFilter/ResultFilter 调用的细节以及源码中令人叫绝的代码实现.首先我们看到在Contoller这个类中已经实现了IActionFilter/IResultFilter,并且它们的接口实现是调用两个虚函数来实现的,这就为我们提供了便利,可以在我们的Controller中重写这些虚函数来截获并实现我们自己的逻辑.
Controller.cs
1 protected virtual void OnActionExecuting(ActionExecutingContext filterContext) {
2 }
3
4 protected virtual void OnActionExecuted(ActionExecutedContext filterContext) {
5 }
6
7 protected virtual void OnAuthorization(AuthorizationContext filterContext) {
8 }
9
10 protected virtual void OnException(ExceptionContext filterContext) {
11 }
12
13 protected virtual void OnResultExecuted(ResultExecutedContext filterContext) {
14 }
15
16 protected virtual void OnResultExecuting(ResultExecutingContext filterContext) {
17 }
18
19
20 #region IActionFilter Members
21 void IActionFilter.OnActionExecuting(ActionExecutingContext filterContext) {
22 OnActionExecuting(filterContext);
23 }
24
25 void IActionFilter.OnActionExecuted(ActionExecutedContext filterContext) {
26 OnActionExecuted(filterContext);
27 }
28 #endregion
29
30 #region IResultFilter Members
31 void IResultFilter.OnResultExecuting(ResultExecutingContext filterContext) {
32 OnResultExecuting(filterContext);
33 }
34
35 void IResultFilter.OnResultExecuted(ResultExecutedContext filterContext) {
36 OnResultExecuted(filterContext);
37 }
38 #endregion
但是我们如何来获取这个由Controller类实现的Filter接口呢?请看ControllerInstanceFilterProvider,这个已经默认注册的Filter Provider可以得到这些Filter的接口实现.
ControllerInstanceFilterProvider.cs
1 public class ControllerInstanceFilterProvider : IFilterProvider {
2 public IEnumerable<Filter> GetFilters(ControllerContext controllerContext, ActionDescriptor actionDescriptor) {
3 if (controllerContext.Controller != null) {
4 // Use FilterScope.First and Order of Int32.MinValue to ensure controller instance methods always run first
5 yield return new Filter(controllerContext.Controller, FilterScope.First, Int32.MinValue);
6 }
7 }
8 }
---------------------------------------------------------------------------------------------
但是请大家考虑一个问题,如果我们在Action 上也同时标记了Action Filter的时候会产生一次调用需要调用两个或多个Action filter的时候MVC 怎么处理这样的情况呢? 请看在ControllerActionInvoker.InvokeAction方法中的InvokeActionMethodWithFilters 方法. 我们今天的主角登场了,嘿嘿.
ControllerActionInvoker.cs
1 protected virtual ActionExecutedContext InvokeActionMethodWithFilters(ControllerContext controllerContext, IList<IActionFilter> filters, ActionDescriptor actionDescriptor, IDictionary<string, object> parameters) {
2 ActionExecutingContext preContext = new ActionExecutingContext(controllerContext, actionDescriptor, parameters);
3 Func<ActionExecutedContext> continuation = () =>
4 new ActionExecutedContext(controllerContext, actionDescriptor, false /* canceled */, null /* exception */) {
5 Result = InvokeActionMethod(controllerContext, actionDescriptor, parameters)
6 };
7
8 // need to reverse the filter list because the continuations are built up backward
9 Func<ActionExecutedContext> thunk = filters.Reverse().Aggregate(continuation,
10 (next, filter) => () => InvokeActionMethodFilter(filter, preContext, next));
11 return thunk();
12 }
首先我们看到代码中声明了Func<ActionExecutedContext> continuation, 的这样一个委托, 注意这里只是声明还没有调用哦.这个委托是用来调用Action方法的. 接下来又声明了Func<ActionExecutedContext> thunk 这样一个委托, 这个委托的内容是用filters.Aggregate 方法来合并我们的Filter执行链,(这里不理解的话,我们需要看Aggregate 方法的说明). InvokeActionMethodFilter的方法是执行IActionFilter中的接口实现.
InvokeActionMethodFilter方法
1 internal static ActionExecutedContext InvokeActionMethodFilter(IActionFilter filter, ActionExecutingContext preContext, Func<ActionExecutedContext> continuation) {
2 filter.OnActionExecuting(preContext);
3 if (preContext.Result != null) {
4 return new ActionExecutedContext(preContext, preContext.ActionDescriptor, true /* canceled */, null /* exception */) {
5 &nb
补充:Web开发 , ASP.Net ,