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 ...
随机推荐
- Gradle Wrapper简述
个人博客:http://www.enjoytoday.cn Gradle更多介绍参考:http://www.enjoytoday.cn/categorys/Gradle 案例源码:GitHub gra ...
- python3基础学习(1)
python基础内容讲解主要内容: 1.使用编辑器(IDE) 2.第一个“hello world” 3.何所谓“变量” 4.python与其他主流语言输出对比 5.数据类型 6.python用作“计算 ...
- vs code切换中英文界面
1. 在vs code的应用扩展中搜索这个插件: Chinese (Simplified) Language Pack for Visual Studio Code 这个插件,安装完毕重新加载即可生效 ...
- PHP转Go系列:字符串
字符串的赋值 在PHP中,字符串的赋值虽然只有一行,其实包含了两步,一是声明变量,二是赋值给变量,同一个变量可以任意重新赋值. $str = 'Hello World!'; $str = 'hia'; ...
- LVM 在线扩容磁盘(ubuntu 14.04 server)
mware workstation 8 或者 vmware vsphere client 6.0( exsi 6.0) (前提:你的服务器需要有已经存在的卷组,才可以添加新的物理卷到卷组,然后再扩容逻 ...
- Flask Rest接口
Flask适用于简单的接口请求 安装 pip install Flask pip install Flask-RESTful 仅简单请求url,然后出发处理程序,返回处理结果 app.py代码如下 f ...
- Java JDK 运行环境安装
1 Windows系统 1.1 安装包准备 安装包本文档讲解为64位系统,如果是32位系统需要下载32位系统安装包 1.1.1 下载方式 打开jdk官方下载地址,该文档提供jdk版本为1.8 http ...
- envoy的配置文件的样子
yaml文件 admin: access_log_path: /tmp/admin_access.log address: socket_address: protocol: TCP address: ...
- JDOJ3011 铺地板III
JDOJ3011 铺地板III https://neooj.com/oldoj/problem.php?id=3011 题目描述 有3 x N (0 <= N <= 105)的网格,需要用 ...
- nextjs作为koa中间件的使用
react客户端渲染的缺点:首屏速度慢,对SEO不友好 浏览器请求步骤 客户端跳转 1. ...