MVC中IActionFilter过滤器俄罗斯套娃的实现方式
程序员文章站
2022-05-27 20:26:42
看mvc的源码我们知道,它是在 ControllerActionInvoker 类中执行 InvokeAction 方法来实现过滤器和action方法执行的。 通过查看源码我们知道,他是通过调用 InvokeActionMethodWithFilters 方法来实现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 }
看到这里我直接懵逼了,由于它委托中嵌套了委托而且还简写,还调用了扩展方法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方法的执行。