MVC中IActionFilter过滤器俄罗斯套娃的实现方式
看mvc的源码我们知道,它是在 ControllerActionInvoker 类中执行 InvokeAction 方法来实现过滤器和action方法执行的。
通过查看源码我们知道,他是通过调用 InvokeActionMethodWithFilters 方法来实现IActionFilter过滤器和action方法执行的,如图

点进去这个方法我们可以看到
protected virtual ActionExecutedContext InvokeActionMethodWithFilters(ControllerContext controllerContext, IList<IActionFilter> filters, ActionDescriptor actionDescriptor, IDictionary<string, object> parameters)
{
ActionExecutingContext preContext = new ActionExecutingContext(controllerContext, actionDescriptor, parameters);
Func<ActionExecutedContext> seed = () => new ActionExecutedContext(controllerContext, actionDescriptor, false, null)
{
Result = this.InvokeActionMethod(controllerContext, actionDescriptor, parameters)
};
return filters.Reverse<IActionFilter>().Aggregate(seed, (Func<ActionExecutedContext> next, IActionFilter filter) => () => ControllerActionInvoker.InvokeActionMethodFilter(filter, preContext, next))();
}
看到这里我直接懵逼了,由于它委托中嵌套了委托而且还简写,还调用了扩展方法Aggregate累加器,所以很难直接看懂,这到底是怎么执行代码的呐?我来把代码整理如下
public class Class1
{ protected virtual ActionExecutedContext InvokeActionMethodWithFilters(ControllerContext controllerContext, IList<IActionFilter> filters, ActionDescriptor actionDescriptor, IDictionary<string, object> parameters)
{
ActionExecutingContext preContext = new ActionExecutingContext(controllerContext, actionDescriptor, parameters); Func<ActionExecutedContext> seed = () => new ActionExecutedContext(controllerContext, actionDescriptor, false, null)
{
Result = this.InvokeActionMethod(controllerContext, actionDescriptor, parameters)
}; Func<Func<ActionExecutedContext>, IActionFilter, Func<ActionExecutedContext>> secondParam =
(Func<ActionExecutedContext> next, IActionFilter filter) =>
{
Func<ActionExecutedContext> returnFunc = () =>
{
return Class1.InvokeActionMethodFilter(filter, preContext, next);
}; return returnFunc; //这个是简写
//return () => Class1.InvokeActionMethodFilter(filter, preContext, next);
}; return filters.Reverse<IActionFilter>().Aggregate(seed,
//(Func<ActionExecutedContext> next, IActionFilter filter) => () => Class1.InvokeActionMethodFilter(filter, preContext, next)
secondParam
)
.Invoke();
} internal static ActionExecutedContext InvokeActionMethodFilter(IActionFilter filter, ActionExecutingContext preContext, Func<ActionExecutedContext> continuation)
{
filter.OnActionExecuting(preContext);
if (preContext.Result != null)
{
return new ActionExecutedContext(preContext, preContext.ActionDescriptor, true, null)
{
Result = preContext.Result
};
}
bool flag = false;
ActionExecutedContext actionExecutedContext = null;
try
{
actionExecutedContext = continuation();
}
catch (ThreadAbortException)
{
actionExecutedContext = new ActionExecutedContext(preContext, preContext.ActionDescriptor, false, null);
filter.OnActionExecuted(actionExecutedContext);
throw;
}
catch (Exception exception)
{
flag = true;
actionExecutedContext = new ActionExecutedContext(preContext, preContext.ActionDescriptor, false, exception);
filter.OnActionExecuted(actionExecutedContext);
if (!actionExecutedContext.ExceptionHandled)
{
throw;
}
}
if (!flag)
{
filter.OnActionExecuted(actionExecutedContext);
}
return actionExecutedContext;
} protected virtual ActionResult InvokeActionMethod(ControllerContext controllerContext, ActionDescriptor actionDescriptor, IDictionary<string, object> parameters)
{
object actionReturnValue = actionDescriptor.Execute(controllerContext, parameters);
return this.CreateActionResult(controllerContext, actionDescriptor, actionReturnValue);
} protected virtual ActionResult CreateActionResult(ControllerContext controllerContext, ActionDescriptor actionDescriptor, object actionReturnValue)
{
if (actionReturnValue == null)
{
return new EmptyResult();
}
ActionResult arg_29_0;
if ((arg_29_0 = (actionReturnValue as ActionResult)) == null)
{
arg_29_0 = new ContentResult();
//(arg_29_0 = new ContentResult()).Content = Convert.ToString(actionReturnValue, CultureInfo.InvariantCulture);
(arg_29_0 as ContentResult).Content = Convert.ToString(actionReturnValue, CultureInfo.InvariantCulture);
}
return arg_29_0;
} }
咋一看,还是不知所云,一步一步来,
首先,我们先要知道 Aggregate 这个扩展方法是怎么执行的,直接看源码如下

看了源码就很容易理解了,它就是遍历数据源来循环执行传递过来的委托,并把结果当成参数,执行下一次循环的委托。
所有我整理了一个容易理解的一串代码
public class Class2
{ public void Test()
{
var preContext = new ActionExecutingContext(); Func<ActionExecutedContext> seed = () =>
{
Console.WriteLine("执行action");
return new ActionExecutedContext();
}; int[] arr = { , , , , , , , , }; Func<Func<ActionExecutedContext>, int, Func<ActionExecutedContext>> secondParam =
(Func<ActionExecutedContext> next, int filter) =>
{
return () => this.getStr(next, filter, preContext);
}; var reFunc2 = arr.Reverse().Aggregate<int, Func<ActionExecutedContext>>(seed, secondParam);
reFunc2.Invoke(); } public ActionExecutedContext getStr(Func<ActionExecutedContext> func, int filter, ActionExecutingContext preContext)
{ Console.WriteLine("before action----" + filter + "----" + preContext.ToString()); var res = func.Invoke(); Console.WriteLine("before action----" + filter + "----" + res.ToString()); return res;
} }
我是用一个int数组来模拟IActionFilter集合,其它的写法都和mvc框架的写法一样。
运行结果为 如图

看到这里,你是否明白了,它就是通过 委托里嵌套委托 来巧妙的实现了俄罗斯套娃的形式来实现IActionFilter过滤器和Action方法的执行。
MVC中IActionFilter过滤器俄罗斯套娃的实现方式的更多相关文章
- Spring MVC中forward请求转发2种方式(带参数)
Spring MVC中forward请求转发2种方式(带参数) http://www.51gjie.com/javaweb/956.html
- .NET MVC中登录过滤器拦截的两种方法
今天给大家介绍两种ASP中过滤器拦截的两种方法. 一种是EF 的HtppModule,另一种则是灵活很多针对MVC的特性类 Attribute 具体什么是特性类可以参考着篇文章:https://www ...
- MVC中处理表单提交的方式(Ajax+Jquery)
MVC中处理表单有很多种方法,这里说到第一种方式:Ajax+Jquery 先看下表单: <form class="row form-body form-horizontal m-t&q ...
- MVC中的过滤器
authour: chenboyi updatetime: 2015-05-09 09:30:30 friendly link: 目录: 1,思维导图 2,过滤器种类(图示) 3,全局过滤器 ...
- MVC中的过滤器/拦截器怎么写
创建一个AuthenticateFilterAttribute(即过滤器/拦截器) 引用System.Web.Mvc; public class AuthenticateFilterAttribute ...
- ASP.NET MVC 中的过滤器
这里用实例说明各种过滤器的用法,有不对的地方还请大神指出,共同探讨. 1. ActionFilter 方法过滤器: 接口名为 IActionFilter ,在控制器方法调用前/后执行. 在新建的MVC ...
- MVC中CheckBoxList的3种实现方式
比如,当为一个用户设置角色的时候,角色通常以CheckBoxList的形式呈现.用户和角色是多对多关系: using System.Collections.Generic; using System. ...
- ASP.NET MVC教程四:ASP.NET MVC中页面传值的几种方式
准备 在Models文件夹里面新添加Student实体类,用来模拟从Controller向View传递数据,Student类定义如下: using System; using System.Colle ...
- MVC中使用过滤器记录异常日志
using System; using System.Collections.Generic; using System.Linq; using System.Web; namespace Filte ...
随机推荐
- whistle手机调试工具使用简单教程
npm全局安装 npm install -g whistle 全局启动 w2 start 启动之后,输入127.0.0.1:8899 就可以访问到whistle调试界面了: 我们主要常用几个功能: 1 ...
- 版本管理·玩转git(日志查看与版本切换)
如果你想更清晰地学习git,你必须要了解3个重要区域. 工作区:即开发者的工作目录 暂存区:修改已被记录,但尚未录入版本库的区域 版本库:存储变化日志及版本信息 当你在工作区进行开发工作时,git会记 ...
- 如何使用 CODING 进行瀑布流式研发
你好,欢迎使用CODING!这份最佳实践将帮助你通过 CODING 更好地实践瀑布流式开发流程. 什么是瀑布流式研发 1970 年温斯顿·罗伊斯(Winston Royce)提出了著名的"瀑 ...
- hive的metatable学习
一.存储Hive版本的元数据表(VERSION)   二.Hive数据库相关的元数据表(DBS.DATABASE_PARAMS) DBS --存储Hive中所有数据库的基本信息   DATAB ...
- 字符串和id的转换方法
在项目中经常会遇到一个需求就是字符串和id的转换,比如标签和标签id.因为在存储系统里面存储字符串会比较浪费内存,而存储id会节省内存和提高效率. 问题分解 通过字符串获得id 通过id获得字符串 实 ...
- JavaScript—数据可视化(ECharts)
Echarts具有丰富的图表,可以说是数据可视化的神器: 1.下载Echarts 官网下载地址:https://echarts.baidu.com/index.html 2.Echarts引用案例—柱 ...
- Linux—各种重要配置文件详解
一./etc/profile文件详解(环境变量) 添加环境变量 .编辑profile文件 [root@localhost ~]# vi /etc/profile .在profile文件中添加如下内容 ...
- Mysql—事务原理与详解
事务的四大特性 事务的隔离级别 https://www.cnblogs.com/57rongjielong/p/8036418.html https://blog.csdn.net/zwq123211 ...
- win7个性化不能换界面:此页面上的一个或多个设置已被系统管理员禁用,关机里的切换用户和锁定为灰色
win7个性化不能换界面:此页面上的一个或多个设置已被系统管理员禁用,关机里的切换用户和锁定为灰色 找到注册表 cmd-regedit HKEY_CURRENT_USER\Software\Micro ...
- 05justify-content
display: flex; 的默认轴是x轴 justify-content: 设置主轴上的子元素排列的方式 所以在使用之前要确定好哪一个是主轴 /* justify-content:flex-sta ...