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 ...
随机推荐
- java 抽象类和接口总结
1.抽象类和抽象方法必须使用abstract 关键字来修饰 2.抽象类不能实例化 3.抽象方法是为实现的方法,它与空方法时两个完全不同的概念 4.abstract 不能喝private static ...
- Mongdb操作嵌套文档
1.一个文档如下 db.posts.find() { "_id" : ObjectId("5388162dfc164ee1f39be37f"), "t ...
- SparkStreaming结合Kafka使用
spark自带的example中就有streaming结合kafka使用的案例: $SPARK_HOME/examples/src/main/scala/org/apache/spark/exampl ...
- java.io.Serializable浅析
转自:http://www.cnblogs.com/gw811/archive/2012/10/10/2718331.html Java API中java.io.Serializable接口源码: p ...
- 简单的python http接口自动化脚本
今天给大家分享一个简单的Python脚本,使用python进行http的接口测试,脚本很简单,逻辑是:读取excel写好的测试用例,然后根据excel中的用例内容进行调用,判断预期结果中的返回值是否和 ...
- java基础问题 (转)
原文地址:http://blog.csdn.net/free0sky/article/details/7927275 一.String,StringBuffer, StringBuilder 的区别是 ...
- 基于Web的企业网和互联网的信息和应用( 1194.22 )
基于Web的企业网和互联网的信息和应用( 1194.22 ) 原文更新日期: 2001年6月21日原文地址: http://www.access-board.gov/sec508/guide/1194 ...
- USACO Section 3.2 01串 Stringsobits
题目背景 考虑排好序的N(N<=31)位二进制数. 题目描述 他们是排列好的,而且包含所有长度为N且这个二进制数中1的位数的个数小于等于L(L<=N)的数. 你的任务是输出第i(1< ...
- Android基础总结(5)——数据存储,持久化技术
瞬时数据:指那些存储在内存当中,有可能会因为程序广播或其他原因导致内存被回收而丢失的数据. 数据持久化:指将那些内存中的瞬时数据保存到存储设备中,保证即使在手机或电脑关机的情况下,这些数据仍然不丢失. ...
- com组件 智能指针崩溃问题崩溃问题
int main(){ CoInitialize(NULL); HRESULT hr; IWinHttpRequestPtr pHttpReq=NULL; pHttpReq.CreateInstanc ...