ActionDescriptor 的认识
ActionDescriptor的作用是对Action方法的元数据的描述,通过ActionDescriptor我们可以获取到action方法的相关的名称,所属控制器,方法的参数列表,应用到方法上的特性以及一些筛选器;ActionDescriptor是由ControllerDescriptor类中的FindAction方法进行创建;
ActionDescriptor类也继承了ICustomAttributeProvider接口,所以ActionDescriptor类或是它的继承类也实现了GetCustomAttributes和IsDefined方法;
ActionDescriptor类中的属性和ControllerDescriptor类的属性差不多,包含有一个含有描述操作符唯一性ID的 UniqueId,表示方法名称的ActionName以及action所属于的控制器的元数据描述类ControllerDescriptor等属性字段;为了加快action方法的执行效率,ActionDescriptor类内部还创建了一个action方法调度的缓存属性(ActionMethodDispatcherCache )DispatcherCache;
ActionMethodDispatcherCache 这个类结构是key为MethodInfo value 为ActionMethodDispatcher的字典缓存,在这个缓存类中通过GetDispatcher方法来快速获取ActionMethodDispatcher类;
ReflectedActionDescriptor
ReflectedActionDescriptor类在MVC框架中继承了ActionDescriptor类而且继承了IMethodInfoActionDescriptor接口(获取MethodInfo信息),并且覆盖了一些父类的方法;
在ReflectedActionDescriptor类的构造函数中除了一些基本属性的赋值以外,还会内部调用VerifyActionMethodIsCallable方法来对methodInfo属性进行验证,
VerifyActionMethodIsCallable方法的验证逻辑:
1.方法不是静态函数
2.方法的名称不能是ControllerBase类中的方法
3.泛型方法中不能包含未赋值的泛型类型参数
4.方法的参数中不能有in 或是out修饰的参数
如果验证不通过的话,直接throw一个ArgumentException异常;
在ReflectedActionDescriptor类中包含有一个GetFilterAttributes方法来获取应用到action方法上的FilterAttribute的特性列表;
对于action方法中的参数的元数据的获取是通过GetParameters方法,在ReflectedActionDescriptor类中有一个ParameterDescriptor[]的数组缓存,当缓存中存在时直接从缓存数组中获取相应的参数元数据信息,如果没有则通过MethodInfo的GetParameters方法获取,然后调用ReflectedParameterDescriptor类的构造函数创建参数的元数据信息;
在Control可以存在同名的action方法,当时同名的action方法不能有相同的请求方式,我们可以标记一个action方式支持Post,Get等提交方式,在MVC框架中HttpGetAttribute,HttpPostAttribute等特性类都继承了抽象类ActionMethodSelectorAttribute类,在ActionMethodSelectorAttribute类中只包含一个IsValidForRequest抽象方法
public abstract class ActionMethodSelectorAttribute : Attribute
{
public abstract bool IsValidForRequest(ControllerContext controllerContext, MethodInfo methodInfo);
}
在IsValidForRequest 方法目的是验证当前action的方法是否与当前的请求类型相匹配;
在ReflectedActionDescriptor类中提供了获取这些筛选特性的方法GetSelectors,这个方法内部会返回作用于当前action当前的ActionMethodSelectorAttribute类的子类的列表,由于这个返回值是ActionSelector类型的集合,而ActionSelector是一个参数为ControllerContext返回值为布尔类型的委托
public static ICollection<ActionSelector> GetSelectors(MethodInfo methodInfo)
{
ActionMethodSelectorAttribute[] attrs = (ActionMethodSelectorAttribute[])methodInfo.GetCustomAttributes(typeof(ActionMethodSelectorAttribute), inherit: true);
ActionSelector[] selectors = Array.ConvertAll(attrs, attr => (ActionSelector)(controllerContext => attr.IsValidForRequest(controllerContext, methodInfo)));
return selectors;
}
在ReflectedActionDescriptor类中还包含一个和GetSelectors方法类似的内部方法 GetNameSelectors,这个方法返回值为ActionNameSelector类型,这个类型也是一个委托类型,方法的作用是筛选ActionNameSelectorAttribute抽象类的子类的列表;其实内部实现和GetNameSelectors是相似的
public static ICollection<ActionNameSelector> GetNameSelectors(MethodInfo methodInfo)
{
ActionNameSelectorAttribute[] attrs = (ActionNameSelectorAttribute[])methodInfo.GetCustomAttributes(typeof(ActionNameSelectorAttribute), inherit: true);
ActionNameSelector[] selectors = Array.ConvertAll(attrs, attr => (ActionNameSelector)((controllerContext, actionName) => attr.IsValidName(controllerContext, actionName, methodInfo)));
return selectors;
}
对于ActionNameSelectorAttribute与ActionMethodSelectorAttribute类的区别是前者是对action的名字进行筛选,而后者是对请求方式的筛选;
当获得了ReflectedActionDescriptor类后就会执行action方法的执行,对于action方法的执行时直接调用类的Execute方法;
public override object Execute(ControllerContext controllerContext, IDictionary<string, object> parameters)
在Execute方法的内部,由于考虑到性能,避免使用Linq或是委托;
首先通过MethodInfo.GetParameters获取到参数信息列表,然后对参数列表进行遍历验证,参数验证保证不能有重复的参数名,如果参数值为空的话要保证参数的类型是可以为空,当参数值不为空时,要保证参数值的类型和参数的类型一致;如果其中一条规则不符合时就会 throw ArgumentException 异常;
当参数列表遍历完成后,就会在ActionMethodDispatcherCache缓存中通过GetDispatcher方法获取到ActionMethodDispatcher类,然后调用ActionMethodDispatcher类来进行方法的调用,调用完成后执行结果返回;
public override object Execute(ControllerContext controllerContext, IDictionary<string, object> parameters)
{
if (controllerContext == null)
{
throw new ArgumentNullException("controllerContext");
}
if (parameters == null)
{
throw new ArgumentNullException("parameters");
}
// Performance sensitive so avoid Linq or delegates.
ParameterInfo[] parameterInfos = MethodInfo.GetParameters();
object[] parametersArray = new object[parameterInfos.Length];
for (int i = ; i < parameterInfos.Length; i++)
{
ParameterInfo parameterInfo = parameterInfos[i];
object parameter = ExtractParameterFromDictionary(parameterInfo, parameters, MethodInfo);
parametersArray[i] = parameter;
}
ActionMethodDispatcher dispatcher = DispatcherCache.GetDispatcher(MethodInfo);
object actionReturnValue = dispatcher.Execute(controllerContext.Controller, parametersArray);
return actionReturnValue;
}
ActionDescriptor 的认识的更多相关文章
- 控制器描述者(ControllerDescriptor),行为方法描述者(ActionDescriptor),参数描述者(ParameterDescriptor)的小结
Model的绑定是在Action方法绑定参数时发生的,这个绑定的参数过程要用到的元数据来自于控制器,行为方法和参数的描述者ContrllerDescriptor,ActionDescriptor和Pa ...
- ASP.NET MVC5学习笔记之Controller执行ControllerDescriptor和ActionDescriptor
一. ControllerDescriptor说明 ControllerDescriptor是一个抽象类,它定义的接口代码如下: public abstract class ControllerDes ...
- Asp.net MVC中三大描述对象之ActionDescriptor 以及继承类ReflectedControllerDescriptor
ActionDescriptor抽象类中几个基本的属性: ControllerName:被描述的Controller名称,去除后缀Controller的名称.例如:HomeController则为Ho ...
- 半夜了我来发张图 睡觉 ControllerDescriptor 与 ActionDescriptor 之间 的 关系
- .NetCore MVC中的路由(1)路由配置基础
.NetCore MVC中的路由(1)路由配置基础 0x00 路由在MVC中起到的作用 前段时间一直忙于别的事情,终于搞定了继续学习.NetCore.这次学习的主题是MVC中的路由.路由是所有MVC框 ...
- POCO Controller 你这么厉害,ASP.NET vNext 知道吗?
写在前面 阅读目录: POCO 是什么? 为什么会有 POJO? POJO 的意义 POJO 与 PO.VO 的区别 POJO 的扩展 POCO VS DTO Controller 是什么? 关于 P ...
- ASP.NET MVC5+EF6+EasyUI 后台管理系统(71)-微信公众平台开发-公众号管理
系列目录 思维导图 下面我们来看一个思维导图,这样就可以更快了解所需要的功能: 上一节我们利用了一个简单的代码例子,完成了与微信公众号的对话(给公众号发一条信息,并得到回复) 这一节将讲解公众号如何设 ...
- ASP.NET MVC5+EF6+EasyUI 后台管理系统(66)-MVC WebApi 用户验证 (2)
系列目录 前言: 回顾上一节,我们利用webapi简单的登录并进行了同域访问与跨域访问来获得Token,您可以跳转到上一节下载代码来一起动手. 继续上一篇的文章,我们接下来演示利用拿到的Token来访 ...
- MVC常遇见的几个场景代码分享
本次主要分享几个场景的处理代码,有更好处理方式多多交流,相互促进进步:代码由来主要是这几天使用前端Ace框架做后台管理系统,这Ace是H5框架里面的控件效果挺多的,做兼容也很好,有点遗憾是控件效果基本 ...
随机推荐
- Android学习七---Hello OpenCV samples
创建一个能够使用OpenCV JavaCameraView的应用程序来了解基于OpenCV java API 的应用程序的开发流程.有了Android的基础,在程序中需要修改的几个地方1.activi ...
- Remote System Upgrade With Cyclone III Devices
系统设计者会遇到较短的设计周期.标准发展和系统调度的挑战,飓风III系列支持远程系统更新,通过其固有的重编程功能和专有电路来克服以上问题.远程系统更新帮助传递系统性能增强和bug修复,避免了昂贵的召回 ...
- Django框架之单表操作
一.添加表记录 对于单表有两种方式 # 添加数据的两种方式 # 方式一:实例化对象就是一条表记录 Frank_obj = models.Student(name ="海东",cou ...
- Typecho部署安装
此文章已经在这里上. 如果您看到这篇文章,表示您的 blog 已经在digitalocean.com安装成功.下面说下安装的步骤,此文章都是在digitalocean.com的centos上成功安装: ...
- 3. Longest Substring Without Repeating Characters(最长子串,双指针+hash)
Given a string, find the length of the longest substring without repeating characters. Examples: Giv ...
- Apache 浏览器访问限制配置
浏览器访问限制配置 user_agent收入的浏览器中,我们通过百度,谷歌很容易就可以查到相关的一些资料,方便了我们对知识的查找,但在某些特定情况下,我们并不希望有人可以通过某写搜索引擎直接访问到我们 ...
- Nginx 域名跳转
域名跳转 就是实现URL的跳转和隐藏真实地址,基于Perl语言的正则表达式规范.平时帮助我们实现拟静态,拟目录,域名跳转,防止盗链等 . 域名跳转配置 1.多域名指定一个域名重定向 # 空格分割域名 ...
- 运维必备技能 WEB 日志分析
文章节选自<Netkiller Monitoring 手札> 20.2. Web 20.2.1. Apache Log 1.查看当天有多少个IP访问: awk '{print $1}' l ...
- 20145109《Java程序设计》第一周学习总结
20145109 <Java程序设计>第一周学习总结 教材学习内容总结 About JVM, JRE, JDK JVM包含于JRE中,用于运行Java程序.JDK用于开发Java程序,包含 ...
- Gradle命令详解与导入第三方包--快速打包
快速打包app:gradlew assembleRelease --console plain (好使) 下边的方法暂时不好使,可以用的兄弟请教下哈! Android Studio + Gradle的 ...