Welcome 微信登录

首页 / 网页编程 / ASP.NET / MVC中ControllerActionInvoker类的InvokeActionMethodWithFilters详解

MVC中ControllerActionInvoker类的InvokeActionMethodWithFilters详解2011-08-15 博客园 情三首先呢,你得先掌握Linq的扩展方法Aggregate的使用,具体可以查看我转载的一篇文章[Linq] Enumerable.Aggregate

我们把Aggregate反编译出来的代码也贴一下:

public static TAccumulate Aggregate<TSource, TAccumulate>(this IEnumerable<TSource> source,
TAccumulate seed,
Func<TAccumulate, TSource, TAccumulate> func)
{
// ... 省略部分代码 ...
TAccumulate local = seed;
foreach (TSource local2 in source)
{
local = func(local, local2);
}
return local;
}

下面是InvokeActionMethodWithFilters这个方法的代码

protected virtual ActionExecutedContext InvokeActionMethodWithFilters (ControllerContext controllerContext, IList<IActionFilter> filters, ActionDescriptor actionDescriptor, IDictionary<string, object> parameters) {
ActionExecutingContext preContext = new ActionExecutingContext (controllerContext, actionDescriptor, parameters);
Func<ActionExecutedContext> continuation = () =>
new ActionExecutedContext(controllerContext, actionDescriptor, false /* canceled */, null /* exception */) {
Result = InvokeActionMethod(controllerContext, actionDescriptor, parameters)
};
// need to reverse the filter list because the continuations are built up backward
Func<ActionExecutedContext> thunk = filters.Reverse().Aggregate (continuation,
(next, filter) => () => InvokeActionMethodFilter(filter, preContext, next));
/*-----------------这里是我的注释----------------
* 我们要注意的是这里Aggregate返回的是一个Func委托,它并不执行委托,即每次都 返回() => InvokeActionMethodFilter(filter, preContext, next),只不过每次的filter,next 不一样而已.
* Linq扩展方法Aggregate在foreach循环IEnumerable<TSource>之前,已经对 next做了赋值工作,即:next=continuation;
* foreach第一个元素完之后:next其实是等同于:
* () => InvokeActionMethodFilter(
* filter, //filter参数不分析了,即是 IEnumerable<TSource>第一,二,三...个元素
* preContext,
* continuation
* ), //我们暂且叫它做next1吧
*如果还要再具体点就是:
*() => InvokeActionMethodFilter(
* filter,
* preContext,
* () =>new ActionExecutedContext (controllerContext, actionDescriptor, false , null ) { Result = InvokeActionMethod (controllerContext, actionDescriptor, parameters) };
* ), //即把continuation,替换为实际的代码
* 第二次foreach完之后:next其实是等同于:
* () => InvokeActionMethodFilter(
* filter,
* preContext,
* next1
* ),我们暂且叫它做next2吧
* 再具体点,就是
* () => InvokeActionMethodFilter(
* filter,
* preContext,
* () => InvokeActionMethodFilter (filter, preContext, continuation)
* ),即把next1替换为实际代码
* 如果还要再具体点就是:
* () => InvokeActionMethodFilter(
* filter,
* preContext,
* () => InvokeActionMethodFilter (filter, preContext, () =>new ActionExecutedContext(controllerContext, actionDescriptor, false , null ) { Result = InvokeActionMethod(controllerContext, actionDescriptor, parameters) };)
* )//即把continuation,替换为实际的代码
* //假设我们叫他做next2吧
*
* 其它的依此类推
* 我们假设只有两个元素,所以foreach只循环了两次,就返回了,所以Aggregate扩展 方法执行完后返回的其实就是next2
*
* */
return thunk();
/*接上面返回来的委托.开始执行委托.
* 首先,它调用外围的匿名函数,去调用InvokeActionMethodFilter函数
* 在InvokeActionMethodFilter函数里面.做了判断.如果我们的filter拦截器做了实 质性的拦截动作,它直接返回
* filter.OnActionExecuting(preContext);
* if (preContext.Result != null) {
* return new ActionExecutedContext(preContext, preContext.ActionDescriptor, true , null ) {
* Result = preContext.Result
* };
* }
* 否则的话.它开始调用内围的匿名函数,去调用InvokeActionMethodFilter函数
* 流程的话.则是跟第一步一样的
* 然后以此类推...
* 最终,流程完成
*
* 也就是说,我们的程序没有通过哪个filter的验证,那么它后面的filter就不用去验 证了,因为它比较低级的验证都没通过.更别谈高级验证了,就像找工作面试一样,,HR面试都没通过..更甭 谈老板面试了
*
* */
}