带你读开源—ASP.NET_MVC(九)

继续上篇的内容。
如果程序未定义Authentication和Authorization这两个过滤器,则执行InvokeActionMethodWithFilters方法以获取ActionResult,继而通过执行InvokeActionResultWithFilters方法来处理ActionResult。从名称可以猜测出,InvokeActionMethodWithFilters方法处理的是IActionFilter,而InvokeActionResultWithFilters方法处理的是IResultFilter。
我们先看InvokeActionMethodWithFilters方法,在其方法体内发现它调用了InvokeActionMethodFilter方法,跟踪进入,见代码段1,从中可以看出它的功能是:先调用OnActionExecuting方法,再执行一些preContext、postContext等乱七八糟的东东,然后调用OnActionExecuted方法。

C# code

?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
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 /* canceled */null /* exception */)
                {
                    Result = preContext.Result
                };
            }
            bool wasError = false;
            ActionExecutedContext postContext = null;
            try
            {
                postContext = continuation();
            }
            catch (ThreadAbortException)
            {
                // This type of exception occurs as a result of Response.Redirect(), but we special-case so that
                // the filters don't see this as an error.
                postContext = new ActionExecutedContext(preContext, preContext.ActionDescriptor, false /* canceled */null /* exception */);
                filter.OnActionExecuted(postContext);
                throw;
            }
            catch (Exception ex)
            {
                wasError = true;
                postContext = new ActionExecutedContext(preContext, preContext.ActionDescriptor, false /* canceled */, ex);
                filter.OnActionExecuted(postContext);
                if (!postContext.ExceptionHandled)
                {
                    throw;
                }
            }
            if (!wasError)
            {
                filter.OnActionExecuted(postContext);
            }
            return postContext;
        }

 

代码段 1

我们再看InvokeActionResultWithFilters方法的定义,发现它调用了InvokeActionResultFilterRecursive方法,继续跟踪到InvokeActionResultFilterRecursive方法的定义,见代码段2。

C# code

?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
   private ResultExecutedContext InvokeActionResultFilterRecursive(IList<IResultFilter> filters, int filterIndex, ResultExecutingContext preContext, ControllerContext controllerContext, ActionResult actionResult)
        {
            // Performance-sensitive
            // For compatbility, the following behavior must be maintained
            //   The OnResultExecuting events must fire in forward order
            //   The InvokeActionResult must then fire
            //   The OnResultExecuted events must fire in reverse order
            //   Earlier filters can process the results and exceptions from the handling of later filters
            // This is achieved by calling recursively and moving through the filter list forwards
            // If there are no more filters to recurse over, create the main result
            if (filterIndex > filters.Count - 1)
            {
                InvokeActionResult(controllerContext, actionResult);
                return new ResultExecutedContext(controllerContext, actionResult, canceled: false, exception: null);
            }
            // Otherwise process the filters recursively
            IResultFilter filter = filters[filterIndex];
            filter.OnResultExecuting(preContext);
            if (preContext.Cancel)
            {
                return new ResultExecutedContext(preContext, preContext.Result, canceled: true, exception: null);
            }
            bool wasError = false;
            ResultExecutedContext postContext = null;
            try
            {
                // Use the filters in forward direction
                int nextFilterIndex = filterIndex + 1;
                postContext = InvokeActionResultFilterRecursive(filters, nextFilterIndex, preContext, controllerContext, actionResult);
            }
            catch (ThreadAbortException)
            {
                // This type of exception occurs as a result of Response.Redirect(), but we special-case so that
                // the filters don't see this as an error.
                postContext = new ResultExecutedContext(preContext, preContext.Result, canceled: false, exception: null);
                filter.OnResultExecuted(postContext);
                throw;
            }
            catch (Exception ex)
            {
                wasError = true;
                postContext = new ResultExecutedContext(preContext, preContext.Result, canceled: false, exception: ex);
                filter.OnResultExecuted(postContext);
                if (!postContext.ExceptionHandled)
                {
                    throw;
                }
            }
            if (!wasError)
            {
                filter.OnResultExecuted(postContext);
            }
            return postContext;
        }

 

代码段 2

代码段1中的注释比较完备,可以帮助我们理解代码的用意。InvokeActionResultFilterRecursive方法是一个递归方法,根据注释以及对代码进行理解,我们可以梳理出Filter执行的条理:首先检查有没有更多的Filter,没有的话就执行ActionResult;如果还有未处理的Filter,则先执行Filter的OnResultExecuting方法,然后递归调用InvokeActionResultFilterRecursive方法自身,再调用Filter的OnResultExecuted方法。
从上面介绍的内容可以了解到过滤器执行的先后顺序。对于ActionFilter来说,OnActionExecuting在Action执行之前调用,OnActionExecuted在Action执行之后调用;对于ResultFilter而言,OnResultExecuting发生在ActionResult执行之前,OnResultExecuted发生在ActionResult执行之后。
好了,我们再回过头来看看MVC预置了哪些过滤器。在源码中找到IFilter的定义(代码段3)。

C# code

?

1
2
3
4
    public interface IFilter
    {
        bool AllowMultiple { get; }
    }

代码段 3
接着,寻找都有哪些类实现了该接口,IActionFilter、IAuthenticationFilter、IAuthorizationFilter、IExceptionFilter、IOverrideFilter、FilterTracer。擦!这些类又是接口,我们常用的ActionFilter和ResultFilter等过滤器实现了这些接口。
下面谈一下“依赖注入(DI)”,或者“控制反转(IOC)”。我们都知道在面向对象程序设计过程中,一个重要的思想是要尽量的减少对象之间的耦合关系,从而尽可能的适应变化。解除耦合的一个重要概念就是“接口”,根据“里氏替换原则”,我们要针对抽象编程。我们常说的“依赖”是指一个对象A要想实现其预定的功能,必须要其他对象B的协助,而这里的“其他对象B”应该是一个抽象,即“接口”、“抽象类”或“基类”。这样对象A依赖于一个抽象的B,而不依赖于B的实现细节,当需求发生变化时,对象A的实现不用改变,甚至对象A都不知道B的实现发生了变化,从而有效斩断了对象之间的耦合。当然,接口的实例化有很多专业的工具可以实现,例如NInject等,这些工具又称为“IOC容器”,大家可以百度一下“IOC”,网上有很多详细的介绍。

xiaotmh
  • 版权声明: 本文源自 CSDN CKAOS, 于9个月前,由整理发表,共 6265字。
  • 原文链接:点此查看原文

发表评论

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: