ASP.NET MVC5学习笔记之Controller执行ControllerDescriptor和ActionDescriptor
一. ControllerDescriptor说明
ControllerDescriptor是一个抽象类,它定义的接口代码如下:
public abstract class ControllerDescriptor : ICustomAttributeProvider, IUniquelyIdentifiable
{ public abstract ActionDescriptor FindAction(ControllerContext controllerContext, string actionName); public virtual object[] GetCustomAttributes(bool inherit); public virtual object[] GetCustomAttributes(Type attributeType, bool inherit); public virtual IEnumerable<FilterAttribute> GetFilterAttributes(bool useCache); public virtual bool IsDefined(Type attributeType, bool inherit);
}
从中我们看到包含Controller的一些基本信息,包括Controller的名字,类型,并实现了ICustomAttributeProvider接口,方便在其上查找应用的attribute, 其中更重要是定义一个抽象的FindAction方法,帮助确定在Controller上调用的是那一个Action。在ActionInvoker的FindAction方法其实是通过ControllerDescriptor的FindAction来得到ActionDescriptor。现在我们来看一下ControllerDescriptor的子类,如下图所示:
这里我们还是以同步的版本ReflectedControllerDescriptor为主,看看其FindAction方法的实现:
public override ActionDescriptor FindAction(ControllerContext controllerContext, string actionName)
{
//省略非相关代码 MethodInfo matched = _selector.FindActionMethod(controllerContext, actionName);
if (matched == null)
{
return null;
} return new ReflectedActionDescriptor(matched, actionName, this);
}
可以看到,通一个名字_selector的属性的FindActionMethod方法查找Action的方法元数据,如果有找到方法元数据描述最终返回ReflectedActionDescriptor,否则返回null
_selector的类型名为ActionMethodSelector的内部类,它继承自ActionMethodSelectorBase类型, ActionMethodSelectorBase在初始化时会调用PopulateLookupTables方法,它会准备好在当前Controller上Action方法有关的数据, 主要包括三个方面的列表:
1. 在Action上应用了别名属性ActionNameSelectorAttribute的方法MethodInfo列表(AliasedMethods), ActionNameSelectorAttribute其作用在于允许请求的url中的Action name为ActionNameSelectorAttribute指定的name, 可以匹配该Action;
2. 正常的Action方法MethodInfo列表(NonAliasedMethods)
3. 在Action上应用了属性路由(Attribute Routing)MethodInfo列表
现在来看ActionMethodSelectorBase的FindActionMethod方法,具体代码如下:
public MethodInfo FindActionMethod(ControllerContext controllerContext, string actionName)
{
//省略非相关代码 List<MethodInfo> finalMethods = FindActionMethods(controllerContext, actionName); switch (finalMethods.Count)
{
case :
return null; case :
return finalMethods[]; default:
throw CreateAmbiguousActionMatchException(finalMethods, actionName);
}
}
可以看到,查找动作又委托给了其内部的FindActionMethods方法:
protected List<MethodInfo> FindActionMethods(ControllerContext controllerContext, string actionName)
{
List<MethodInfo> matches = new List<MethodInfo>(); // Performance sensitive, so avoid foreach
for (int i = ; i < AliasedMethods.Length; i++)
{
MethodInfo method = AliasedMethods[i];
if (IsMatchingAliasedMethod(method, controllerContext, actionName))
{
matches.Add(method);
}
}
matches.AddRange(NonAliasedMethods[actionName]);
RunSelectionFilters(controllerContext, matches);
return matches;
}
FindActionMethods首先检查AliasedMethods中是否有方法与当前的action的name匹配,如果匹配则把当前的MethodInfo加入返回列表; 接着在NonAliasedMethods根据action name查找MethodInfo并加入返回列表,最后调用RunSelectionFilters对查找到的方法进行筛选。它的代码如下:
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);
}
}
}
RunSelectionFilters方法是检查Action应用的ActionMethodSelectorAttribute规则, 以确定最终的匹配的Action MethodInfo。
ActionMethodSelectorAttribute一个抽象类,只定义了一个抽象方法:
public abstract bool IsValidForRequest(ControllerContext controllerContext, MethodInfo methodInfo),用来检查在当前请求中,Action是否允许执行。比如在Action上声明了HttpPostAttribute,则只允许当前的http是POST请求,才允许执行当前Action.ActionMethodSelectorAttribute有很多子类,如下所示:
// 摘要:
// 包含描述反射的操作方法的信息。
public class ReflectedActionDescriptor : ActionDescriptor
{
// 摘要:
// 初始化 System.Web.Mvc.ReflectedActionDescriptor 类的新实例。
//
// 参数:
// methodInfo:
// 操作方法信息。
//
// actionName:
// 操作的名称。
//
// controllerDescriptor:
// 控制器描述符。
//
// 异常:
// System.ArgumentNullException:
// methodInfo 或 controllerDescriptor 参数为 null。
//
// System.ArgumentException:
// actionName 参数为 null 或为空。
public ReflectedActionDescriptor(MethodInfo methodInfo, string actionName, ControllerDescriptor controllerDescriptor); // 摘要:
// 获取操作的名称。
//
// 返回结果:
// 操作的名称。
public override string ActionName { get; }
//
// 摘要:
// 获取控制器描述符。
//
// 返回结果:
// 控制器描述符。
public override ControllerDescriptor ControllerDescriptor { get; }
//
// 摘要:
// 获取或设置操作方法信息。
//
// 返回结果:
// 操作方法信息。
public MethodInfo MethodInfo { get; }
//
// 摘要:
// 使用延迟初始化来获取反射的操作描述符的唯一 ID。
//
// 返回结果:
// 唯一 ID。
public override string UniqueId { get; } // 摘要:
// 使用指定的操作方法参数来执行指定的控制器上下文。
//
// 参数:
// controllerContext:
// 控制器上下文。
//
// parameters:
// 参数。
//
// 返回结果:
// 操作返回值。
//
// 异常:
// System.ArgumentNullException:
// parameters 或 controllerContext 参数为 null。
public override object Execute(ControllerContext controllerContext, IDictionary<string, object> parameters);
//
// 摘要:
// 返回为此成员定义的自定义特性的数组,指定的特性除外。
//
// 参数:
// inherit:
// 要查找继承的自定义特性的层次结构链,则为 true;否则为 false。
//
// 返回结果:
// 自定义特性的数组,如果没有自定义特性,则为空数组。
//
// 异常:
// System.TypeLoadException:
// 无法加载自定义特性类型。
//
// System.Reflection.AmbiguousMatchException:
// 为此成员定义的 attributeType 类型特性不止一个。
public override object[] GetCustomAttributes(bool inherit);
//
// 摘要:
// 返回为此成员定义的自定义特性的数组(按类型标识)。
//
// 参数:
// attributeType:
// 自定义特性的类型。
//
// inherit:
// 要查找继承的自定义特性的层次结构链,则为 true;否则为 false。
//
// 返回结果:
// 自定义特性的数组,如果没有自定义特性,则为空数组。
//
// 异常:
// System.TypeLoadException:
// 无法加载自定义特性类型。
//
// System.Reflection.AmbiguousMatchException:
// 为此成员定义的 attributeType 类型特性不止一个。
public override object[] GetCustomAttributes(Type attributeType, bool inherit);
//
// 摘要:
// 获取筛选器特性。
//
// 参数:
// useCache:
// 若要使用缓存,则为 true,否则为 false。
//
// 返回结果:
// 筛选器特性。
public override IEnumerable<FilterAttribute> GetFilterAttributes(bool useCache);
//
// 摘要:
// 检索操作方法的参数。
//
// 返回结果:
// 操作方法的参数。
public override ParameterDescriptor[] GetParameters();
//
// 摘要:
// 检索操作选择器。
//
// 返回结果:
// 操作选择器。
public override ICollection<ActionSelector> GetSelectors();
//
// 摘要:
// 指示是否为此成员定义某个自定义特性类型的一个或多个实例。
//
// 参数:
// attributeType:
// 自定义特性的类型。
//
// inherit:
// 要查找继承的自定义特性的层次结构链,则为 true;否则为 false。
//
// 返回结果:
// 如果为此成员定义了自定义特性类型,则为 true;否则为 false。
public override bool IsDefined(Type attributeType, bool inherit);
}
我们看到它继承自ActionDescriptor,整个ActionDescriptor的继承关系如下所示:
ASP.NET MVC5学习笔记之Controller执行ControllerDescriptor和ActionDescriptor的更多相关文章
- ASP.NET MVC5学习笔记之Controller同步执行架构分析
在开始之前,声明一下,由于ASP.NET MVC5正式发布了,后面的分析将基于ASP.NET MVC5最新的源代码.在前面的内容我们分析了怎样根据路由信息来确定Controller的类型,并最终生成C ...
- ASP.NET MVC 学习笔记-7.自定义配置信息 ASP.NET MVC 学习笔记-6.异步控制器 ASP.NET MVC 学习笔记-5.Controller与View的数据传递 ASP.NET MVC 学习笔记-4.ASP.NET MVC中Ajax的应用 ASP.NET MVC 学习笔记-3.面向对象设计原则
ASP.NET MVC 学习笔记-7.自定义配置信息 ASP.NET程序中的web.config文件中,在appSettings这个配置节中能够保存一些配置,比如, 1 <appSettin ...
- ASP.NET MVC5学习笔记01
由于之前在项目中也使用MVC进行开发,但是具体是那个版本就不是很清楚了,但是我觉得大体的思想是相同的,只是版本高的在版本低的基础上增加了一些更加方便操作的东西.下面是我学习ASP.NET MVC5高级 ...
- ASP.NET MVC5 学习笔记-1 控制器、路由、返回类型、选择器、过滤器
[TOC] 1. Action 1.1 新建项目 新建项目->Web->Asp.net Web应用程序,选择MVC,选择添加测试. 在解决方案上右键,选择"管理NuGet程序包& ...
- ASP.NET MVC5学习笔记之Filter提供体系
前面我们介绍了Filter的基本使用,但各种Filter要在合适的时机运行起来,需要预先准备好,现在看看ASP.NET MVC框架是怎么做的. 一.Filter集合 在ControlerActionI ...
- ASP.NET MVC5学习笔记之Filter基本介绍
Filter是ASP.NET MVC框架提供的基于AOP(面向方面)设计,提供在Action执行前后做一些非业务逻辑通用处理,如用户验证,缓存等.现在来看看Filter相关的一些类型信息. 一.基本类 ...
- ASP.NET MVC5学习笔记之Action参数模型绑定基本过程
当我们在Controller中定义一个Action,通常会定义一个或多个参数,每个参数称为一个模型,ASP.NET MVC框架提供了一种机制称为模型绑定,会尝试自动从请求的信息中实例化每一个模型并赋值 ...
- ASP.NET MVC4学习笔记之Controller的激活
一. 高层相关类说明 当路由系统根据请求Url收集路由信息后,下一步就要将路由信息传给Controller激活系统,Controller激活系统负责实现了IController接口的Controlle ...
- ASP.NET MVC5 学习笔记-4 OWIN和Katana
1. Owin OWIN全名:Open Web Interface for .NET. 它是一个说明,而非一个框架,该声明用来实现Web服务器和框架的松耦合.它提供了模块化.轻量级和便携的设计.类似N ...
随机推荐
- poj 1273 (nyoj 323) Drainage Ditches : 最大流
点击打开链接 Drainage Ditches Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 49648 Accepte ...
- Regional Changchun Online--Elven Postman(裸排序二叉树)
Elven Postman Time Limit: 1500/1000 MS (Java/Others) Memory Limit: 131072/131072 K (Java/Others) Tot ...
- NOIP201305转圈游戏
2016.1.25 试题描述 有n个小伙伴(编号从0到n-1)围坐一圈玩游戏.按照顺时针方向给n个位置编号,从0到n-1.最初,第0号小伙伴在第0号位置,第1号小伙伴在第1号位置,……,依此类推. ...
- BeanDefinitionStoreException: Failed to read candidate component class: URL
如题,遇到这种情况一般都是引用jar包版本不一致或者编译后的class除了问题 解决办法: a.如果是maven项目,把项目全部clean一下,重新mvn install b.如果不是maven项目, ...
- Troubleshooting 'library cache: mutex X' Waits.
What is a 'library cache: mutex X' wait? The mutex feature is a mechanism to control access to in me ...
- OC基础(27)
单例设计模式 *:first-child { margin-top: 0 !important; } body > *:last-child { margin-bottom: 0 !import ...
- Hive参数层面常用优化
1.hive数据仓库权限问题: set hive.warehouse.subdir.inherit.perms=true; 2.HiveServer2的内存 连接的个数越多压力越大,可以加大内存:可以 ...
- (Loadrunner)Error: Failed to send data by channels - post message failed.(转)
把Diagnotics-configure-Web Page Diagnotics 设置为 转自: http://www.51testing.com/html/64/371664-3708254.ht ...
- 注销CA登录
//移除CA缓存HttpCookie ticketCookie = Request.Cookies[FormsAuthentication.FormsCookieName];FormsAuthenti ...
- C#中messagebox用法
[函数] <整型> MessageBox(<字符串 Text, <字符串> Title, <整型> nType,MessageBoxIcon);[函数说明] ...