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

简介:

ASP.NET MVC应用的请求都是针对某个Controller的某个Action方法,所以对请求的处理最终体现在对目标Action方法的执行。而Action方法具有相应的参数,所以在方法执行之前必须根据相应的规则从请求中提取相应的数据并将其转换为Action方法参数列表,我们将这个过程称为Model绑定。在ASP.NET MVC应用编程接口中,Action方法某个参数的元数据通过ParameterDescriptor表示,而两个相关的类型ControllerDescriptorActionDescriptor则用于描述Controller和Action方法。[本文已经同步到《How ASP.NET MVC Works?》中]

一、ControllerDescriptor

ControllerDescriptor包含了用于描述某个Controller的元数据信息。如下面的代码片断所示,ControllerDescriptor具有三个属性,其中ControllerName和ControllerType分别表示Controller的名称和类型,前者来源于路由信息;字符串类型的UniqueId表示ControllerDescriptor的唯一标识,该标识由自身的类型Controller的类型以及Controller的名称三者派生。

   1: public abstract class ControllerDescriptor : 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 ActionDescriptor FindAction(ControllerContext controllerContext, string actionName);
   9:      public abstract ActionDescriptor[] GetCanonicalActions();
  10:   
  11:     public virtual string ControllerName { get; }
  12:     public abstract Type ControllerType { get; }
  13:     public virtual string UniqueId { get; }
  14: }
  15:  
  16: public interface ICustomAttributeProvider
  17: {
  18:     object[] GetCustomAttributes(bool inherit);
  19:     object[] GetCustomAttributes(Type attributeType, bool inherit);
  20:     bool IsDefined(Type attributeType, bool inherit);
  21: }

ControllerDescriptor实现了ICustomAttributeProvider接口,意味着我们可以通过调用GetCustomAttributes和GetCustomAttributes方法获取应用在Controller类型上的所有自定义特性或者给定类型的特性,也可以调用IsDefined方法判断指定的自定义特性类型是否应用在对应的Controller类型上。

另一个方法GetFilterAttributes用于获取应用在Controller上的所有筛选器特性(继承自抽象类FilterAttribute)。筛选器是一种基于AOP的设计,它使我们可以一些基于横切关注点相关逻辑的执行动态的注入到Action方法的执行前后,我们会在“Action方法的执行”中对筛选器进行详细地介绍。

ControllerDescriptor的FindAction方法根据指定的Controller上下文和名称得到相应的Action方法,返回的是用于描述Action方法的ActionDescriptor对象。而GetCanonicalActions得到当前Controller的所有Action方法,返回类型为ActionDescriptor数组。

二、ReflectedControllerDescriptor

在ASP.NET MVC应用编程接口中定义了抽象类ControllerDescriptor的唯一继承类型ReflectedControllerDescriptor。顾名思义,ReflectedControllerDescriptor通过反射的机制解析用于描述Controller的元数据。如下面的代码片断所示,表示Controller类型的ControllerType属性在构造函数中指定。ReflectedControllerDescriptor通过反射的方式获取应用在Controller类型上的相关特性以提供针对ICustomAttributeProvider接口的实现。

   1: public class ReflectedControllerDescriptor : ControllerDescriptor
   2: {
   3:     public ReflectedControllerDescriptor(Type controllerType);
   4:    
   5:     public override object[] GetCustomAttributes(bool inherit);
   6:     public override object[] GetCustomAttributes(Type attributeType, bool inherit);
   7:     public override IEnumerable<FilterAttribute> GetFilterAttributes(bool useCache);
   8:     public override bool IsDefined(Type attributeType, bool inherit);
   9:  
  10:     public override ActionDescriptor FindAction( ControllerContext controllerContext, string actionName);
  11:     public override ActionDescriptor[] GetCanonicalActions();
  12:  
  13:     public sealed override Type ControllerType { get; }
  14: }

对于GetCanonicalActions方法返回的用于描述所有Action方法的ActionDescriptor数组,仅限于公有实例方法,但是从.Controller中继承下来的方法除外。当我们调用FindAction方法根据Action名称获取对应ActionDescriptor的时候,在默情况下会将方法名称视为Action名称进行匹配。如果方法上应用了具有如下定义的ActionNameSelectorAttribute特性,会传入相应的参数调用其IsValidName方法,如果该返回值为True,目标方法会被认为是匹配的Action方法。

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

顾名思义,抽象类ActionNameSelectorAttribute是一个用于辅助选择目标Action方法的特性,在ASP.NET MVC应用编程接口中具有一个类型为ActionNameAttribute的继承者。ActionNameAttribute特性应用于Action方法通过参数值指定一个Action别名,在实现的IsValidName方法中会比较指定的别名是否和当前的Action名称相匹配。如果具有不同 的Action选择规则,我们也可以通过自定义ActionNameSelectorAttribute特性的方式来实现。

   1: [AttributeUsage(AttributeTargets.Method, AllowMultiple=false, Inherited=true)]
   2: public sealed class ActionNameAttribute : ActionNameSelectorAttribute
   3: {    
   4:     public ActionNameAttribute(string name);
   5:     public override bool IsValidName(ControllerContext controllerContext, string actionName, MethodInfo methodInfo);
   6:     public string Name { get; }
   7: }

对于FindAction方法,如果找不到与指定Action名称的Action方法,则返回Null,而最终会导致一个状态码为404的HttpException异常的抛出;如果具有多个匹配的Action方法,则直接抛出AmbiguousMatchException异常。也就是说对于每一次请求,要求有且只有一个匹配的Action方法

三、ReflectedAsyncControllerDescriptor

ReflectedAsyncControllerDescriptor类型为ReflectedControllerDescriptor的异步版本。如下面的代码片断所示,ReflectedAsyncControllerDescriptor和ReflectedControllerDescriptor具有类似的成员定义,实际上除了FindAction和GetCanonicalActions两个方法,其他方法的实现逻辑(即对应用在Controller类型上的相关特性的解析)与ReflectedControllerDescriptor完全一致。

   1: public class ReflectedAsyncControllerDescriptor : ControllerDescriptor
   2: {  
   3:     public ReflectedAsyncControllerDescriptor(Type controllerType);
   4:     
   5:     public override object[] GetCustomAttributes(bool inherit);
   6:     public override object[] GetCustomAttributes(Type attributeType,  bool inherit);
   7:     public override IEnumerable<FilterAttribute> GetFilterAttributes( bool useCache);
   8:     public override bool IsDefined(Type attributeType, bool inherit);
   9:  
  10:     public override ActionDescriptor FindAction( ControllerContext controllerContext, string actionName);
  11:     public override ActionDescriptor[] GetCanonicalActions();
  12:   
  13:     public sealed override Type ControllerType { get; }
  14: }

ReflectedAsyncControllerDescriptor的GetCanonicalActions总是返回一个空的ActionDescriptor数组。对于继承自AsyncController的Controller类型,一个异步Action方法由两个匹配的方法({ActionName}Async和{ActionName}Completed)构成,ReflectedAsyncControllerDescriptor在根据指定的Action名称对方法成员进行匹配的时候会自动忽略掉方法名称的“Async”和“Completed”后缀。

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


作者:蒋金楠
微信公众账号:大内老A
微博: www.weibo.com/artech
如果你想及时得到个人撰写文章以及著作的消息推送,或者想看看个人推荐的技术资料,可以扫描左边二维码(或者长按识别二维码)关注个人公众号(原来公众帐号 蒋金楠的自媒体将会停用)。
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
相关文章
|
3月前
|
开发框架 前端开发 .NET
ASP.NET CORE 3.1 MVC“指定的网络名不再可用\企图在不存在的网络连接上进行操作”的问题解决过程
ASP.NET CORE 3.1 MVC“指定的网络名不再可用\企图在不存在的网络连接上进行操作”的问题解决过程
42 0
|
1月前
|
开发框架 前端开发 .NET
进入ASP .net mvc的世界
进入ASP .net mvc的世界
29 0
|
1月前
mvc.net分页查询案例——mvc-paper.css
mvc.net分页查询案例——mvc-paper.css
5 0
|
1月前
|
开发框架 前端开发 .NET
C# .NET面试系列六:ASP.NET MVC
<h2>ASP.NET MVC #### 1. MVC 中的 TempData\ViewBag\ViewData 区别? 在ASP.NET MVC中,TempData、ViewBag 和 ViewData 都是用于在控制器和视图之间传递数据的机制,但它们有一些区别。 <b>TempData:</b> 1、生命周期 ```c# TempData 的生命周期是短暂的,数据只在当前请求和下一次请求之间有效。一旦数据被读取,它就会被标记为已读,下一次请求时就会被清除。 ``` 2、用途 ```c# 主要用于在两个动作之间传递数据,例如在一个动作中设置 TempData,然后在重定向到另
100 5
|
1月前
|
XML 前端开发 Java
MVC 模式及对象持久化
MVC 模式及对象持久化
27 7
|
3月前
|
XML 前端开发 定位技术
C#(NET Core3.1 MVC)生成站点地图(sitemap.xml)
C#(NET Core3.1 MVC)生成站点地图(sitemap.xml)
25 0
|
3月前
|
前端开发
.net core mvc获取IP地址和IP所在地(其实是百度的)
.net core mvc获取IP地址和IP所在地(其实是百度的)
124 0
|
5月前
|
开发框架 自然语言处理 前端开发
基于ASP.NET MVC开发的、开源的个人博客系统
基于ASP.NET MVC开发的、开源的个人博客系统
52 0
|
8月前
|
存储 开发框架 前端开发
[回馈]ASP.NET Core MVC开发实战之商城系统(五)
经过一段时间的准备,新的一期【ASP.NET Core MVC开发实战之商城系统】已经开始,在之前的文章中,讲解了商城系统的整体功能设计,页面布局设计,环境搭建,系统配置,及首页【商品类型,banner条,友情链接,降价促销,新品爆款】,商品列表页面,商品详情等功能的开发,今天继续讲解购物车功能开发,仅供学习分享使用,如有不足之处,还请指正。
117 0
|
9月前
|
开发框架 前端开发 .NET
[回馈]ASP.NET Core MVC开发实战之商城系统(三)
[回馈]ASP.NET Core MVC开发实战之商城系统(三)
67 0