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 ...
随机推荐
- C++primer 练习12.27
// 12_27.cpp : 定义控制台应用程序的入口点. // #include "stdafx.h" #include<iostream> #include< ...
- poj 1753 Flip Game
点击打开链接 Flip Game Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 25674 Accepted: 1109 ...
- phpmyadmin #2003 无法登录 MySQL服务器的解决方法
本文章向大家介绍phpmyadmin #2003 无法登录 MySQL服务器的解决方法,需要的码农可以参考一下. 通过phpmyadmin连接mysql数据库时提示:"2003 无法登录 M ...
- Redis服务器配置
Redis 服务器提供了一些配置选项(configuration option),通过修改这些选项的值,可以改变选项对应功能的行为. 比如:介绍 SELECT 命令时曾经说过,Redis 服务器默认会 ...
- android Json 解析和生成
什么是json: JSON即JavaScript Object Natation的简称,它是一种轻量级的数据交换格式,非常适合服务器与JavaScript的交互.JSON易于人阅读和编写.同时也易于机 ...
- Android开发-API指南-Fragment
Fragments 英文原文:http://developer.android.com/guide/components/fragments.html 采集日期:2014-12-31 在本文中 设计理 ...
- Calendar的add()方法介绍
[java] view plaincopy public static Date addYears(Date date, int amount) { return add(date, 1, amoun ...
- 智能指针(三):unique_ptr使用简介
我们知道auto_ptr通过复制构造或者通过=赋值后,原来的auto_ptr对象就报废了.所有权转移到新的对象中去了.而通过shared_ptr可以让多个智能指针对象同时拥有某一块内存的访问权.但假如 ...
- Windows server 2008 R2远程桌面终端连接数的破解
Windows server 2008 R2远程桌面终端连接数的破解 日常工作中,经常需要远程连接到服务器上,然而在公司里,老总.同事都需要连接到服务器上,而默认的服务器系统同时连接的最大连接数只有2 ...
- leetcode 112
112. Path Sum Given a binary tree and a sum, determine if the tree has a root-to-leaf path such that ...