MVC中IActionFilter过滤器俄罗斯套娃的实现方式

看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 }
View Code

看到这里我直接懵逼了,由于它委托中嵌套了委托而且还简写,还调用了扩展方法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     }
View Code

咋一看,还是不知所云,一步一步来,

首先,我们先要知道 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     }
View Code

我是用一个int数组来模拟IActionFilter集合,其它的写法都和mvc框架的写法一样。

运行结果为 如图

看到这里,你是否明白了,它就是通过 委托里嵌套委托 来巧妙的实现了俄罗斯套娃的形式来实现IActionFilter过滤器和Action方法的执行。

猜你喜欢

转载自www.cnblogs.com/xiaoZhang521/p/11269677.html
今日推荐