ActionDescriptor 的認識


     ActionDescriptor的作用是對Action方法的元數據的描述,通過ActionDescriptor我們可以獲取到action方法的相關的名稱,所屬控制器,方法的參數列表,應用到方法上的特性以及一些篩選器;ActionDescriptor是由ControllerDescriptor類中的FindAction方法進行創建;

     ActionDescriptor類也繼承了ICustomAttributeProvider接口,所以ActionDescriptor類或是它的繼承類也實現了GetCustomAttributes和IsDefined方法;

     ActionDescriptor類中的屬性和ControllerDescriptor類的屬性差不多,包含有一個含有描述操作符唯一性ID的 UniqueId,表示方法名稱的ActionName以及action所屬於的控制器的元數據描述類ControllerDescriptor等屬性字段;為了加快action方法的執行效率,ActionDescriptor類內部還創建了一個action方法調度的緩存屬性(ActionMethodDispatcherCache )DispatcherCache;

     ActionMethodDispatcherCache 這個類結構是key為MethodInfo value 為ActionMethodDispatcher的字典緩存,在這個緩存類中通過GetDispatcher方法來快速獲取ActionMethodDispatcher類;

  ReflectedActionDescriptor

      ReflectedActionDescriptor類在MVC框架中繼承了ActionDescriptor類而且繼承了IMethodInfoActionDescriptor接口(獲取MethodInfo信息),並且覆蓋了一些父類的方法;

     在ReflectedActionDescriptor類的構造函數中除了一些基本屬性的賦值以外,還會內部調用VerifyActionMethodIsCallable方法來對methodInfo屬性進行驗證,

     VerifyActionMethodIsCallable方法的驗證邏輯:

     1.方法不是靜態函數

     2.方法的名稱不能是ControllerBase類中的方法

     3.泛型方法中不能包含未賦值的泛型類型參數

     4.方法的參數中不能有in 或是out修飾的參數

    如果驗證不通過的話,直接throw一個ArgumentException異常;

    在ReflectedActionDescriptor類中包含有一個GetFilterAttributes方法來獲取應用到action方法上的FilterAttribute的特性列表;

    對於action方法中的參數的元數據的獲取是通過GetParameters方法,在ReflectedActionDescriptor類中有一個ParameterDescriptor[]的數組緩存,當緩存中存在時直接從緩存數組中獲取相應的參數元數據信息,如果沒有則通過MethodInfo的GetParameters方法獲取,然后調用ReflectedParameterDescriptor類的構造函數創建參數的元數據信息;

    在Control可以存在同名的action方法,當時同名的action方法不能有相同的請求方式,我們可以標記一個action方式支持Post,Get等提交方式,在MVC框架中HttpGetAttribute,HttpPostAttribute等特性類都繼承了抽象類ActionMethodSelectorAttribute類,在ActionMethodSelectorAttribute類中只包含一個IsValidForRequest抽象方法

  

    public abstract class ActionMethodSelectorAttribute : Attribute
    {
      public abstract bool IsValidForRequest(ControllerContext controllerContext, MethodInfo methodInfo);
    }

     在IsValidForRequest 方法目的是驗證當前action的方法是否與當前的請求類型相匹配;

     在ReflectedActionDescriptor類中提供了獲取這些篩選特性的方法GetSelectors,這個方法內部會返回作用於當前action當前的ActionMethodSelectorAttribute類的子類的列表,由於這個返回值是ActionSelector類型的集合,而ActionSelector是一個參數為ControllerContext返回值為布爾類型的委托

   public static ICollection<ActionSelector> GetSelectors(MethodInfo methodInfo)
   {
       ActionMethodSelectorAttribute[] attrs = (ActionMethodSelectorAttribute[])methodInfo.GetCustomAttributes(typeof(ActionMethodSelectorAttribute), inherit: true);
       ActionSelector[] selectors = Array.ConvertAll(attrs, attr => (ActionSelector)(controllerContext => attr.IsValidForRequest(controllerContext, methodInfo)));
      return selectors;
   }

    在ReflectedActionDescriptor類中還包含一個和GetSelectors方法類似的內部方法 GetNameSelectors,這個方法返回值為ActionNameSelector類型,這個類型也是一個委托類型,方法的作用是篩選ActionNameSelectorAttribute抽象類的子類的列表;其實內部實現和GetNameSelectors是相似的

 

   public static ICollection<ActionNameSelector> GetNameSelectors(MethodInfo methodInfo)
   {
       ActionNameSelectorAttribute[] attrs = (ActionNameSelectorAttribute[])methodInfo.GetCustomAttributes(typeof(ActionNameSelectorAttribute), inherit: true);
       ActionNameSelector[] selectors = Array.ConvertAll(attrs, attr => (ActionNameSelector)((controllerContext, actionName) => attr.IsValidName(controllerContext, actionName, methodInfo)));
       return selectors;
  }

      對於ActionNameSelectorAttribute與ActionMethodSelectorAttribute類的區別是前者是對action的名字進行篩選,而后者是對請求方式的篩選;

      當獲得了ReflectedActionDescriptor類后就會執行action方法的執行,對於action方法的執行時直接調用類的Execute方法;

        public override object Execute(ControllerContext controllerContext, IDictionary<string, object> parameters)

       在Execute方法的內部,由於考慮到性能,避免使用Linq或是委托;

      首先通過MethodInfo.GetParameters獲取到參數信息列表,然后對參數列表進行遍歷驗證,參數驗證保證不能有重復的參數名,如果參數值為空的話要保證參數的類型是可以為空,當參數值不為空時,要保證參數值的類型和參數的類型一致;如果其中一條規則不符合時就會    throw ArgumentException 異常;

     當參數列表遍歷完成后,就會在ActionMethodDispatcherCache緩存中通過GetDispatcher方法獲取到ActionMethodDispatcher類,然后調用ActionMethodDispatcher類來進行方法的調用,調用完成后執行結果返回;

 

public override object Execute(ControllerContext controllerContext, IDictionary<string, object> parameters)
{
    if (controllerContext == null)
    {
      throw new ArgumentNullException("controllerContext");
    }
    if (parameters == null)
    {
      throw new ArgumentNullException("parameters");
    }
// Performance sensitive so avoid Linq or delegates.
     ParameterInfo[] parameterInfos = MethodInfo.GetParameters();
     object[] parametersArray = new object[parameterInfos.Length];
     for (int i = 0; i < parameterInfos.Length; i++)
     {
       ParameterInfo parameterInfo = parameterInfos[i];
       object parameter = ExtractParameterFromDictionary(parameterInfo, parameters, MethodInfo);
       parametersArray[i] = parameter;
     }
     ActionMethodDispatcher dispatcher = DispatcherCache.GetDispatcher(MethodInfo);
     object actionReturnValue = dispatcher.Execute(controllerContext.Controller, parametersArray);
      return actionReturnValue;
}

 

     

     

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM