ASP.NET MVC ActionDescriptor对象

  在Model绑定过程中会通过激活的Controller类型创建用于描述它的 ControllerDescriptor对象。Controller是一组Action方法的集合,而每一个Action通过 ActionDescriptor对象来表示,在这篇文章中我们就来着重谈谈不同类型的ActionDescriptor。

一、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集合。

 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方法并在其中直接抛出异常。

作者:Artech
出处:http://artech.cnblogs.com/

加支付宝好友偷能量挖...


评论(0)网络
阅读(110)喜欢(0)asp.net-mvc