• 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方法的执行。

  • 相关阅读:
    使用Python创建简单的HTTP和FTP服务
    Xps实现文档显示、套打功能
    时间测试
    微信公众账号 开发教程
    竞赛快速及常用(后续更新)
    第十届蓝桥杯JavaC组省赛真题
    第十届蓝桥杯JavaC组省赛真题
    第十届蓝桥杯JavaC组省赛真题
    C# Winform学习(六)
    C# Winform学习(六)
  • 原文地址:https://www.cnblogs.com/xiaoZhang521/p/11269677.html
Copyright © 2020-2023  润新知