当前位置:编程学习 > asp >>

Asp.net MVC源码分析--Action Filter的链式调用

 

上一篇中我们介绍了asp.net MVC 的Filter的种类,以及调用的时点.今天我们来看一下ActionFilter/ResultFilter 调用的细节以及源码中令人叫绝的代码实现.首先我们看到在Contoller这个类中已经实现了IActionFilter/IResultFilter,并且它们的接口实现是调用两个虚函数来实现的,这就为我们提供了便利,可以在我们的Controller中重写这些虚函数来截获并实现我们自己的逻辑.

Controller.cs

 

 1   protected virtual void OnActionExecuting(ActionExecutingContext filterContext) {

 2         }

 3

 4         protected virtual void OnActionExecuted(ActionExecutedContext filterContext) {

 5         }

 6

 7         protected virtual void OnAuthorization(AuthorizationContext filterContext) {

 8         }

 9

10         protected virtual void OnException(ExceptionContext filterContext) {

11         }

12

13         protected virtual void OnResultExecuted(ResultExecutedContext filterContext) {

14         }

15

16         protected virtual void OnResultExecuting(ResultExecutingContext filterContext) {

17         }

18

19

20  #region IActionFilter Members

21         void IActionFilter.OnActionExecuting(ActionExecutingContext filterContext) {

22             OnActionExecuting(filterContext);

23         }

24

25         void IActionFilter.OnActionExecuted(ActionExecutedContext filterContext) {

26             OnActionExecuted(filterContext);

27         }

28         #endregion

29

30    #region IResultFilter Members

31         void IResultFilter.OnResultExecuting(ResultExecutingContext filterContext) {

32             OnResultExecuting(filterContext);

33         }

34

35         void IResultFilter.OnResultExecuted(ResultExecutedContext filterContext) {

36             OnResultExecuted(filterContext);

37         }

38         #endregion

但是我们如何来获取这个由Controller类实现的Filter接口呢?请看ControllerInstanceFilterProvider,这个已经默认注册的Filter Provider可以得到这些Filter的接口实现.

ControllerInstanceFilterProvider.cs

 

1  public class ControllerInstanceFilterProvider : IFilterProvider {

2         public IEnumerable<Filter> GetFilters(ControllerContext controllerContext, ActionDescriptor actionDescriptor) {

3             if (controllerContext.Controller != null) {

4                 // Use FilterScope.First and Order of Int32.MinValue to ensure controller instance methods always run first

5                 yield return new Filter(controllerContext.Controller, FilterScope.First, Int32.MinValue);

6             }

7         }

8     }

---------------------------------------------------------------------------------------------

但是请大家考虑一个问题,如果我们在Action 上也同时标记了Action Filter的时候会产生一次调用需要调用两个或多个Action filter的时候MVC 怎么处理这样的情况呢? 请看在ControllerActionInvoker.InvokeAction方法中的InvokeActionMethodWithFilters 方法.  我们今天的主角登场了,嘿嘿.

ControllerActionInvoker.cs

 

 1    protected virtual ActionExecutedContext InvokeActionMethodWithFilters(ControllerContext controllerContext, IList<IActionFilter> filters, ActionDescriptor actionDescriptor, IDictionary<string, object> parameters) {

 2             ActionExecutingContext preContext = new ActionExecutingContext(controllerContext, actionDescriptor, parameters);

 3             Func<ActionExecutedContext> continuation = () =>

 4                 new ActionExecutedContext(controllerContext, actionDescriptor, false /* canceled */, null /* exception */) {

 5                     Result = InvokeActionMethod(controllerContext, actionDescriptor, parameters)

 6                 };

 7

 8             // need to reverse the filter list because the continuations are built up backward

 9             Func<ActionExecutedContext> thunk = filters.Reverse().Aggregate(continuation,

10                 (next, filter) => () => InvokeActionMethodFilter(filter, preContext, next));

11             return thunk();

12         }

首先我们看到代码中声明了Func<ActionExecutedContext> continuation, 的这样一个委托, 注意这里只是声明还没有调用哦.这个委托是用来调用Action方法的. 接下来又声明了Func<ActionExecutedContext> thunk 这样一个委托, 这个委托的内容是用filters.Aggregate 方法来合并我们的Filter执行链,(这里不理解的话,我们需要看Aggregate 方法的说明). InvokeActionMethodFilter的方法是执行IActionFilter中的接口实现.

InvokeActionMethodFilter方法

 

 1  internal static ActionExecutedContext InvokeActionMethodFilter(IActionFilter filter, ActionExecutingContext preContext, Func<ActionExecutedContext> continuation) {

 2             filter.OnActionExecuting(preContext);

 3             if (preContext.Result != null) {

 4                 return new ActionExecutedContext(preContext, preContext.ActionDescriptor, true /* canceled */, null /* exception */) {

 5              &nb

补充:Web开发 , ASP.Net ,
CopyRight © 2022 站长资源库 编程知识问答 zzzyk.com All Rights Reserved
部分文章来自网络,