看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过滤器俄罗斯套娃的实现方式的更多相关文章

  1. Spring MVC中forward请求转发2种方式(带参数)

    Spring MVC中forward请求转发2种方式(带参数) http://www.51gjie.com/javaweb/956.html  

  2. .NET MVC中登录过滤器拦截的两种方法

    今天给大家介绍两种ASP中过滤器拦截的两种方法. 一种是EF 的HtppModule,另一种则是灵活很多针对MVC的特性类 Attribute 具体什么是特性类可以参考着篇文章:https://www ...

  3. MVC中处理表单提交的方式(Ajax+Jquery)

    MVC中处理表单有很多种方法,这里说到第一种方式:Ajax+Jquery 先看下表单: <form class="row form-body form-horizontal m-t&q ...

  4. MVC中的过滤器

    authour: chenboyi updatetime: 2015-05-09 09:30:30 friendly link:   目录: 1,思维导图   2,过滤器种类(图示) 3,全局过滤器 ...

  5. MVC中的过滤器/拦截器怎么写

    创建一个AuthenticateFilterAttribute(即过滤器/拦截器) 引用System.Web.Mvc; public class AuthenticateFilterAttribute ...

  6. ASP.NET MVC 中的过滤器

    这里用实例说明各种过滤器的用法,有不对的地方还请大神指出,共同探讨. 1. ActionFilter 方法过滤器: 接口名为 IActionFilter ,在控制器方法调用前/后执行. 在新建的MVC ...

  7. MVC中CheckBoxList的3种实现方式

    比如,当为一个用户设置角色的时候,角色通常以CheckBoxList的形式呈现.用户和角色是多对多关系: using System.Collections.Generic; using System. ...

  8. ASP.NET MVC教程四:ASP.NET MVC中页面传值的几种方式

    准备 在Models文件夹里面新添加Student实体类,用来模拟从Controller向View传递数据,Student类定义如下: using System; using System.Colle ...

  9. MVC中使用过滤器记录异常日志

    using System; using System.Collections.Generic; using System.Linq; using System.Web; namespace Filte ...

随机推荐

  1. Tasteless challenges medium WP

    http://chall.tasteless.eu/ 国外的一个靶场,都是单点知识,medium大部分还是比较简单 medium Level 1- Infiltration http://chall. ...

  2. 企业账号发布APP

    做了一个公司内部人使用的项目,公司申请了企业开发者账号.现将企业开发者账号发布app的过成总结如下: 1.生成Certificate Signing Request (CSR)文件 2.2 请求Cer ...

  3. [PHP] 运维新增服务器导致的附件上传失败问题

    现象:客服反馈webmail发信上传附件时,报错提示上传失败,发信时提示发送失败前因:运维同事新增加了三台服务器 1.服务器上有一个挂载的公共目录,该目录是存储的上传后的附件文件.该路径是通过一个软链 ...

  4. 渗透测试学习 十八、 XSS跨站脚本漏洞详解 续

    XSS平台搭建 ISS+zkeysphp 首先在IIS中新建一个网站,详细过程可以看我之前写搭环境的文章 (下面的写入选项不需要选中) 安装ZKEYS PHP 修改数据库配置 用户名:root 密码: ...

  5. 高频Python面试题分享

    一.Python语言中你用过哪些方式来实现进程间通信1.队列Queue 2.Pipe管道 只适用于两个进程之间的通信, pipe的效率高于queue 3.共享内存 4.socket套接字(UDP即可) ...

  6. 扎西平措 201571030332 《面向对象程序设计(java)课程学习进度条》

    <2019面向对象程序设计(java)课程学习进度条> 周次 (阅读/编写)代码行数 发布博客量/评论他人博客数量 课余学习时间(小时) 学习收获最大的程序 阅读或编译让我 第一周 20/ ...

  7. IntelliJ IDEA 版本控制 GIT(四)

    1. 从GitLab或GitGitHub中检出项目 VCS - Checkout from Version Control - Git 2. 更新项目 第一种:更新当前窗口下的整个项目 第二种:更新相 ...

  8. zz自动驾驶多传感器感知的探索

    案例教学,把“问题”讲清楚了,赞 Pony.ai 在多传感器感知上积累了很多的经验,尤其是今年年初在卡车上开始了新的尝试.我们有不同的传感器配置,以及不同的场景,对多传感器融合的一些新的挑战,有了更深 ...

  9. luoguP2597 [ZJOI2012]灾难

    题意 这题思路好奇怪啊 见到有向无环图显然是要拓朴排序,不妨按照被吃向吃连边,那么\(x\)灭绝当且仅当x的入点都灭绝,于是考虑怎样x的入点都灭绝 比如4号节点,它灭绝当且仅当2和3灭绝,2和3灭绝当 ...

  10. springboot集成freemarker属性配置(不知道是针对于某个版本,2.0后有变动)

    freemarker属性配置 freemarker属性配置: spring.freemarker.allow-request-override=false # 设置是否允许HttpServletReq ...