欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  科技

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

程序员文章站 2023-08-20 19:29:42
看mvc的源码我们知道,它是在 ControllerActionInvoker 类中执行 InvokeAction 方法来实现过滤器和action方法执行的。 通过查看源码我们知道,他是通过调用 InvokeActionMethodWithFilters 方法来实现IActionFilter过滤器和 ......

看mvc的源码我们知道,它是在 controlleractioninvoker 类中执行 invokeaction 方法来实现过滤器和action方法执行的。 

通过查看源码我们知道,他是通过调用 invokeactionmethodwithfilters 方法来实现iactionfilter过滤器和action方法执行的,如图 

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

点进去这个方法我们可以看到 

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 这个扩展方法是怎么执行的,直接看源码如下 

 

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

看了源码就很容易理解了,它就是遍历数据源来循环执行传递过来的委托,并把结果当成参数,执行下一次循环的委托。

所有我整理了一个容易理解的一串代码 

 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框架的写法一样。

运行结果为 如图

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

 

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