看mvc的源码我们知道,它是在 ControllerActionInvoker 类中执行 InvokeAction 方法来实现过滤器和action方法执行的。
通过查看源码我们知道,他是通过调用 InvokeActionMethodWithFilters 方法来实现IActionFilter过滤器和action方法执行的,如图
点进去这个方法我们可以看到
1 protected virtual ActionExecutedContext InvokeActionMethodWithFilters(ControllerContext controllerContext, IList<IActionFilter> filters, ActionDescriptor actionDescriptor, IDictionary<string, object> parameters) 2 { 3 ActionExecutingContext preContext = new ActionExecutingContext(controllerContext, actionDescriptor, parameters); 4 Func<ActionExecutedContext> seed = () => new ActionExecutedContext(controllerContext, actionDescriptor, false, null) 5 { 6 Result = this.InvokeActionMethod(controllerContext, actionDescriptor, parameters) 7 }; 8 return filters.Reverse<IActionFilter>().Aggregate(seed, (Func<ActionExecutedContext> next, IActionFilter filter) => () => ControllerActionInvoker.InvokeActionMethodFilter(filter, preContext, next))(); 9 }
看到这里我直接懵逼了,由于它委托中嵌套了委托而且还简写,还调用了扩展方法Aggregate累加器,所以很难直接看懂,这到底是怎么执行代码的呐?我来把代码整理如下
1 public class Class1 2 { 3 4 protected virtual ActionExecutedContext InvokeActionMethodWithFilters(ControllerContext controllerContext, IList<IActionFilter> filters, ActionDescriptor actionDescriptor, IDictionary<string, object> parameters) 5 { 6 ActionExecutingContext preContext = new ActionExecutingContext(controllerContext, actionDescriptor, parameters); 7 8 Func<ActionExecutedContext> seed = () => new ActionExecutedContext(controllerContext, actionDescriptor, false, null) 9 { 10 Result = this.InvokeActionMethod(controllerContext, actionDescriptor, parameters) 11 }; 12 13 Func<Func<ActionExecutedContext>, IActionFilter, Func<ActionExecutedContext>> secondParam = 14 (Func<ActionExecutedContext> next, IActionFilter filter) => 15 { 16 Func<ActionExecutedContext> returnFunc = () => 17 { 18 return Class1.InvokeActionMethodFilter(filter, preContext, next); 19 }; 20 21 return returnFunc; 22 23 //这个是简写 24 //return () => Class1.InvokeActionMethodFilter(filter, preContext, next); 25 }; 26 27 return filters.Reverse<IActionFilter>().Aggregate(seed, 28 //(Func<ActionExecutedContext> next, IActionFilter filter) => () => Class1.InvokeActionMethodFilter(filter, preContext, next) 29 secondParam 30 ) 31 .Invoke(); 32 } 33 34 internal static ActionExecutedContext InvokeActionMethodFilter(IActionFilter filter, ActionExecutingContext preContext, Func<ActionExecutedContext> continuation) 35 { 36 filter.OnActionExecuting(preContext); 37 if (preContext.Result != null) 38 { 39 return new ActionExecutedContext(preContext, preContext.ActionDescriptor, true, null) 40 { 41 Result = preContext.Result 42 }; 43 } 44 bool flag = false; 45 ActionExecutedContext actionExecutedContext = null; 46 try 47 { 48 actionExecutedContext = continuation(); 49 } 50 catch (ThreadAbortException) 51 { 52 actionExecutedContext = new ActionExecutedContext(preContext, preContext.ActionDescriptor, false, null); 53 filter.OnActionExecuted(actionExecutedContext); 54 throw; 55 } 56 catch (Exception exception) 57 { 58 flag = true; 59 actionExecutedContext = new ActionExecutedContext(preContext, preContext.ActionDescriptor, false, exception); 60 filter.OnActionExecuted(actionExecutedContext); 61 if (!actionExecutedContext.ExceptionHandled) 62 { 63 throw; 64 } 65 } 66 if (!flag) 67 { 68 filter.OnActionExecuted(actionExecutedContext); 69 } 70 return actionExecutedContext; 71 } 72 73 protected virtual ActionResult InvokeActionMethod(ControllerContext controllerContext, ActionDescriptor actionDescriptor, IDictionary<string, object> parameters) 74 { 75 object actionReturnValue = actionDescriptor.Execute(controllerContext, parameters); 76 return this.CreateActionResult(controllerContext, actionDescriptor, actionReturnValue); 77 } 78 79 protected virtual ActionResult CreateActionResult(ControllerContext controllerContext, ActionDescriptor actionDescriptor, object actionReturnValue) 80 { 81 if (actionReturnValue == null) 82 { 83 return new EmptyResult(); 84 } 85 ActionResult arg_29_0; 86 if ((arg_29_0 = (actionReturnValue as ActionResult)) == null) 87 { 88 arg_29_0 = new ContentResult(); 89 //(arg_29_0 = new ContentResult()).Content = Convert.ToString(actionReturnValue, CultureInfo.InvariantCulture); 90 (arg_29_0 as ContentResult).Content = Convert.ToString(actionReturnValue, CultureInfo.InvariantCulture); 91 } 92 return arg_29_0; 93 } 94 95 }
咋一看,还是不知所云,一步一步来,
首先,我们先要知道 Aggregate 这个扩展方法是怎么执行的,直接看源码如下
看了源码就很容易理解了,它就是遍历数据源来循环执行传递过来的委托,并把结果当成参数,执行下一次循环的委托。
所有我整理了一个容易理解的一串代码
1 public class Class2 2 { 3 4 public void Test() 5 { 6 var preContext = new ActionExecutingContext(); 7 8 Func<ActionExecutedContext> seed = () => 9 { 10 Console.WriteLine("执行action"); 11 return new ActionExecutedContext(); 12 }; 13 14 int[] arr = { 1, 2, 3, 4, 5, 6, 7, 8, 9 }; 15 16 Func<Func<ActionExecutedContext>, int, Func<ActionExecutedContext>> secondParam = 17 (Func<ActionExecutedContext> next, int filter) => 18 { 19 return () => this.getStr(next, filter, preContext); 20 }; 21 22 var reFunc2 = arr.Reverse().Aggregate<int, Func<ActionExecutedContext>>(seed, secondParam); 23 reFunc2.Invoke(); 24 25 } 26 27 public ActionExecutedContext getStr(Func<ActionExecutedContext> func, int filter, ActionExecutingContext preContext) 28 { 29 30 Console.WriteLine("before action----" + filter + "----" + preContext.ToString()); 31 32 var res = func.Invoke(); 33 34 Console.WriteLine("before action----" + filter + "----" + res.ToString()); 35 36 return res; 37 } 38 39 }
我是用一个int数组来模拟IActionFilter集合,其它的写法都和mvc框架的写法一样。
运行结果为 如图
看到这里,你是否明白了,它就是通过 委托里嵌套委托 来巧妙的实现了俄罗斯套娃的形式来实现IActionFilter过滤器和Action方法的执行。