ControllerDescriptor的认识

ControllerDescriptor类主要包含了对ASP.NET MVC中的Control的元数据的解析,在MVC的Model绑定以及数据处理过程中经常会遇到ControllerDescriptor类;

ControllerDescriptor类在ASP.NET MVC源码中是一个抽象类,它继承了IUniquelyIdentifiable接口(只包含了UniqueId属性的接口)和ICustomAttributeProvider接口(获取应用在相应参数上的特性);

ControllerDescriptor类主要有3个属性

  说明
ControllerName 获取控制器的名称。
ControllerType 获取控制器的类型。
UniqueId 在派生类中实现时,通过使用延迟初始化来获取控制器描述符的唯一 ID。

ControllerName属性是通过 ControllerType.Name获取并去掉了Controller后缀;

UniqueId属性主要是确定唯一性,在ControllerDescriptor类中通过ControllerName,ControllerType,ControllerDescriptor本身的类型进行创建(通过源码可以发现主要是通过字符串的长度+字符串已[{0}]{1}的格式叠加起来,具体的实现可以参考源码中DescriptorUtil.CreateUniqueId方法);

在ControllerDescriptor类中含有重要的方法FindAction的抽象方法,这个方法的目的为使用指定的名称和控制器上下文来查找操作方法。

ReflectedControllerDescriptor

      ReflectedControllerDescriptor类是MVC框架中继承ControllerDescriptor的实现类;ReflectedControllerDescriptor类的构造函数接收一个Controller的Type,并且在构造函数中会组件一个ActionMethodSelector只读类;

ReflectedControllerDescriptor类覆盖了抽象基类ControllerDescriptor的GetCanonicalActions,GetCustomAttributes,GetFilterAttributes,IsDefined,FindAction方法;

IsDefined方法的作用是返回一个是否为此成员定义某个自定义特性类型的一个或多个实例的布尔值;函数内部直接调用MemberInfo类的bool IsDefined(Type attributeType, bool inherit);可以通过IsDefined来进行判断是否有一个特性值作用于Controller;

GetCustomAttributes方法时获取所有的自定义特性的数组;当有特性作用于Controller时,可以通过GetCustomAttributes方法来获取这些特性;

      IsDefined方法与GetCustomAttributes方法都来源于ICustomAttributeProvider接口;

GetFilterAttributes方法实现了FilterAttribute接口的所有特性;函数的内部还是调用GetCustomAttributes方法(GetCustomAttributes方法参数Type为typeof(FilterAttribute));

GetCanonicalActions方法目的是返回控制器内所有的Action的列表,返回值为ActionDescriptor[] ;

FindAction方法时ControllerDescriptor中最重要的方法,这个方法通过ControllerContext(控制器上下文)与actionName来筛选出相应的Action,返回ActionDescriptor;在这个函数内部首先通过_selector(类型为ActionMethodSelector)类的FindActionMethod方法获取到匹配的方法元数据信息(返回值为MethodInfo),然后调用ReflectedActionDescriptor类(基类:ActionDescriptor)的构造函数;

ActionMethodSelectorBase

ActionMethodSelector类继承了ActionMethodSelectorBase基类,这个类主要的功能就是Action的筛选;

ActionMethodSelectorBase类中含有ControllerType,(类型:MethodInfo[])ActionMethods( 所有的action方法),

(类型:HashSet<MethodInfo>)StandardRouteMethods(直接路由的方法),

(类型:MethodInfo[])AliasedMethods(在MVC框架中的action的名字可以通过特性ActionNameSelectorAttributes来进行重新命名,因此这个属性是存储含有别名的方法信息),

(类型:ILookup<string, MethodInfo>)NonAliasedMethods(存储没有别名信息的action的方法信息,key action的名称);

在ActionMethodSelectorBase类中还对于所有的action方法做了缓存,存储在StandardRouteCache属性(私有)中,StandardRouteCache属性的类型为StandardRouteActionMethodCache类,对于StandardRouteActionMethodCache类很简单,有2个属性,一个是存储没有别名信息方法信息的ILookup<string, MethodInfo> NonAliasedMethods和含有别名信息的MethodInfo[] AliasedMethods;在CreateStandardRouteCache方法中创建缓存的逻辑也很简单,首先在StandardRouteMethods列表中筛选出方法中含有ActionNameSelectorAttribute的方法,然后在与StandardRouteMethods做差集获得没有别名信息的方法集合;

在ReflectedControllerDescriptor类的构造函数中会创建ActionMethodSelector类,ActionMethodSelector在构造函数中调用基类的Initialize来完成初始化,在初始化过程中首先会获取ControllerType类中的所有的公共方法,然后通过ActionMethodSelector类中的IsValidActionMethod方法来筛选出所有的action方法;并写入到StandardRouteMethods属性中;对于action的筛选方法可以通过代码看到

    protected override bool IsValidActionMethod(MethodInfo methodInfo)
    {
       return !(methodInfo.IsSpecialName ||methodInfo.GetBaseDefinition().DeclaringType.IsAssignableFrom(typeof(Controller)));
    } 

在进行FindAction方法时,直接调用了基类的FindActionMethod方法,在这个方法中首先会从缓存中的别名方法中帅选,由于别名方法列表的是数组,逐个遍历每一项,获取每一项中的继承了ActionNameSelectorAttribute类的子类列表,由于ActionNameSelectorAttribute是一个抽象类,含有 bool IsValidName(ControllerContext controllerContext, string actionName, MethodInfo methodInfo)的抽象方法;在进行别名匹配的时候调用IsValidName来进行校验;

       protected static bool IsMatchingAliasedMethod(MethodInfo method, ControllerContext controllerContext, string actionName)
       {
            // return if aliased method is opting in to this request
            // to opt in, all attributes defined on the method must return true
          ReadOnlyCollection<ActionNameSelectorAttribute> attributes = ReflectedAttributeCache.GetActionNameSelectorAttributes(method);
            // Caching count is faster for ReadOnlyCollection
          int attributeCount = attributes.Count;
            // Performance sensitive, so avoid foreach
          for (int i = 0; i < attributeCount; i++)
          {
             if (!attributes[i].IsValidName(controllerContext, actionName, method))
             {
                return false;
             }
            }
         return true;
        }

当遍历完所有的别名列表时,在进行没有别名方法列表的筛选,由于没有别名方法的列表在缓存中的存储格式为ILookup<string, MethodInfo>格式,因此直接通过key(action的名字)来进行获取;

当缓存中的所有数据都查找完成后会得到一个方法元数据的集合,然后在调用RunSelectionFilters方法进行最后的过滤,当过滤完成后如果列表中没有元素时,直接返回为空,当为一个元素时,返回当前元素,当为多个元素时,就会throw 一个AmbiguousMatchException错误;

RunSelectionFilters方法主要对结果进行筛选,

第一个是根据ActionMethodSelectorAttribute特性进行过滤,首先获取方法的ActionMethodSelectorAttribute的特性列表,如果方法没有这个MethodSelectionAttribute,如果已经方法列表中已经存在了标记有ActionMethodSelectorAttribute特性的方法时就要移除掉这个方法;

ActionMethodSelectorAttribute中含有一个抽象方法bool IsValidForRequest(ControllerContext controllerContext, MethodInfo methodInfo);

第二个是调用IsValidMethodSelector,这个方法也是调用ActionMethodSelectorAttribute的IsValidForRequest方法;

    protected static void RunSelectionFilters(ControllerContext controllerContext, List<MethodInfo> methodInfos)
        {
            // Filter depending on the selection attribute.
            // Methods with valid selection attributes override all others.
            // Methods with one or more invalid selection attributes are removed.

            bool hasValidSelectionAttributes = false;
            // loop backwards for fastest removal
            for (int i = methodInfos.Count - 1; i >= 0; i--)
            {
                MethodInfo methodInfo = methodInfos[i];
                ReadOnlyCollection<ActionMethodSelectorAttribute> attrs = ReflectedAttributeCache.GetActionMethodSelectorAttributesCollection(methodInfo);
                if (attrs.Count == 0)
                {
                    // case 1: this method does not have a MethodSelectionAttribute

                    if (hasValidSelectionAttributes)
                    {
                        // if there is already method with a valid selection attribute, remove method without one
                        methodInfos.RemoveAt(i);
                    }
                }
                else if (IsValidMethodSelector(attrs, controllerContext, methodInfo))
                {
                    // case 2: this method has MethodSelectionAttributes that are all valid

                    // if a matching action method had a selection attribute, consider it more specific than a matching action method
                    // without a selection attribute
                    if (!hasValidSelectionAttributes)
                    {
                        // when the first selection attribute is discovered, remove any items later in the list without selection attributes
                        if (i + 1 < methodInfos.Count)
                        {
                            methodInfos.RemoveFrom(i + 1);
                        }
                        hasValidSelectionAttributes = true;
                    }
                }
                else
                {
                    // case 3: this method has a method selection attribute but it is not valid

                    // remove the method since it is opting out of this request
                    methodInfos.RemoveAt(i);
                }
            }
        }

 protected static bool IsValidMethodSelector(ReadOnlyCollection<ActionMethodSelectorAttribute> attributes, ControllerContext controllerContext, MethodInfo method)
        {
            int attributeCount = attributes.Count;
            Contract.Assert(attributeCount > 0);
            for (int i = 0; i < attributeCount; i++)
            {
                if (!attributes[i].IsValidForRequest(controllerContext, method))
                {
                    return false;
                }
            }
            return true;
        }

时间: 2024-12-06 01:09:23

ControllerDescriptor的认识的相关文章

MVC 3个重要的描述对象之ControllerDescriptor

1.ControllerDescriptor 1.1 ReflectedControllerDescriptor public class HomeController : Controller { public ActionResult Index() { ReflectedControllerDescriptor controllerDescriptor = new ReflectedControllerDescriptor(typeof(HomeController)); return V

MVC4 Model ControllerDescriptor

1. ControllerDescriptor 的描述 Controller  的Action 方法有以下一些特性: 1.1 ActionNameAttribute特性  他继承自 System.Web.Mvc.ActionNameSelectorAttribute 抽象类 ActionNameSelectorAttribute  通过 其 抽象方法 IsValidName 判断指定的Action名称是否与目标Action方法相匹配.   如下代码片段: 添加了 ActionNameAttrib

半夜了我来发张图 睡觉 ControllerDescriptor 与 ActionDescriptor 之间 的 关系

ASP.NET MVC使用AuthenticationAttribute验证登录

首先,添加一个类AuthenticationAttribute,该类继承AuthorizeAttribute,如下: using System.Web; using System.Web.Mvc; namespace Zhong.Web { public class AuthenticationAttribute : AuthorizeAttribute { public override void OnAuthorization(AuthorizationContext filterConte

【转】.net MVC 生命周期

对于Asp.net MVC,我对它的生命周期还是兴趣很浓,于是提出两个问题: 一个HTTP请求从IIS移交到Asp.net运行时,Asp.net MVC是在什么时机获得了控制权并对请求进行处理呢?处理过程又是怎样的? 以IIS7中asp.net应用程序生命周期为例,下图是来自MSDN的一张HTTP请求处理过程发生事件的简图,后面我列出了一个完整的事件列表.既然Asp.net Mvc还是以Asp.net运行时为基础那么它必然要在Asp.net应用程序的生命周期中对请求进行截获.第一反应当然是去we

MVC5-9 今天讲三个Descriptor

ControllerDescriptor.ActionDescriptor.ParmaterDescriptor 看名字一脸懵逼,这是做什么的呢?可别小看它们,它们在MVC中扮演着尤为重要的角色. 思考 ,我们在MVC中可以用各种好用的预定义特性(attribute)来实现很棒的功能,例如HttpPost.HttpGet这样的特性,但是基础好的同学一定明白attribute本身不会做什么,而是我们在背后对它做了什么.背后的故事,就在这三个类里了 其实说是这三个类也不太准确,因为它们都是抽象类,而

我这么玩Web Api(二):数据验证,全局数据验证与单元测试

目录 一.模型状态 - ModelState 二.数据注解 - Data Annotations 三.自定义数据注解 四.全局数据验证 五.单元测试   一.模型状态 - ModelState 我理解的ModelState是微软在ASP.NET MVC中提出的一种新机制,它主要实现以下几个功能: 1. 保存客户端传过来的数据,如果验证不通过,把数据返回到客户端,这样可以保存用户输入,不需要重新输入. 2. 验证数据,以及保存数据对应的错误信息. 3. 微软的一种DRY(Don't Repeat

通过源码了解ASP.NET MVC 几种Filter的执行过程

一.前言 之前也阅读过MVC的源码,并了解过各个模块的运行原理和执行过程,但都没有形成文章(所以也忘得特别快),总感觉分析源码是大神的工作,而且很多人觉得平时根本不需要知道这些,会用就行了.其实阅读源码是个很好的习惯,它不只停留在知道怎么用的阶段,而是让我们知道一系列的为什么,为什么这样设计,为什么这样使用....很多朋友应该看过<asp.net x 框架揭秘>这本书,确实不错,特别是边看源码边看书,可以有不小的收获.Ok,我不是大神,我只是心血来潮想看一下源码! 二.几种常见的Filter

Lind.DDD.Authorization用户授权介绍

回到目录 Lind.DDD.Authorization是Lind.DDD框架的组成部分,之所以把它封装到框架里,原因就是它的通用性,几乎在任何一个系统中,都少不了用户授权功能,用户授权对于任何一个系统来说都是必要的,像管理型的页面都需要用户先去登陆,然后拿到凭证,才可以进行访问,这在MVC和WebApi体系结构里是很容易实现的,像过滤器里的AuthorizeAttribute和ActionFilterAttribute都可以实现用户授权的功能. AuthorizeAttribute和Action