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 = ; 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 - ; i >= ; i--)
{
MethodInfo methodInfo = methodInfos[i];
ReadOnlyCollection<ActionMethodSelectorAttribute> attrs = ReflectedAttributeCache.GetActionMethodSelectorAttributesCollection(methodInfo);
if (attrs.Count == )
{
// 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 + < methodInfos.Count)
{
methodInfos.RemoveFrom(i + );
}
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 > );
for (int i = ; i < attributeCount; i++)
{
if (!attributes[i].IsValidForRequest(controllerContext, method))
{
return false;
}
}
return true;
}

ControllerDescriptor的认识的更多相关文章

  1. 控制器描述者(ControllerDescriptor),行为方法描述者(ActionDescriptor),参数描述者(ParameterDescriptor)的小结

    Model的绑定是在Action方法绑定参数时发生的,这个绑定的参数过程要用到的元数据来自于控制器,行为方法和参数的描述者ContrllerDescriptor,ActionDescriptor和Pa ...

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

    1.ControllerDescriptor 1.1 ReflectedControllerDescriptor public class HomeController : Controller { ...

  3. ASP.NET MVC5学习笔记之Controller执行ControllerDescriptor和ActionDescriptor

    一. ControllerDescriptor说明 ControllerDescriptor是一个抽象类,它定义的接口代码如下: public abstract class ControllerDes ...

  4. MVC4 Model ControllerDescriptor

    1. ControllerDescriptor 的描述 Controller  的Action 方法有以下一些特性: 1.1 ActionNameAttribute特性  他继承自 System.We ...

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

  6. POCO Controller 你这么厉害,ASP.NET vNext 知道吗?

    写在前面 阅读目录: POCO 是什么? 为什么会有 POJO? POJO 的意义 POJO 与 PO.VO 的区别 POJO 的扩展 POCO VS DTO Controller 是什么? 关于 P ...

  7. ASP.NET MVC5+EF6+EasyUI 后台管理系统(66)-MVC WebApi 用户验证 (2)

    系列目录 前言: 回顾上一节,我们利用webapi简单的登录并进行了同域访问与跨域访问来获得Token,您可以跳转到上一节下载代码来一起动手. 继续上一篇的文章,我们接下来演示利用拿到的Token来访 ...

  8. MVC常遇见的几个场景代码分享

    本次主要分享几个场景的处理代码,有更好处理方式多多交流,相互促进进步:代码由来主要是这几天使用前端Ace框架做后台管理系统,这Ace是H5框架里面的控件效果挺多的,做兼容也很好,有点遗憾是控件效果基本 ...

  9. 尝试asp.net mvc 基于controller action 方式权限控制方案可行性

    微软在推出mvc框架不久,短短几年里,版本更新之快,真是大快人心,微软在这种优秀的框架上做了大量的精力投入,是值得赞同的,毕竟程序员驾驭在这种框架上,能够强力的精化代码,代码层次也更加优雅,扩展较为方 ...

随机推荐

  1. 基于mondrain 的原理纠正特殊指标值

    原文地址:http://www.cnblogs.com/qiaoyihang/p/7348385.html 下面有两张表 数学试卷成绩 表1 学号 省份 批次 学校 试卷成绩 数学试卷小题成绩 表2 ...

  2. 知乎Live总结-重复nature文章笔记Single-cell

    来自知乎Live-孟浩巍 1.文章重要技术及图讲解 首先在转录组RNA-seq中,有基因表达差异.基因融合.可变剪切.RNA单点突变. 在基因组中,单点变异.结构变异,CNV变异(拷贝数变异) 三类基 ...

  3. 解释一下python中的逻辑运算符

    python中有三个逻辑运算符:and.or.not print(False and True)#False print(7<7 or True)#True print(not 2==2)#Fa ...

  4. mongodb的安装使用和pymongo基本使用

    (1) mongodb的安装 下载tgz解压后,需要添加相应的环境变量才能在终端直接启动mongod. mongodb数据存储在/data/db中,需要手动创建目录树,同时mongod执行的时候如果权 ...

  5. Django学习笔记之模板渲染、模板语言、simple_tag、母版子版、静态配置文件

    一.首先我们用PyCharm来创建一个Django项目 终端命令:django-admin startproject sitename 图形创建:   这样一个Django项目就创建完成了,上面可以看 ...

  6. Zabbix JVM 安装

    Zabbix 服务端安装插件 系统:centos 7.4 x64 环境:zabbix 3.0.16 yum源:rpm -ivh http://repo.zabbix.com/zabbix/3.0/rh ...

  7. FTP pure-ftpd 安装、管理

    FTP简介 FTP是File Transfer Protocol(文件传输协议)的英文简称,而中文简称为文传协议,用户Internet上的控制文件的双向传输. FTP的主要作用,就是让用户链接上一个远 ...

  8. 《React-Native系列》3、RN与native交互之Callback、Promise

    接着上一篇<React-Native系列>RN与native交互与数据传递,我们接下来研究另外的两种RN与Native交互的机制 一.Callback机制 首先Calllback是异步的, ...

  9. Windows Server 2008 R2服务器遗忘管理员密码解决方案

     A goal is a dream with a deadline. Much effort, much prosperity.  在日常的工作中,对于一个网络管理员来讲最悲哀的事情莫过于在没有备用 ...

  10. 1001: [BeiJing2006]狼抓兔子

    1001: [BeiJing2006]狼抓兔子 Time Limit: 15 Sec  Memory Limit: 162 MBSubmit: 12827  Solved: 3044[Submit][ ...