一、前言
之前也阅读过MVC的源码,并了解过各个模块的运行原理和执行过程,但都没有形成文章(所以也忘得特别快),总感觉分析源码是大神的工作,而且很多人觉得平时根本不需要知道这些,会用就行了。其实阅读源码是个很好的习惯,它不只停留在知道怎么用的阶段,而是让我们知道一系列的为什么,为什么这样设计,为什么这样使用...。很多朋友应该看过《asp.net x 框架揭秘》这本书,确实不错,特别是边看源码边看书,可以有不小的收获。Ok,我不是大神,我只是心血来潮想看一下源码!
二、几种常见的Filter
说到mvc里的Filter,自然会想到IAuthorizationFilter,IActionFilter,IResultFilter,IExceptionFilter,搜索一下也都知道怎么用了。其实说白了,这些接口定义了一系列方法,这些方法在请求的不同时机被执行,所谓Filter,就是让我们可以在不同时机进行拦截处理。
这里还涉及到一个特性:FilterAttribute,例如常用的AuthorizeAttribute就继承了FilterAttribute和实现了IAuthorizationFilter接口。说到Attribute,马上会关联到:运行时、反射、性能。框架会在运行过程中,通过反射获取标记属性,并执行特定的操作;至于性能问题,通常可以通过缓存来优化。
所以,我们可以做出猜测,以AuthorizeAttribute为例,msdn说它可以进行权限验证,也就是在Action执行前,框架会通过反射获取标记在Action(或Controller)上的FilterAttribute,并执行IAuthorizationFilter定义的OnAuthorization方法,在该方法内部进行权限验证。所以如果我们要在Action执行前做某些判断或处理,可以 1.定义一个Attribute继承FilterAttribute,并实现IActionFilter接口(与IAuthorizationFilter不同的是,这个时候ModelBinding已经完成);2.实现IActionFilter中的方法;3.标记在Action(或Controller上)。ok,下面就通过源码来验证这个过程。
三、源码分析
Action的执行是由ActionInvoker负责的,我们直接从这里出发。IActionInvoker定义了ActionInvoker要实现的方法,该接口定义如下:
| 1 2 3 4 | publicinterfaceIActionInvoker{    boolInvokeAction(ControllerContext controllerContext, stringactionName);} | 
ControllerActionInvoker 实现了该接口,顾名思义,它用于执行Controller 的 Action方法。它的 InvokeAction如下:
| 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 59 60 61 62 63 64 65 66 | publicvirtualboolInvokeAction(ControllerContext controllerContext, stringactionName){    ControllerDescriptor controllerDescriptor = GetControllerDescriptor(controllerContext);    ActionDescriptor actionDescriptor = FindAction(controllerContext, controllerDescriptor, actionName);    if(actionDescriptor != null)    {        //标记1        FilterInfo filterInfo = GetFilters(controllerContext, actionDescriptor);        try        {            //标记2            AuthenticationContext authenticationContext = InvokeAuthenticationFilters(controllerContext, filterInfo.AuthenticationFilters, actionDescriptor);            if(authenticationContext.Result != null)            {                InvokeActionResult(controllerContext, authenticationContext.Result);            }            else            {                IPrincipal principal = authenticationContext.Principal;                if(principal != null)                {                    Thread.CurrentPrincipal = principal;                    HttpContext.Current.User = principal;                }                //标记3                AuthorizationContext authorizationContext = InvokeAuthorizationFilters(controllerContext, filterInfo.AuthorizationFilters, actionDescriptor);                if(authorizationContext.Result != null)                {                    AuthenticationChallengeContext challengeContext =                        InvokeAuthenticationFiltersChallenge(controllerContext, filterInfo.AuthenticationFilters, actionDescriptor, authorizationContext.Result);                                              InvokeActionResult(controllerContext, challengeContext.Result ?? authorizationContext.Result);                }                else                {                    if(controllerContext.Controller.ValidateRequest)                    {                        ValidateRequest(controllerContext);                    }                    //标记4                    IDictionary<string, object> parameters = GetParameterValues(controllerContext, actionDescriptor);                    ActionExecutedContext postActionContext = InvokeActionMethodWithFilters(controllerContext, filterInfo.ActionFilters, actionDescriptor, parameters);                    //标记5                    InvokeActionResultWithFilters(controllerContext, filterInfo.ResultFilters, postActionContext.Result);                }            }        }        catch(Exception ex)        {            //标记6            ExceptionContext exceptionContext = InvokeExceptionFilters(controllerContext, filterInfo.ExceptionFilters, ex);            if(!exceptionContext.ExceptionHandled)            {                throw;            }            InvokeActionResult(controllerContext, exceptionContext.Result);        }        returntrue;    }    returnfalse;} | 
其实这里的6个标记已经印证了我们的猜测,先获取各种Filter,然后在各个时机执行它们。上面标记2-6都是InvokeXXXFilters就是具体的执行方法。
但是,到这里上面我们说到的FilterAttribute还没有出现。我们先把焦点放到标记1,GetFilters 上,它获取一个FilterInfo。GetFilters的定义如下:
| 1 2 3 4 | protectedvirtualFilterInfo GetFilters(ControllerContext controllerContext, ActionDescriptor actionDescriptor){    returnnewFilterInfo(_getFiltersThunk(controllerContext, actionDescriptor));} | 
_getFiltersThunk 是一个私有变量:
| 1 | privateFunc<ControllerContext, ActionDescriptor, IEnumerable<Filter>> _getFiltersThunk = FilterProviders.Providers.GetFilters; | 
通过定义可以看出,_getFiltersThunk 会返回一个Filter 集合(这里的Filter是一个实际的类,而上面提到的是概念性的东西,或者叫过滤器更合适),Filter 对象包装了IXXXFilter接口对象,具体是在其Instance 属性中。这里有点绕,但不影响,简单的说就是 GetFilters 方法会根据 FilterProviders.Providers.GetFilters 返回的一个IEnumerable<Filter>包装一个 FilterInfo对象。
我们先看 IEnumerable<Filter> 是如何获取的,它通过 FilterProviders.Providers.GetFilters 获得,FilterProviders 定义如下:
| 1 2 3 4 5 6 7 8 9 10 11 12 | publicstaticclassFilterProviders{    staticFilterProviders()    {        Providers = newFilterProviderCollection();        Providers.Add(GlobalFilters.Filters);        Providers.Add(newFilterAttributeFilterProvider());        Providers.Add(newControllerInstanceFilterProvider());    }    publicstaticFilterProviderCollection Providers { get; privateset; }} | 
这里可以注册自定义的FilterProvider,FilterProvider实际是实现了IFilterProvider(定义了GetFilters方法)的类。可以看到,mvc 默认已经准备两个FilterProvider。调用GetFilters实际会遍历每一个FilterProvider的GetFilters方法,以内置的FilterAttributeFilterProvider 为例,它的 GetFilters方法如下:
| 1 2 3 4 5 6 7 8 9 10 | publicvirtualIEnumerable<Filter> GetFilters(ControllerContext controllerContext, ActionDescriptor actionDescriptor){    ControllerBase controller = controllerContext.Controller;    vartypeFilters = GetControllerAttributes(controllerContext, actionDescriptor)        .Select(attr => newFilter(attr, FilterScope.Controller, null));    varmethodFilters = GetActionAttributes(controllerContext, actionDescriptor)        .Select(attr => newFilter(attr, FilterScope.Action, null));    returntypeFilters.Concat(methodFilters).ToList();} | 
这里也可以看到,Filter对象包装了具体的过滤器。其中GetControllerAttributes,实际它会调用ControllerDescriptor的 GetFilterAttribute,该方法定义如下:
| 1 2 3 4 | publicvirtualIEnumerable<FilterAttribute> GetFilterAttributes(booluseCache){    returnGetCustomAttributes(typeof(FilterAttribute), inherit: true).Cast<FilterAttribute>();} | 
ok,FilterAttribute 终于出现了!GetActionAttributes 也是类似的过程。
获取到Controller和Action的FilterAttribute,并包装成Filter集合后,就会构建一个FilterInfo对象,该对象的作用可以从其构造函数看出:
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | publicFilterInfo(IEnumerable<Filter> filters){    // evaluate the 'filters' enumerable only once since the operation can be quite expensive    varcache = filters.ToList();    varoverrides = cache.Where(f => f.Instance isIOverrideFilter);    FilterScope actionOverride = SelectLastScope<IActionFilter>(overrides);    FilterScope authenticationOverride = SelectLastScope<IAuthenticationFilter>(overrides);    FilterScope authorizationOverride = SelectLastScope<IAuthorizationFilter>(overrides);    FilterScope exceptionOverride = SelectLastScope<IExceptionFilter>(overrides);    FilterScope resultOverride = SelectLastScope<IResultFilter>(overrides);    _actionFilters.AddRange(SelectAvailable<IActionFilter>(cache, actionOverride));    _authenticationFilters.AddRange(SelectAvailable<IAuthenticationFilter>(cache, authenticationOverride));    _authorizationFilters.AddRange(SelectAvailable<IAuthorizationFilter>(cache, authorizationOverride));    _exceptionFilters.AddRange(SelectAvailable<IExceptionFilter>(cache, exceptionOverride));    _resultFilters.AddRange(SelectAvailable<IResultFilter>(cache, resultOverride));} | 
很明显,它将Filter 按照各自IXXXFilter接口进行分类。在InvokeAction方法内,就是根据这个分类,在各个时机进行相应的调用的。
四、总结
  通过一张图来简单总结一下:
| 本博客Android APP 下载 | 
|  | 
| 支持我们就给我们点打赏 | 
|  | 
| 支付宝打赏 支付宝扫一扫二维码 | 
|  | 
| 微信打赏 微信扫一扫二维码 | 
|  | 
如果想下次快速找到我,记得点下面的关注哦!
 
                    
                     
                    
                 
                    
                 
 
         
                
            
         浙公网安备 33010602011771号
浙公网安备 33010602011771号