之前对Controller创建的分析中,知道了Controller的创建是有两个步骤组成,分别是Controller的类型查找以及根据类型创建Controller实例。
在查询Controller的类型时,实际上是通过RouteData中的Controller名称和命名空间来完成匹配和查找的,而Controller的名称就根据路由对象中的url模板来获取,如默认的url模板:"{controller}/{action}/{id}"。以下是根据ControllerName查找Controller类型的方法,需要注意的是,在通过Controller名称查找之前还有一个判断,当RouteData不为空且被匹配为直连路由时,会通过另外的逻辑使用RouteData获取一个Controller类型。代码如下:
DirectRoute是什么?本章将从以下几点介绍直连路由相关内容:
● 什么是直连路由
● 如何在MVC中使用直连路由
● 直连路由与约定路由的区别
● 为什么使用直连路由
什么是直连路由
直连路由又称为特性路由(Attribute Routing),因为它是通过特性的方式将路由的匹配模板直接应用到Action方法上。如下图代码中的action需要使用http://XXX/dr/test才能够正常访问:
其中Route特性的定义如下:
从其定义可以看出Route特性可以应用在Controller以及Action上。通过Route特性可以直接为action指定路由。
那么对于程序来说什么是直连路由呢?从最初给出的代码来看,代码层面是通过RouteData.HasDirectRouteMatch方法来判断的,下图是判断逻辑,非常简单仅仅判断Value中是否包含名称为“MS_DirectRouteMatches”的Key值。换句话说,RouteData中包含“MS_DirectRouteMatches”这个Key值的就是直连路由。
如何在MVC中使用直连路由
ASP.NET MVC中有一个对路由表的拓展对象RouteCollectionAttributeRoutingExtensions,其定义如下图所示,它的功能就是将当前应用中使用特性定义的路由注册到路由表中。
所以在注册路由时加入以下代码即可:
在项目中添加以下测试代码:
运行程序后可以看到dr/test以及dr/test2均被添加到路由表中:
并且在对应的路由信息中包含了Controller和action的信息:
注:此处添加了三条路由信息,其中一条它的值是一个RouteCollectionRoute类型,就是说该路由表又包含了一个路由表,被包含的这个路由表中的路由信息是该程序中所有被Route特性标记的Action生成的,另外的两个LinkGenerationRoute也是通过特性生成的路由。换句话说一个特性标记会生成两条路由信息,但为什么一个特性标记会在两个路由表中都插入路由对象本章节不再深入分析。
以下内容更新于2017-12-4:
关于RouteCollectionRoute和LinkGenerationRoute:其中RouteCollectionRoute是一个专门保存特性路由的路由集合(表),在匹配路由时将会调用RouteCollectionRoute.GetRouteData来完成特性路由匹配,但是要注意的是这里的匹配和路由表中的不同,路由表做的仅仅是遍历每一个路由对象,并调用路由对象的GetRouteData方法,而RouteCollectionRoute除了遍历匹配外,还对每一个匹配成功的路由对象添加了“MS_DirectRouteMatches”标记:
但是RouteCollectionRoute的GetVirtualPath方法返回的是null,就是说通过RouteCollectionRoute无法对特性路由生成链接,所以又为每一个特性路由在路由表中注册了LinkGenerationRoute专门用于链接的生成,但同样的LinkGenerationRoute不参与路由匹配,它的GetRouteData返回null:
RouteCollectionRoute的GetVirtualPath方法:
LinkGenerationRoute的GetRouteData方法:
再次感谢 浮云也是种寂寞 让我发现了问题。(*^_^*)
关于如何在直连路由中使用默认值、路由前缀、默认路由、路由约束、直连路由的Area等功能可参考这篇文章:https://blogs.msdn.microsoft.com/webdev/2013/10/17/attribute-routing-in-asp-net-mvc-5/
直连路由与约定路由的区别
相对于直连路由来说,使用Controller和Action匹配的路由被称为基于约定的路由,因为请求url中携带了约定好的Controller和Action的名称。它们的区别主要有以下几点:
1. 直连路由与约定路由,路由的注册方式不同,前者通过查找所有Controller类型中是否使用Route特性来创建路由。后者通过在配置文件中自行添加。
2. 直连路由在注册时将对应的Controller和Action的信息包含到了Route对象中,而约定的路由是在解析时通过url模板匹配获得Controller和Action信息。
3. 当Action被Route特性标记后,Controller的类型查找不再会通过基于约定的路由的Controller类型查找逻辑。
4. 当Action被Route特性标记后并且项目中使用了基于约定的路由,那么使用基于约定的路由方法是访问不到被标记的action的,因为查找Action的逻辑中它们两种路由是分开的:
5. 直连路由请求中的RouteData自动添加了MS_DirectRoute相关的值,如下:
为什么使用直连路由
直连路由最主要的特性就是路由与实际代码在同一个文件里,这样在代码阅读时更容易将路由与实际的Action进行匹配,另外使用直连路由可以根据实际的需求来“创造”一个更符合需求的url“新约定”,同时也可以避免基于约定的路由对代码内部实现的暴露。
小结
本章通过在MVC的源码中发现两种不同的Controller、Action处理方式引出了直连路由的概念,实际上这是MVC5中加入的新特性,可以使用特性的方式指定对应的action的路由模板。但要注意的是尽量避免两种路由方式的混用造成代码混乱。
参考:
https://blogs.msdn.microsoft.com/webdev/2013/10/17/attribute-routing-in-asp-net-mvc-5/