好得很程序员自学网

<tfoot draggable='sEl'></tfoot>

ASP.NET MVC三个重要的描述对象:ActionDescriptor

ASP.NET MVC三个重要的描述对象:ActionDescriptor

在Model绑定过程中会通过激活的Controller类型创建用于描述它的ControllerDescriptor对象。Controller是一组Action方法的集合,而每一个Action通过ActionDescriptor对象来表示,在这篇文章中我们就来着重谈谈不同类型的ActionDescriptor。[本文已经同步到《 How ASP.NET MVC Works? 》中]

目录 
一、ActionDescriptor 
二、AsyncActionDescriptor 
三、ReflectedActionDescriptor 
四、ReflectedAsyncActionDescriptor 
五、TaskAsyncActionDescriptor

一、ActionDescriptor

用于描述定义在Controller类中的Action方法的ActionDescriptor定义如下。属性ActionName和ControllerDescriptor表示Action的名称和描述所在Controller的ControllerDescriptor对象。表示唯一标识的UniqueId属性由 自身类型 、 Controller的类型 与 Action名称 三者派生。

    1:   public   abstract   class  ActionDescriptor : ICustomAttributeProvider
    2:  {
    3:       public   virtual   object [] GetCustomAttributes( bool  inherit);
    4:       public   virtual   object [] GetCustomAttributes(Type attributeType,   bool  inherit);
    5:       public   virtual   bool  IsDefined(Type attributeType,  bool  inherit);
    6:       public   virtual  IEnumerable<FilterAttribute> GetFilterAttributes(  bool  useCache);
    7:      
    8:       public   abstract  ParameterDescriptor[] GetParameters();
    9:       public   abstract   object  Execute(ControllerContext controllerContext,  IDictionary< string ,  object > parameters);
   10:       public   virtual  ICollection<ActionSelector> GetSelectors();
   11:       public   virtual  FilterInfo GetFilters();    
   12:   
   13:       public   abstract   string  ActionName { get; }
   14:       public   abstract  ControllerDescriptor ControllerDescriptor { get; }
   15:       public   virtual   string  UniqueId { get; }
   16:  }

与ControllerDescriptor一样,ActionDescriptor同样实现了定义在ICustomAttributeProvider接口中的方法,我们可以通过相应的方法得到应用在Action方法上的相关特性,或者判断某个指定的特性是否应用在对应的Action方法上。GetFilterAttributes方法用于返回应用在Action方法上的所有筛选器特性。用于描述Action方法中所有参数的ParameterDescriptor数组通过方法GetParameters返回。 Action方法的执行可以直接通过调用方法Execute来完成 ,该方法的两个参数controllerContext和parameters分别代表Action方法执行所在的Controller上下文和传入的参数。

GetSelectors方法用于返回一组表示Action选择器的类型为 ActionSelector 的对象,而ActionSelector是一个委托类型。如下面的代码片断所示,ActionSelector委托具有唯一的类型为ControllerContext的参数,布尔类型的返回值表示目标Action方法是否与指定的Controller上下文相匹配。该方法默认返回的是一个空的ActionSelector集合。

    1:   public   delegate   bool  ActionSelector(ControllerContext controllerContext);

ActionDescriptor的GetFilters方法返回的是一个 FilterInfo 类型的对象,我们通过这个对象可以得到应用在该Action方法上所有的筛选器。如下面的代码所示,FilterInfo具有四个只读的集合属性,分别代码应用在该Action方法上的四种类型的筛选器(ActionFilter、AuthorizationFilter、ExceptionFilter和ResultFilter)。

    1:   public   class  FilterInfo
    2:  {
    3:       public  IList<IActionFilter>         ActionFilters { get; }
    4:       public  IList<IAuthorizationFilter>  AuthorizationFilters { get; }
    5:       public  IList<IExceptionFilter>      ExceptionFilters { get; }
    6:       public  IList<IResultFilter>         ResultFilters { get; }
    7:  }


二、AsyncActionDescriptor

异步版本的ActionDescriptor通过 AsyncActionDescriptor 类型表示,它用于描述定义在AsyncController中的异步方法。如下面的代码片断所示,AsyncActionDescriptor是一个继承自ActionDescriptor的抽象类,它重写了Execute方法,并且定义了两个用于异步执行Action方法的抽象方法 BeginExecute/EndExecute 。

    1:   public   abstract   class  AsyncActionDescriptor : ActionDescriptor
    2:  {
    3:       public   abstract  IAsyncResult BeginExecute( ControllerContext controllerContext, IDictionary< string ,  object > parameters, AsyncCallback callback,   object  state);
    4:       public   abstract   object  EndExecute(IAsyncResult asyncResult);
    5:       public   override   object  Execute(ControllerContext controllerContext,  IDictionary< string ,  object > parameters);
    6:  }

实际上AsyncActionDescriptor重写的Execute方法并没有实现任何Action方法执行的逻辑,而是直接抛出一个InvalidOperationException异常,意味用于 同步执行Action操作的Execute方法在这里无效 。

三、ReflectedActionDescriptor

上面我们介绍的ReflectedControllerDescriptor的FindAction和GetCanonicalActions方法返回的ActionDescriptor对象实际上是一个 ReflectedActionDescriptor 对象。顾名思义,ReflectedActionDescriptor针对Action方法元数据信息的解析同样通过针对目标方法成员的反射来实现。如下面的代码片断所示,ReflectedActionDescriptor直接继承自ActionDescriptor,表示Action名称、所在Controller的描述以及Action方法的只读属性ActionName、ControllerDescriptor和MethodInfo均在构造函数中初始化。

    1:   public   class  ReflectedActionDescriptor : ActionDescriptor
    2:  {   
    3:       public  ReflectedActionDescriptor(MethodInfo methodInfo,  string  actionName, ControllerDescriptor controllerDescriptor);    
    4:      
    5:       public   override   object [] GetCustomAttributes( bool  inherit);
    6:       public   override   object [] GetCustomAttributes(Type attributeType,   bool  inherit);
    7:       public   override   bool  IsDefined(Type attributeType,  bool  inherit);
    8:       public   override  IEnumerable<FilterAttribute> GetFilterAttributes(  bool  useCache);
    9:   
   10:       public   override  ParameterDescriptor[] GetParameters();
   11:       public   override   object  Execute(ControllerContext controllerContext, IDictionary< string ,  object > parameters);
   12:       public   override  ICollection<ActionSelector> GetSelectors();
   13:     
   14:       public   override   string  ActionName { get; }
   15:       public   override  ControllerDescriptor ControllerDescriptor { get; }
   16:       public  MethodInfo MethodInfo { get;}
   17:       public   override   string  UniqueId { get; }
   18:  }

ReflectedControllerDescriptor通过对应用在Action方法上所有特性的反射实现了定义在ICustomAttributeProvider接口中的三个方法。对于方法GetFilterAttributes返回的应用在Action方法上的筛选器特性,同样是通过相同的方式获得。

ReflectedControllerDescriptor重写了UniqueId属性,在现有的基础上将表示Action方法的MethodInfo对象作为了决定元素之一。也就是说,表示ReflectedControllerDescriptor对象唯一标识的UniqueId属性通过 自身的类型、Controller类型、Action名称和表示目标Action方法的MethodInfo对象四者派生 。

对于通过方法GetParameters返回的用于描述所有参数的ParameterDescriptor数组,也是通过对Action方法的参数列表进行反射来创建的。Execute方法最终传入参数列表调用MethodInfo对象执行Action方法。

ReflectedControllerDescriptor的GetSelectors返回的ActionSelector集合涉及到一个类型为 ActionMethodSelectorAttribute 的特性。ActionMethodSelectorAttribute特性应用于Action方法,会影响到通过ControllerDescriptor的FindAction方法实现的基于当前Controller上下文的Action方法的选择。如下面的代码片断所示,ActionMethodSelectorAttribute是一个抽象类型,其唯一的抽象方法IsValidForRequest用于判断目标Action方法是否与当前请求(即指定的Controller上下文)相匹配。

    1:  [AttributeUsage(AttributeTargets.Method, AllowMultiple =  false ,  Inherited =  true )]
    2:   public   abstract   class  ActionMethodSelectorAttribute : Attribute
    3:  {
    4:       public   abstract   bool  IsValidForRequest(ControllerContext controllerContext,  MethodInfo methodInfo);
    5:  }

在ASP.NET MVC应用编程接口中定义了如下四个基于HTTP方法(GET、POST、PUT和DELETE)的ActionMethodSelectorAttribute,当我们将它们应用到某个Action方法上时,只有在当前请求的HTTP方法与之相匹配的情况下目标Action方法才会被选择。

System.Web.Mvc.HttpGetAttribute System.Web.Mvc.HttpPostAttribute System.Web.Mvc.HttpPutAttribute System.Web.Mvc.HttpDeleteAttribute

除了上面四个基于某种HTTP方法的ActionMethodSelectorAttribute特性之外,还定义了一个 AcceptVerbsAttribute 特性。AcceptVerbsAttribute的不同之处在于它可以动态地指定一个或者多个匹配的HTTP方法。如下面的的代码片断所示,AcceptVerbsAttribute具有一个字符串集合类型的只读属性Verbs,用于表示目标Action方法支持的HTTP方法(HTTP Method又被称为HTTP Verb),该属性在构造函数中被初始化。

    1:  [AttributeUsage(AttributeTargets.Method, AllowMultiple= false , Inherited= true )]
    2:   public   sealed   class  AcceptVerbsAttribute : ActionMethodSelectorAttribute
    3:  {    
    4:       public  AcceptVerbsAttribute(HttpVerbs verbs);
    5:       public  AcceptVerbsAttribute( params   string [] verbs); 
    6:    
    7:       public   override   bool  IsValidForRequest(ControllerContext controllerContext,  MethodInfo methodInfo);
    8:       public  ICollection< string > Verbs { get;  }
    9:  }
   10:   
   11:  [Flags]
   12:   public   enum  HttpVerbs
   13:  {
   14:      Get     = 1,
   15:      Post    = 2,
   16:      Put     = 4,
   17:      Delete  = 8,
   18:      Head    = 16,
   19:  }

从上面的代码片断可以看出AcceptVerbsAttribute具有两个构造函数,其参数类型分别是 HttpVerbs 枚举和字符串数组,由于AcceptVerbsAttribute枚举应用了FlagsAttribute特性,我们可以使用操作符“|”指定多个HTTP方法。如下所示的两种应用AcceptVerbsAttribute的方式是等效的。顺便提一下,通过字符串指定的HTTP方式是不区分大小写的;实际上述的四个ActionMethodSelectorAttribute在内部使用了AcceptVerbsAttribute特性实现了具体的Action方法选择逻辑。

    1:   //使用HttpVerbs枚举表示HTTP方法 
    2:   public   class  ContactController
    3:  {
    4:      [AcceptVerbs(HttpVerbs.Put|HttpVerbs.Post|HttpVerbs.Delete)]
    5:       public  ActionResult UpdateContact(Contact contact)
    6:      { 
    7:           //省略实现 
    8:      }
    9:  }
   10:   
   11:   //使用字符串表示HTTP方法 
   12:   public   class  ContactController
   13:  {
   14:      [AcceptVerbs( "PUT" , "POST" , "DELETE" )]
   15:       public  ActionResult UpdateContact(Contact contact)
   16:      {
   17:           //省略实现 
   18:      }
   19:  }

除了上面5个基于HTTP方法的ActionMethodSelectorAttribute特性之外,还具有另一个具有如下定义的 NonActionAttribute 特性。顾名思义,应用了NonActionAttribute特性的方法将不会被认为是一个Action方法,所以在根据请求进行目标Action方法选择 的时候,这样的方法总是被排除在候选范围之内,所以IsValidForRequest方法直接返回False。

    1:  [AttributeUsage(AttributeTargets.Method, AllowMultiple =  false ,  Inherited =  true )]
    2:   public   sealed   class  NonActionAttribute : ActionMethodSelectorAttribute
    3:  {    
    4:       public   override   bool  IsValidForRequest(ControllerContext controllerContext,  MethodInfo methodInfo)
    5:      {
    6:           return   false ;
    7:      }
    8:  }


四、ReflectedAsyncActionDescriptor

异步的ReflectedControllerDescriptor由 ReflectedAsyncActionDescriptor 类型表示。它用于描述以XxxAsync/XxxCompleted方式定义的异步Action方法,所以一个ReflectedAsyncActionDescriptor对象通过代表着两个方法的MethodInfo对象来创建。如下面的代码片断所示,ReflectedAsyncActionDescriptor的构造的参数asyncMethodInfo和completedMethodInfo就代码这两个MethodInfo。在构造函数中初始化的这两个MethodInfo对象爱分别通过只读属性AsyncMethodInfo和CompletedMethodInfo返回。

    1:   public   class  ReflectedAsyncActionDescriptor : AsyncActionDescriptor
    2:  {    
    3:       public  ReflectedAsyncActionDescriptor(MethodInfo asyncMethodInfo,  MethodInfo completedMethodInfo,  string  actionName,  ControllerDescriptor controllerDescriptor);
    4:      
    5:       public   override  IAsyncResult BeginExecute(ControllerContext controllerContext, IDictionary< string ,  object > parameters, AsyncCallback callback,  object  state);
    6:       public   override   object  EndExecute(IAsyncResult asyncResult);
    7:   
    8:       public   override   object [] GetCustomAttributes( bool  inherit);
    9:       public   override   object [] GetCustomAttributes(Type attributeType,  bool  inherit);
   10:       public   override  IEnumerable<FilterAttribute> GetFilterAttributes(  bool  useCache);
   11:       public   override  ParameterDescriptor[] GetParameters();
   12:       public   override  ICollection<ActionSelector> GetSelectors();
   13:       public   override   bool  IsDefined(Type attributeType,  bool  inherit);
   14:   
   15:       public   override   string  ActionName { get; }
   16:       public  MethodInfo AsyncMethodInfo {  get;  }
   17:       public  MethodInfo CompletedMethodInfo {  get; }
   18:       public   override  ControllerDescriptor ControllerDescriptor { get; }
   19:       public   override   string  UniqueId { get; }
   20:  }

ReflectedAsyncActionDescriptor方法中用于相关特性(定义在ICustomAttributeProvider接口中的三个方法,用于获取筛选器特性列表的GetFilterAttributes方法以及GetSelectors方法对ActionMethodSelectorAttribute特性的解析)和参数描述(GetParameters方法)都是通过针对XxxAsync方法(即AsyncMethodInfo属性)的反射实现的。实现的BeginExecute/EndExecute最终对AsyncMethodInfo和CompletedMethodInfo的调用实现了对Action方法的异步执行。

五、TaskAsyncActionDescriptor

异步Action除了以配对的XxxAsync/XxxCompleted方法进行定义之外,还可以通过一个返回类型为 Task 的方法来定义,基于后者的Action描述通过类型 TaskAsyncActionDescriptor 表示。如下面的代码片断所示,TaskAsyncActionDescriptor具有一个名为TaskMethodInfo的只读属性,正是表示的这个基于Task的方法,该属性在构造函数中初始化。

    1:   public   class  TaskAsyncActionDescriptor : AsyncActionDescriptor
    2:  {   
    3:       public  TaskAsyncActionDescriptor(MethodInfo taskMethodInfo,  string  actionName, ControllerDescriptor controllerDescriptor);
    4:      
    5:       public   override  IAsyncResult BeginExecute(ControllerContext controllerContext, IDictionary< string ,  object > parameters, AsyncCallback callback,  object  state);
    6:       public   override   object  EndExecute(IAsyncResult asyncResult);
    7:       public   override   object  Execute(ControllerContext controllerContext, IDictionary< string ,  object > parameters);
    8:   
    9:       public   override   object [] GetCustomAttributes( bool  inherit);
   10:       public   override   object [] GetCustomAttributes(Type attributeType,  bool  inherit);
   11:       public   override  IEnumerable<FilterAttribute> GetFilterAttributes( bool  useCache);
   12:       public   override  ParameterDescriptor[] GetParameters();
   13:       public   override  ICollection<ActionSelector> GetSelectors();
   14:       public   override   bool  IsDefined(Type attributeType,  bool  inherit);
   15:   
   16:       public   override   string  ActionName { get; }
   17:       public   override  ControllerDescriptor ControllerDescriptor { get; }
   18:       public  MethodInfo TaskMethodInfo { get; }
   19:       public   override   string  UniqueId { get; }
   20:  }

TaskAsyncActionDescriptor对于涉及到特性和参数描述的方法都是通过针对TaskMethodInfo的反射来完成的。用于实现对Action操作的异步执行的BeginExecute/EndExecute通过Action方法返回的Task对象来完成(BeginExecute执行Action方法得到并异步执行Task,EndExecute方法获取Task执行的结果)。TaskAsyncActionDescriptor重写了Execute方法并在其中直接抛出异常。

ASP.NET MVC三个重要的描述对象:ControllerDescriptor  
ASP.NET MVC三个重要的描述对象:ActionDescriptor  
ASP.NET MVC三个重要的描述对象:ControllerDescriptor与ActionDescriptor的创建机制  
ASP.NET MVC三个重要的描述对象:ParameterDescriptor

 

分类:  [01] 技术剖析

作者: Leo_wl

    

出处: http://www.cnblogs.com/Leo_wl/

    

本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

版权信息

查看更多关于ASP.NET MVC三个重要的描述对象:ActionDescriptor的详细内容...

  阅读:44次

上一篇: 监视和调整硬件性能

下一篇:图片处理