zoukankan      html  css  js  c++  java
  • 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);
        }
    View Code

    从中我们看到包含Controller的一些基本信息,包括Controller的名字,类型,并实现了ICustomAttributeProvider接口,方便在其上查找应用的attribute, 其中更重要是定义一个抽象的FindAction方法,帮助确定在Controller上调用的是那一个Action。在ActionInvoker的FindAction方法其实是通过ControllerDescriptor的FindAction来得到ActionDescriptor。现在我们来看一下ControllerDescriptor的子类,如下图所示:

    这里我们还是以同步的版本ReflectedControllerDescriptor为主,看看其FindAction方法的实现:

     1 public override ActionDescriptor FindAction(ControllerContext controllerContext, string actionName)
     2         {
     3             //省略非相关代码
     4     
     5             MethodInfo matched = _selector.FindActionMethod(controllerContext, actionName);
     6             if (matched == null)
     7             {
     8                 return null;
     9             }
    10 
    11             return new ReflectedActionDescriptor(matched, actionName, this);
    12         }    
    View Code

    可以看到,通一个名字_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列表

    关于属性路由的概念请参考
    http://blogs.msdn.com/b/webdev/archive/2013/10/17/attribute-routing-in-asp-net-mvc-5.aspx

    现在来看ActionMethodSelectorBase的FindActionMethod方法,具体代码如下:

     1  public MethodInfo FindActionMethod(ControllerContext controllerContext, string actionName)
     2         {
     3             //省略非相关代码
     4     
     5             List<MethodInfo> finalMethods = FindActionMethods(controllerContext, actionName);
     6 
     7             switch (finalMethods.Count)
     8             {
     9                 case 0:
    10                     return null;
    11 
    12                 case 1:
    13                     return finalMethods[0];
    14 
    15                 default:
    16                     throw CreateAmbiguousActionMatchException(finalMethods, actionName);
    17             }
    18         }
    View Code

    可以看到,查找动作又委托给了其内部的FindActionMethods方法:

     1  protected List<MethodInfo> FindActionMethods(ControllerContext controllerContext, string actionName)
     2         {
     3             List<MethodInfo> matches = new List<MethodInfo>();
     4 
     5             // Performance sensitive, so avoid foreach
     6             for (int i = 0; i < AliasedMethods.Length; i++)
     7             {
     8                 MethodInfo method = AliasedMethods[i];
     9                 if (IsMatchingAliasedMethod(method, controllerContext, actionName))
    10                 {
    11                     matches.Add(method);
    12                 }
    13             }
    14             matches.AddRange(NonAliasedMethods[actionName]);
    15             RunSelectionFilters(controllerContext, matches);
    16             return matches;
    17         }
    View Code

     FindActionMethods首先检查AliasedMethods中是否有方法与当前的action的name匹配,如果匹配则把当前的MethodInfo加入返回列表; 接着在NonAliasedMethods根据action name查找MethodInfo并加入返回列表,最后调用RunSelectionFilters对查找到的方法进行筛选。它的代码如下:

     1  protected static void RunSelectionFilters(ControllerContext controllerContext, List<MethodInfo> methodInfos)
     2         {
     3             // Filter depending on the selection attribute.
     4             // Methods with valid selection attributes override all others.
     5             // Methods with one or more invalid selection attributes are removed.
     6 
     7             bool hasValidSelectionAttributes = false;
     8             // loop backwards for fastest removal
     9             for (int i = methodInfos.Count - 1; i >= 0; i--)
    10             {
    11                 MethodInfo methodInfo = methodInfos[i];
    12                 ReadOnlyCollection<ActionMethodSelectorAttribute> attrs = ReflectedAttributeCache.GetActionMethodSelectorAttributesCollection(methodInfo);
    13                 if (attrs.Count == 0)
    14                 {
    15                     // case 1: this method does not have a MethodSelectionAttribute
    16 
    17                     if (hasValidSelectionAttributes)
    18                     {
    19                         // if there is already method with a valid selection attribute, remove method without one
    20                         methodInfos.RemoveAt(i);
    21                     }
    22                 }
    23                 else if (IsValidMethodSelector(attrs, controllerContext, methodInfo))
    24                 {
    25                     // case 2: this method has MethodSelectionAttributes that are all valid
    26 
    27                     // if a matching action method had a selection attribute, consider it more specific than a matching action method
    28                     // without a selection attribute
    29                     if (!hasValidSelectionAttributes)
    30                     {
    31                         // when the first selection attribute is discovered, remove any items later in the list without selection attributes
    32                         if (i + 1 < methodInfos.Count)
    33                         {
    34                             methodInfos.RemoveFrom(i + 1);
    35                         }
    36                         hasValidSelectionAttributes = true;
    37                     }
    38                 }
    39                 else
    40                 {
    41                     // case 3: this method has a method selection attribute but it is not valid
    42 
    43                     // remove the method since it is opting out of this request
    44                     methodInfos.RemoveAt(i);
    45                 }
    46             }
    47         }
    View Code

    RunSelectionFilters方法是检查Action应用的ActionMethodSelectorAttribute规则, 以确定最终的匹配的Action MethodInfo。

    ActionMethodSelectorAttribute一个抽象类,只定义了一个抽象方法:

     public abstract bool IsValidForRequest(ControllerContext controllerContext, MethodInfo methodInfo),用来检查在当前请求中,Action是否允许执行。比如在Action上声明了HttpPostAttribute,则只允许当前的http是POST请求,才允许执行当前Action.ActionMethodSelectorAttribute有很多子类,如下所示:

    除了NoActionAttribute ,其它的Attribute都是引用AcceptVerbsAttribute的实现,只不过提供一种简洁的使用方式。通过了RunSelectionFilters筛选,返回最终Action MethodInfo列表,在ActionMethodSelectorBase的FindActionMethod方法检查返回结果,如果返回MethodInfo数量为0,返回null, 为1是正常状态,大于1抛出AmbiguousMatchException.
     
    最终返回到ReflectedControllerDescriptor的FindAction方法中,实例化ReflectedActionDescriptor并返回。
     
    二. ReflectedActionDescriptor的说明
    它的接口如下:
      1  // 摘要: 
      2     //     包含描述反射的操作方法的信息。
      3     public class ReflectedActionDescriptor : ActionDescriptor
      4     {
      5         // 摘要: 
      6         //     初始化 System.Web.Mvc.ReflectedActionDescriptor 类的新实例。
      7         //
      8         // 参数: 
      9         //   methodInfo:
     10         //     操作方法信息。
     11         //
     12         //   actionName:
     13         //     操作的名称。
     14         //
     15         //   controllerDescriptor:
     16         //     控制器描述符。
     17         //
     18         // 异常: 
     19         //   System.ArgumentNullException:
     20         //     methodInfo 或 controllerDescriptor 参数为 null。
     21         //
     22         //   System.ArgumentException:
     23         //     actionName 参数为 null 或为空。
     24         public ReflectedActionDescriptor(MethodInfo methodInfo, string actionName, ControllerDescriptor controllerDescriptor);
     25 
     26         // 摘要: 
     27         //     获取操作的名称。
     28         //
     29         // 返回结果: 
     30         //     操作的名称。
     31         public override string ActionName { get; }
     32         //
     33         // 摘要: 
     34         //     获取控制器描述符。
     35         //
     36         // 返回结果: 
     37         //     控制器描述符。
     38         public override ControllerDescriptor ControllerDescriptor { get; }
     39         //
     40         // 摘要: 
     41         //     获取或设置操作方法信息。
     42         //
     43         // 返回结果: 
     44         //     操作方法信息。
     45         public MethodInfo MethodInfo { get; }
     46         //
     47         // 摘要: 
     48         //     使用延迟初始化来获取反射的操作描述符的唯一 ID。
     49         //
     50         // 返回结果: 
     51         //     唯一 ID。
     52         public override string UniqueId { get; }
     53 
     54         // 摘要: 
     55         //     使用指定的操作方法参数来执行指定的控制器上下文。
     56         //
     57         // 参数: 
     58         //   controllerContext:
     59         //     控制器上下文。
     60         //
     61         //   parameters:
     62         //     参数。
     63         //
     64         // 返回结果: 
     65         //     操作返回值。
     66         //
     67         // 异常: 
     68         //   System.ArgumentNullException:
     69         //     parameters 或 controllerContext 参数为 null。
     70         public override object Execute(ControllerContext controllerContext, IDictionary<string, object> parameters);
     71         //
     72         // 摘要: 
     73         //     返回为此成员定义的自定义特性的数组,指定的特性除外。
     74         //
     75         // 参数: 
     76         //   inherit:
     77         //     要查找继承的自定义特性的层次结构链,则为 true;否则为 false。
     78         //
     79         // 返回结果: 
     80         //     自定义特性的数组,如果没有自定义特性,则为空数组。
     81         //
     82         // 异常: 
     83         //   System.TypeLoadException:
     84         //     无法加载自定义特性类型。
     85         //
     86         //   System.Reflection.AmbiguousMatchException:
     87         //     为此成员定义的 attributeType 类型特性不止一个。
     88         public override object[] GetCustomAttributes(bool inherit);
     89         //
     90         // 摘要: 
     91         //     返回为此成员定义的自定义特性的数组(按类型标识)。
     92         //
     93         // 参数: 
     94         //   attributeType:
     95         //     自定义特性的类型。
     96         //
     97         //   inherit:
     98         //     要查找继承的自定义特性的层次结构链,则为 true;否则为 false。
     99         //
    100         // 返回结果: 
    101         //     自定义特性的数组,如果没有自定义特性,则为空数组。
    102         //
    103         // 异常: 
    104         //   System.TypeLoadException:
    105         //     无法加载自定义特性类型。
    106         //
    107         //   System.Reflection.AmbiguousMatchException:
    108         //     为此成员定义的 attributeType 类型特性不止一个。
    109         public override object[] GetCustomAttributes(Type attributeType, bool inherit);
    110         //
    111         // 摘要: 
    112         //     获取筛选器特性。
    113         //
    114         // 参数: 
    115         //   useCache:
    116         //     若要使用缓存,则为 true,否则为 false。
    117         //
    118         // 返回结果: 
    119         //     筛选器特性。
    120         public override IEnumerable<FilterAttribute> GetFilterAttributes(bool useCache);
    121         //
    122         // 摘要: 
    123         //     检索操作方法的参数。
    124         //
    125         // 返回结果: 
    126         //     操作方法的参数。
    127         public override ParameterDescriptor[] GetParameters();
    128         //
    129         // 摘要: 
    130         //     检索操作选择器。
    131         //
    132         // 返回结果: 
    133         //     操作选择器。
    134         public override ICollection<ActionSelector> GetSelectors();
    135         //
    136         // 摘要: 
    137         //     指示是否为此成员定义某个自定义特性类型的一个或多个实例。
    138         //
    139         // 参数: 
    140         //   attributeType:
    141         //     自定义特性的类型。
    142         //
    143         //   inherit:
    144         //     要查找继承的自定义特性的层次结构链,则为 true;否则为 false。
    145         //
    146         // 返回结果: 
    147         //     如果为此成员定义了自定义特性类型,则为 true;否则为 false。
    148         public override bool IsDefined(Type attributeType, bool inherit);
    149     }
    View Code

    我们看到它继承自ActionDescriptor,整个ActionDescriptor的继承关系如下所示:

      

  • 相关阅读:
    bzoj3796
    bzoj2186
    bzoj3769
    bzoj2660
    bzoj2245
    bzoj2916
    bzoj1261
    在IDEA中以TDD的方式对String类和Arrays类进行学习
    2018-2019-2 实验二《Java面向对象程序设计》实验报告
    《Java程序设计》第 6 周学习总结
  • 原文地址:https://www.cnblogs.com/jjyjjyjjy/p/3653215.html
Copyright © 2011-2022 走看看