一. 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的继承关系如下所示: