的篇章, 解析了 Action 方法的查找, 以及 Authorize, Action, Result, Error 过滤器的加载时机. 也花了两篇去看授权和错误过滤器的使用. 但是对于 Action/Result 的执行以及 Action/Result 里面的两个过滤器的执行时机, 并没有清晰看到.
一、Action 方法的执行和过滤器的执行
- //System.web.Mvc.ControllerActionInvoker
- protected virtual ActionExecutedContext InvokeActionMethodWithFilters(ControllerContext controllerContext,
- IList filters, ActionDescriptor actionDescriptor, IDictionary<string, object> parameters)
- {
- ActionExecutingContext preContext = new ActionExecutingContext(controllerContext, actionDescriptor, parameters);
- //这里定义了一个Func委托, 返回值为 ActionExecutedContext 类型
- //在返回的 ActionExecutedContext 类型实例中, 对 Result 指定了执行方法
- //这里其实都是在指定待执行的方法, 在它执行完毕后, 并没有任何的方法被执行. 以下标红的部分, 就是执行 Action 方法
- Func seed = () => new ActionExecutedContext(controllerContext, actionDescriptor, false, null)
- { Result = this.InvokeActionMethod(controllerContext, actionDescriptor, parameters) };
- return filters
- //filters变量是一个以controller为首元素的List<IActionFilter>集合,这里的目的就是要反转集合, 变成
- // IActionFilter->Controller
- .Reverse()
- //聚合函数, 这里的 next 其实就是 seed 对象
- //filter 是 IEnumberable 中的元素
- //这里的效果, 就是返回累加后的 seed 对象
- .Aggregate>(seed,
- (next, filter) => () => InvokeActionMethodFilter(filter, preContext, next))
- (); //这一步执行方法
- }
这里的代码就是 的 3.4, 只是我对他进行了分割, 这样容易看懂点
这里有一个 Aggregate<>() 可能不是那么好理解, 先上一个 demo, 应该是能够促进理解的.
- var numbers = new int[] {
- 1,
- 3,
- 9,
- 2
- };
- // 使用当前总值乘以下一个数值得到新的总值
- var product = numbers.Aggregate((total, next) = >total * next);最后的值是: 1 X 3 X 9 X 2 = 54。
这里的执行过程是这样的:
1). 当第一次执行 Aggregate() 的时候, 匿名方法 (next, filter) 中的 next 就是 seed 对象, filter 就是 ActionFilter 对象. 他将 InvokeActionMethodFilter(filter, preContext, next)作为返回值, 并作为下一次执行 (next, filter) 中的 next 参数
2). 第二次执行 (next, filter) 的时候, next 参数的值是 InvokeActionMethodFilter(filter, preContext, next) , filter 是 Controller, 最终将
InvokeActionMethodFilter(filter, preContext, next) 最为结果返回给 filters 变量.
整个执行表达式为 : filters = InvokeActionMethodFilter(controller, preContext, InvokeActionMethodFilter(ActionFilter, preContext, seed));
经过上述步骤后, filters 形成了一个链表, 其最先执行的还是 Controller.
1. InvokeActionMethodFilter
- internal static ActionExecutedContext InvokeActionMethodFilter(IActionFilter filter,
- ActionExecutingContext preContext, Func continuation)
- {
- //这一步执行 ActionExecuting 过滤器
- filter.OnActionExecuting(preContext);
- if (preContext.Result != null)
- {
- //当不能通过过滤器的时候, 会走这里
- return new ActionExecutedContext(preContext, preContext.ActionDescriptor, true, null)
- { Result = preContext.Result };
- }
- bool flag = false;
- ActionExecutedContext filterContext = null;
- try
- {
- //1.第一次执行这一步,会跳转到 InvokeActionFilter(filter, preContext, next)中去执行
- //2.第二次运行到这里的时候,会去执行 上面的 seed 方法
- //在执行seed方法的时候, 就回去运行 InvokeActionMethod() 方法
- filterContext = continuation();
- }
- catch (ThreadAbortException)
- {
- filterContext = new ActionExecutedContext(preContext, preContext.ActionDescriptor, false, null);
- filter.OnActionExecuted(filterContext);
- throw;
- }
- catch (Exception exception)
- {
- flag = true;
- filterContext = new ActionExecutedContext(preContext, preContext.ActionDescriptor, false, exception);
- filter.OnActionExecuted(filterContext);
- if (!filterContext.ExceptionHandled)
- {
- throw;
- }
- }
- if (!flag)
- {
- filter.OnActionExecuted(filterContext);
- }
- return filterContext;
- }
在这里, 已经能看到 ActionExecuting 和 ActionExecuted 两个过滤器的执行时机了
根据上面的注释, 然后看一下 InvokeActionMethod 方法
- protected virtual ActionResult InvokeActionMethod(ControllerContext controllerContext,
- ActionDescriptor actionDescriptor, IDictionary<string, object> parameters)
- {
- object actionReturnValue = actionDescriptor.Execute(controllerContext, parameters);
- return this.CreateActionResult(controllerContext, actionDescriptor, actionReturnValue);
- }
这里的 Execute 方法, 返回的就是 ActionResult 了, 调用 CreateActionResult 是为了进行类型转换, 将返回的 actionReturnValue 转换为 ActionResult 类型.
这里其实就是执行的 Action 方法. 并返回执行结果.
二、Result 的执行和过滤器的执行
- //ControllerActionInvoker
- protected virtual ResultExecutedContext InvokeActionResultWithFilters(ControllerContext controllerContext,
- IList filters, ActionResult actionResult)
- {
- ResultExecutingContext preContext = new ResultExecutingContext(controllerContext, actionResult);
- Func seed = delegate {
- this.InvokeActionResult(controllerContext, actionResult);
- return new ResultExecutedContext(controllerContext, actionResult, false, null);
- };
- return filters
- .Reverse()
- .Aggregate>(seed,
- (next, filter) => () => InvokeActionResultFilter(filter, preContext, next))
- ();
- }
看这里方法的结构和上面 Action 那里差不多. 并且注意到这里的返回值: ResultExecutedContext, 返回的就是执行完 View 的结果.
先看一下 InvokeActionResultFilter 方法
1. InvokeActionResultFilter
- internal static ResultExecutedContext InvokeActionResultFilter(IResultFilter filter,
- ResultExecutingContext preContext, Func continuation)
- {
- filter.OnResultExecuting(preContext);
- if (preContext.Cancel)
- {
- return new ResultExecutedContext(preContext, preContext.Result, true, null);
- }
- bool flag = false;
- ResultExecutedContext filterContext = null;
- try
- {
- filterContext = continuation();
- }
- catch (ThreadAbortException)
- {
- filterContext = new ResultExecutedContext(preContext, preContext.Result, false, null);
- filter.OnResultExecuted(filterContext);
- throw;
- }
- catch (Exception exception)
- {
- flag = true;
- filterContext = new ResultExecutedContext(preContext, preContext.Result, false, exception);
- filter.OnResultExecuted(filterContext);
- if (!filterContext.ExceptionHandled)
- {
- throw;
- }
- }
- if (!flag)
- {
- filter.OnResultExecuted(filterContext);
- }
- return filterContext;
- }
内部方法的执行顺序都是一样的. 从这个方法能看出, Result 过滤器的执行顺序, 确实如前面提到的那样. 先执行 Executing , 再执行 Result, 最后执行 Executed 方法.
2. InvokeActionResult
- protected virtual void InvokeActionResult(ControllerContext controllerContext, ActionResult actionResult)
- {
- actionResult.ExecuteResult(controllerContext);
- }
这一步, 就是执行 View 了, 具体的执行过程有机会的话, 就在后面解析了.
这一篇主要是验证, Action/Result 的四个过滤器的执行顺序是否如前面描述的那样子. 当然, 在探寻的过程中, 顺便也看到了 Action/Result 方法的执行时机.
这里其实还有一个问题, 从上面看, 把 Controller 排序到最前面执行了, 那么如果我是在 FilterConfig 中注册的呢? Action 方法上标注的呢? Controller 类上面标注的呢? 是一个什么顺序
下一篇就去看一下, 这里的顺序, 也能辅助理解这一篇的内容.
参考:
来源: