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 = ; 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的认识的更多相关文章
- 控制器描述者(ControllerDescriptor),行为方法描述者(ActionDescriptor),参数描述者(ParameterDescriptor)的小结
Model的绑定是在Action方法绑定参数时发生的,这个绑定的参数过程要用到的元数据来自于控制器,行为方法和参数的描述者ContrllerDescriptor,ActionDescriptor和Pa ...
- MVC 3个重要的描述对象之ControllerDescriptor
1.ControllerDescriptor 1.1 ReflectedControllerDescriptor public class HomeController : Controller { ...
- ASP.NET MVC5学习笔记之Controller执行ControllerDescriptor和ActionDescriptor
一. ControllerDescriptor说明 ControllerDescriptor是一个抽象类,它定义的接口代码如下: public abstract class ControllerDes ...
- MVC4 Model ControllerDescriptor
1. ControllerDescriptor 的描述 Controller 的Action 方法有以下一些特性: 1.1 ActionNameAttribute特性 他继承自 System.We ...
- 半夜了我来发张图 睡觉 ControllerDescriptor 与 ActionDescriptor 之间 的 关系
- POCO Controller 你这么厉害,ASP.NET vNext 知道吗?
写在前面 阅读目录: POCO 是什么? 为什么会有 POJO? POJO 的意义 POJO 与 PO.VO 的区别 POJO 的扩展 POCO VS DTO Controller 是什么? 关于 P ...
- ASP.NET MVC5+EF6+EasyUI 后台管理系统(66)-MVC WebApi 用户验证 (2)
系列目录 前言: 回顾上一节,我们利用webapi简单的登录并进行了同域访问与跨域访问来获得Token,您可以跳转到上一节下载代码来一起动手. 继续上一篇的文章,我们接下来演示利用拿到的Token来访 ...
- MVC常遇见的几个场景代码分享
本次主要分享几个场景的处理代码,有更好处理方式多多交流,相互促进进步:代码由来主要是这几天使用前端Ace框架做后台管理系统,这Ace是H5框架里面的控件效果挺多的,做兼容也很好,有点遗憾是控件效果基本 ...
- 尝试asp.net mvc 基于controller action 方式权限控制方案可行性
微软在推出mvc框架不久,短短几年里,版本更新之快,真是大快人心,微软在这种优秀的框架上做了大量的精力投入,是值得赞同的,毕竟程序员驾驭在这种框架上,能够强力的精化代码,代码层次也更加优雅,扩展较为方 ...
随机推荐
- 我的Android进阶之旅------>Android采用AES+RSA的加密机制对http请求进行加密
前言 未加密的抓包截图 加密之后的抓包截图 基本需求及概念 AES算法 AES基本原理及算法流程 AES算法流程 RSA算法 RSA算法基本原理及流程 RSA算法实现流程 AES与RSA相结合数据加密 ...
- PAGELATCH_x和PAGEIOLATCH_x介绍
Microsoft SQL Server企业级平台管理实践 第11章 Buffer Latch Timeout的解析 什么是PAGELATCH和PAGEIOLATCH 1.PAGELATCH_x和PA ...
- ubuntu16.04 tomcat7安装和编码修改(转发:https://blog.csdn.net/zl544434558/article/details/76735564)
有直接通过命令安装的,但是我还是喜欢把文件下载下来,然后自己配置. 1,下载tomcat7二进制文件 https://tomcat.apache.org/download-70.cgi 2,解压tom ...
- Tornado模块分类
Tornado模块分类 1. Core web framework tornado.web — 包含web框架的大部分主要功能,包含RequestHandler和Application两个重要的类 t ...
- 关于shared pool的深入探讨(一) 【转载】
关于shared pool的深入探讨(一) 作者:eygle |English [转载时请标明出处和作者信息]|[恩墨学院 OCM培训传DBA成功之道]链接:http://www.eygle.co ...
- Java并发(5):同步容器
一. 同步容器出现的原因 在Java的集合容器框架中,主要有四大类别:List.Set.Queue.Map. List.Set.Queue接口分别继承了Collection接口,Map本身是一个接口. ...
- 【转】Python爬虫(7)_scrapy-redis
scrapy-redis使用以及剖析 scrapy-redis是一个基于redis的scrapy组件,通过它可以快速实现简单分布式爬虫程序,该组件本质上提供了三大功能: scheduler - 调 ...
- org.springframework.beans.factory.config.PropertyPlaceholderConfigurer类
<bean id="investorQueryConfigurer" class="org.springframework.beans.factory.config ...
- HDU - 3829 Cat VS Dog (二分图最大独立集)
题意:P个小朋友,每个人有喜欢的动物和讨厌的动物.留下喜欢的动物并且拿掉讨厌的动物,这个小朋友就会开心.问最多有几个小朋友能开心. 分析:对于每个动物来说,可能既有人喜欢又有人讨厌,那么这样的动物实际 ...
- gitlab + jenkins + docker + k8s
总体流程: 在开发机开发代码后提交到gitlab 之后通过webhook插件触发jenkins进行构建,jenkins将代码打成docker镜像,push到docker-registry 之后将在k8 ...