经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » 数据库/运维 » Windows » 查看文章
MVC中IActionFilter过滤器俄罗斯套娃的实现方式
来源:cnblogs  作者:IT_xiaozhang  时间:2019/8/9 8:42:08  对本文有异议

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

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

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

  1. 1 protected virtual ActionExecutedContext InvokeActionMethodWithFilters(ControllerContext controllerContext, IList<IActionFilter> filters, ActionDescriptor actionDescriptor, IDictionary<string, object> parameters)
  2. 2 {
  3. 3 ActionExecutingContext preContext = new ActionExecutingContext(controllerContext, actionDescriptor, parameters);
  4. 4 Func<ActionExecutedContext> seed = () => new ActionExecutedContext(controllerContext, actionDescriptor, false, null)
  5. 5 {
  6. 6 Result = this.InvokeActionMethod(controllerContext, actionDescriptor, parameters)
  7. 7 };
  8. 8 return filters.Reverse<IActionFilter>().Aggregate(seed, (Func<ActionExecutedContext> next, IActionFilter filter) => () => ControllerActionInvoker.InvokeActionMethodFilter(filter, preContext, next))();
  9. 9 }
View Code

看到这里我直接懵逼了,由于它委托中嵌套了委托而且还简写,还调用了扩展方法Aggregate累加器,所以很难直接看懂,这到底是怎么执行代码的呐?我来把代码整理如下 

  1. 1 public class Class1
  2. 2 {
  3. 3
  4. 4 protected virtual ActionExecutedContext InvokeActionMethodWithFilters(ControllerContext controllerContext, IList<IActionFilter> filters, ActionDescriptor actionDescriptor, IDictionary<string, object> parameters)
  5. 5 {
  6. 6 ActionExecutingContext preContext = new ActionExecutingContext(controllerContext, actionDescriptor, parameters);
  7. 7
  8. 8 Func<ActionExecutedContext> seed = () => new ActionExecutedContext(controllerContext, actionDescriptor, false, null)
  9. 9 {
  10. 10 Result = this.InvokeActionMethod(controllerContext, actionDescriptor, parameters)
  11. 11 };
  12. 12
  13. 13 Func<Func<ActionExecutedContext>, IActionFilter, Func<ActionExecutedContext>> secondParam =
  14. 14 (Func<ActionExecutedContext> next, IActionFilter filter) =>
  15. 15 {
  16. 16 Func<ActionExecutedContext> returnFunc = () =>
  17. 17 {
  18. 18 return Class1.InvokeActionMethodFilter(filter, preContext, next);
  19. 19 };
  20. 20
  21. 21 return returnFunc;
  22. 22
  23. 23 //这个是简写
  24. 24 //return () => Class1.InvokeActionMethodFilter(filter, preContext, next);
  25. 25 };
  26. 26
  27. 27 return filters.Reverse<IActionFilter>().Aggregate(seed,
  28. 28 //(Func<ActionExecutedContext> next, IActionFilter filter) => () => Class1.InvokeActionMethodFilter(filter, preContext, next)
  29. 29 secondParam
  30. 30 )
  31. 31 .Invoke();
  32. 32 }
  33. 33
  34. 34 internal static ActionExecutedContext InvokeActionMethodFilter(IActionFilter filter, ActionExecutingContext preContext, Func<ActionExecutedContext> continuation)
  35. 35 {
  36. 36 filter.OnActionExecuting(preContext);
  37. 37 if (preContext.Result != null)
  38. 38 {
  39. 39 return new ActionExecutedContext(preContext, preContext.ActionDescriptor, true, null)
  40. 40 {
  41. 41 Result = preContext.Result
  42. 42 };
  43. 43 }
  44. 44 bool flag = false;
  45. 45 ActionExecutedContext actionExecutedContext = null;
  46. 46 try
  47. 47 {
  48. 48 actionExecutedContext = continuation();
  49. 49 }
  50. 50 catch (ThreadAbortException)
  51. 51 {
  52. 52 actionExecutedContext = new ActionExecutedContext(preContext, preContext.ActionDescriptor, false, null);
  53. 53 filter.OnActionExecuted(actionExecutedContext);
  54. 54 throw;
  55. 55 }
  56. 56 catch (Exception exception)
  57. 57 {
  58. 58 flag = true;
  59. 59 actionExecutedContext = new ActionExecutedContext(preContext, preContext.ActionDescriptor, false, exception);
  60. 60 filter.OnActionExecuted(actionExecutedContext);
  61. 61 if (!actionExecutedContext.ExceptionHandled)
  62. 62 {
  63. 63 throw;
  64. 64 }
  65. 65 }
  66. 66 if (!flag)
  67. 67 {
  68. 68 filter.OnActionExecuted(actionExecutedContext);
  69. 69 }
  70. 70 return actionExecutedContext;
  71. 71 }
  72. 72
  73. 73 protected virtual ActionResult InvokeActionMethod(ControllerContext controllerContext, ActionDescriptor actionDescriptor, IDictionary<string, object> parameters)
  74. 74 {
  75. 75 object actionReturnValue = actionDescriptor.Execute(controllerContext, parameters);
  76. 76 return this.CreateActionResult(controllerContext, actionDescriptor, actionReturnValue);
  77. 77 }
  78. 78
  79. 79 protected virtual ActionResult CreateActionResult(ControllerContext controllerContext, ActionDescriptor actionDescriptor, object actionReturnValue)
  80. 80 {
  81. 81 if (actionReturnValue == null)
  82. 82 {
  83. 83 return new EmptyResult();
  84. 84 }
  85. 85 ActionResult arg_29_0;
  86. 86 if ((arg_29_0 = (actionReturnValue as ActionResult)) == null)
  87. 87 {
  88. 88 arg_29_0 = new ContentResult();
  89. 89 //(arg_29_0 = new ContentResult()).Content = Convert.ToString(actionReturnValue, CultureInfo.InvariantCulture);
  90. 90 (arg_29_0 as ContentResult).Content = Convert.ToString(actionReturnValue, CultureInfo.InvariantCulture);
  91. 91 }
  92. 92 return arg_29_0;
  93. 93 }
  94. 94
  95. 95 }
View Code

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

首先,我们先要知道 Aggregate 这个扩展方法是怎么执行的,直接看源码如下 

 

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

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

  1. 1 public class Class2
  2. 2 {
  3. 3
  4. 4 public void Test()
  5. 5 {
  6. 6 var preContext = new ActionExecutingContext();
  7. 7
  8. 8 Func<ActionExecutedContext> seed = () =>
  9. 9 {
  10. 10 Console.WriteLine("执行action");
  11. 11 return new ActionExecutedContext();
  12. 12 };
  13. 13
  14. 14 int[] arr = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
  15. 15
  16. 16 Func<Func<ActionExecutedContext>, int, Func<ActionExecutedContext>> secondParam =
  17. 17 (Func<ActionExecutedContext> next, int filter) =>
  18. 18 {
  19. 19 return () => this.getStr(next, filter, preContext);
  20. 20 };
  21. 21
  22. 22 var reFunc2 = arr.Reverse().Aggregate<int, Func<ActionExecutedContext>>(seed, secondParam);
  23. 23 reFunc2.Invoke();
  24. 24
  25. 25 }
  26. 26
  27. 27 public ActionExecutedContext getStr(Func<ActionExecutedContext> func, int filter, ActionExecutingContext preContext)
  28. 28 {
  29. 29
  30. 30 Console.WriteLine("before action----" + filter + "----" + preContext.ToString());
  31. 31
  32. 32 var res = func.Invoke();
  33. 33
  34. 34 Console.WriteLine("before action----" + filter + "----" + res.ToString());
  35. 35
  36. 36 return res;
  37. 37 }
  38. 38
  39. 39 }
View Code

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

运行结果为 如图

 

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

 

原文链接:http://www.cnblogs.com/xiaoZhang521/p/11269677.html

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号