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 = 0; 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;
}

转载于:https://www.cnblogs.com/h20064528/p/5049052.html

ActionDescriptor 的认识相关推荐

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

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

  2. ControllerDescriptor的认识

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

  3. ABP中的Filter(下)

    接着上面的一个部分来叙述,这一篇我们来重点看ABP中的AbpUowActionFilter.AbpExceptionFilter.AbpResultFilter这三个部分也是按照之前的思路来一个个介绍 ...

  4. 判断请求是否为Ajax请求的小妙招

    在写后台程序时,有时候需要知道客户端发送的是普通的请求,还是ajax 请求,最近在做项目的时候,有些地方需要判断当前的请求是不是ajax. 概述 在写后台程序时,有时候需要知道客户端发送的是普通的请求 ...

  5. ASP.NET Web API 过滤器创建、执行过程(二)

    ASP.NET Web API 过滤器创建.执行过程(二) 前言 前面一篇中讲解了过滤器执行之前的创建,通过实现IFilterProvider注册到当前的HttpConfiguration里的服务容器 ...

  6. C#进阶系列——WebApi 身份认证解决方案:Basic基础认证

    阅读目录 一.为什么需要身份认证 二.Basic基础认证的原理解析 1.常见的认证方式 2.Basic基础认证原理 三.Basic基础认证的代码示例 1.登录过程 2./Home/Index主界面 3 ...

  7. Asp.net MVC生命周期

     Asp.net应用程序管道处理用户请求时特别强调"时机",对Asp.net生命周期的了解多少直接影响我们写页面和控件的效率.因此在2007年和2008年我在这个话题上各写了一篇文 ...

  8. ABP源码分析三十四:ABP.Web.Mvc

    ABP.Web.Mvc模块主要完成两个任务: 第一,通过自定义的AbpController抽象基类封装ABP核心模块中的功能,以便利的方式提供给我们创建controller使用. 第二,一些常见的基础 ...

  9. ASP.NET.4.5.1+MVC5.0系统角色和权限讲解

    细说ASP.NET.4.5.1+MVC5.0系统角色和权限 MVC全名是Model View Controller,是模型(model)-视图(view)-控制器(controller)的缩写,一种软 ...

最新文章

  1. (二)数据预处理 2019年研究生数学建模D题《汽车行驶工况构建》
  2. mall整合SpringBoot+MyBatis搭建基本骨架
  3. 什么相片可以两张弄成一张_怎么将两张图片合成一张?
  4. 树莓派+docker+tensorflow
  5. Linux下进行源码安装时如何避免找不到那些使用--prefix指定目录安装的依赖
  6. 〖Linux〗VirtualBox修改虚拟电脑硬盘(vdi)空间大小
  7. Pr 入门教程,如何处理图片文件?
  8. 软件测试技能大赛山东省,我院获2020年山东省职业院校技能大赛“软件测试”赛项二等奖...
  9. Vue.js+axios制作的仿酷狗音乐-音乐播放界面
  10. windows 窗口实现隐藏任务栏预览
  11. Adobe Photoshop CC 2014图文永久安装教程
  12. idea启动vue项目
  13. Tor源码 -- 启动模块
  14. Android中屏蔽返回键,HOME键以及模拟HOME键返回效果的方法
  15. 2019年双十一购物数据分析报告
  16. redis事务java_Redis之Redis的事务
  17. mysql编码修改utf8_修改数据库mysql字符编码为UTF8
  18. 在旧时的桃花里,喊疼
  19. HALCON_根据XLD轮廓 把图像摆正_二
  20. 关于信息化管理的建议

热门文章

  1. 编译安装linux内核步骤
  2. 百度重置页面自动跳转脚本
  3. 雷林鹏分享:MySQL 及 SQL 注入
  4. kubernetes学习笔记之十三:基于calico的网络策略入门
  5. head和tail命令详解
  6. mongodb的安装及主从复制
  7. 凯文凯利:未来世界发展七大趋势
  8. 11gR2 GI和DB安装目录权限属主被修改后的恢复方法
  9. 控制语句 for while if switch
  10. hdu 2795 段树--点更新