ASP.NET MVC的路由是MVC应用的一个核心也是MVC应用处理的入口,作为一个开发者,在正常情况下仅仅需要做的就是根据需求去定义实体、业务逻辑,然后在MVC的Controller中去调用、View中去展现,“路由”仅仅是定义一个路由表,使用户在点击一个链接时,应用能够命中正确的Controller、正确的Action并获取到正确的参数,使程序能够正常运行。

  但ASP.NET没有魔法,一个HTTP请求为什么能够被ASP.NET识别为MVC请求,而不是Web Page或者是静态资源文件?MVC的Controller又是如何被“正确选择”和执行的?本章将从以下几个方面来解释:

  ● ASP.NET 路由的主要参与对象
  ● ASP.NET MVC路由的注册
  ● UrlRoutingModule&MvcRouteHandler
  ● MvcHandler

ASP.NET 路由的主要参与对象

  之前介绍过ASP.NET应用中有一个全局路由表并且是在System.Web.Routing命名空间下的RouteCollection类型:

  

  从这个代码定义可以找到3个重要的对象,分别是RouteBase、RouteData以及VirtualPathData,对于其他的RouteValueDictionary被包含在RouteData中,Route是继承至RouteBase所以直接把它们归在着3个类型中介绍。

  1. RouteBase&Route:

  Route是整个路由机制的核心对象,当注册路由时就是将该对象注册到路由表中,以下是RouteBase的定义:

  

  Route的定义:

  

  它的核心方法就是GetRouteData和GetVirtualPath,并且参数分别是HttpContextBase和RequestContext,换句话说,Route对象的作用就是抓取请求上下文中的数据。并返回RouteData和VirtualPathData两个类型。

  Route仅仅是对其基类增加了一些附加属性,如Constraints、DataTokens、Defaults、Route Handler等。而其中Constraints和Defaults都是可以通过注册路由的方法以参数的形式传入,而RouteHandler等内容则是被硬编码的,比如System.Web.Mvc命名空间下的拓展方法MapRoute:

  

  IRouteHandler是针对每一个路由的处理器,而MVC的路由处理器是在注册路由时创建的:

  

  2. RouteData:

    

  RouteData是用于包装关于路由的信息:
  ● DataTokens:包含了自定义的一个键值对字典,这个最终会传到RouteHandler中使用(如从反编译的MapRoute方法中可以看到,命名空间信息是放到DataTokens里面的),但这个字典的数据不会参与路由匹配。
  ● Route:代表一个路由对象,RouteData通过Route对象的GetRouteData获得,而这里的Route对象就是获得RouteData的那个Route对象。
  ● RouteHandler:处理当前请求的处理器,在MVC中默认是MvcRouteHandler。
  ● Values:它也是一个键值对字典,只不过它只包含URL参数和默认值,它会参与路由匹配(这里就解释了为什么在注册路由时url模板没有action,但是默认参数中存在时,默认action可以被路由到)。

  GetRequiredString:该方法是传入一个字符串,然后通过这个字符串去Values属性中查找是否存在这个Key,如果存在那么返回值,否则抛出System.InvalidOperationException异常。比如在MVC中必须存在Controller和Action,如果不存在则抛异常。

  以下是RouteData的创建代码,可以看到RouteData的属性都来至于用于创建它的Route对象:

  

  3. VirtualPathData:  

  

  它表示一个虚拟路径并包含路由信息,虚拟路径是URL模板通过RouteData.Values中的变量将变量占位符替换后的结果,DataTokens与RouteData中的DataTokens作用一致。

  以下是创建VirtualPathData的代码:

  

ASP.NET MVC路由的注册

  路由的注册就是将Route对象添加到路由表的过程,以下代码就是MVC路由注册的代码,其核心在于把Route的处理器设置为MvcRouteHandler。

  

  而ASP.NET MVC程序的路由注册有两个步骤,这两个步骤都是在Application_Start()方法中完成的:

  

  1. 调用AreaRegistration.RegisterAllAreas方法在所有引用程序集中查找所有继承至AreaRegistration的类型,并调用该类型的RegisterArea方法将路由注册到路由表中。

  2. 调用RouteConfig.RegisterRoutes方法将项目中定义的路由信息注册到路由表中。

UrlRoutingModule

  在之前的文章中介绍过IIS是通过HttpModule来对ASP.NET的程序完成管道拓展的(ASP.NET没有魔法——ASP.NET MVC是如何运行的?它的生命周期是什么?),而路由的处理其实也是一个Module,UrlRoutingModule就是负责处理路由的Module,它在systemroot\Microsoft .NET\Framework\versionNumber\Config\web.config文件中被注册到管道中:

  

  UrlRoutingModule的处理逻辑:

  

  1. 匹配路由,RouteCollection的GetRouteData方法实际上是去遍历所有Route对象,然后调用Route对象的GetRouteData方法,如果返回不会null,则表面匹配成功。

  2. 通过Route获取RouteHandler。

  3. 通过RouteHandler获取HttpHandler。

  4. 将请求重新映射到HttpHandler。

  以上过程中的1、2点根据上面的分析可知,通过url匹配到的MVC路由中包含一个MvcRouteHandler,那么通过MvcRouteHandler获取的HttpHandler是什么呢?

MvcRouteHandler

  由名称可知,MvcRouteHandler就是MVC路由的处理器,并且由上面的分析可知,路由处理器最主要的是获取一个HttpHandler,那么MVC获取的HTTP处理器是什么?

  

  代码非常简单,仅仅是处理了Session行为(关于MVC中的Session会在后续章节中介绍),然后就创建了一个名为MvcHandler的IHttpHandler类型。

MvcHandler

  MvcHandler实现了IHttpHandler和IHttpAsyncHandler,它们分别表示ASP.NET中同步、异步处理Http请求的处理器。意图很明显就是用于处理MVC的HTTP请求。

  以下是MvcHandler处理请求的同步方法:

    

  上面代码有做了以下几件事:
  1. 根据httpContext初始化controller和controllerFactory。
  2. 执行controller。
  3. 释放controller。

小结

  本章节主要是对与路由相关的重要对象和方法进行了分析介绍,简单来说整个过程就是:
  1. 注册路由,将所有路由信息添加到RouteCollection类型的路由表中。
  2. Http请求被UrlRoutingModule处理时,UrlRoutingModule通过RouteCollection的GetRouteData的方法匹配并返回命中的路由对象。
  3. 然后UrlRoutingModule通过Route对象获取对应的IRouteHandler实际类型(MVC中是MvcRouteHandler)。
  4. 最后UrlRoutingModule通过IRouteHandler实际类型获取实际的IHttpHandler(MVC中是MvcHandler),把请求转到IHttpHandler来处理。
  5. MvcHandler根据Http上下文来初始化Controller并完成执行。
  
至此已经了解了一个HTTP请求是如何路由到MvcRouteHandler并转交给MvcHandler处理的,MvcHandler完成了Controller的创建、执行、销毁工作,后续将对MvcHandler与路由的关系以及如何初始化及执行过程进一步分析。

本文地址:http://www.cnblogs.com/selimsong/p/7661399.html

ASP.NET没有魔法——目录

ASP.NET没有魔法——ASP.NET MVC 路由的匹配与处理的更多相关文章

  1. ASP.NET没有魔法——ASP.NET MVC使用Oauth2.0实现身份验证

    随着软件的不断发展,出现了更多的身份验证使用场景,除了典型的服务器与客户端之间的身份验证外还有,如服务与服务之间的(如微服务架构).服务器与多种客户端的(如PC.移动.Web等),甚至还有需要以服务的 ...

  2. ASP.NET没有魔法——ASP.NET MVC Razor与View渲染

    对于Web应用来说,它的界面是由浏览器根据HTML代码及其引用的相关资源进行渲染后展示给用户的结果,换句话说Web应用的界面呈现工作是由浏览器完成的,Web应用的原理是通过Http协议从服务器上获取到 ...

  3. ASP.NET没有魔法——ASP.NET MVC Razor与View渲染 ASP.NET没有魔法——ASP.NET MVC界面美化及使用Bundle完成静态资源管理

    ASP.NET没有魔法——ASP.NET MVC Razor与View渲染   对于Web应用来说,它的界面是由浏览器根据HTML代码及其引用的相关资源进行渲染后展示给用户的结果,换句话说Web应用的 ...

  4. ASP.NET没有魔法——ASP.NET MVC 与数据库大集合

    ASP.NET没有魔法——ASP.NET与数据库 ASP.NET没有魔法——ASP.NET MVC 与数据库之MySQL ASP.NET没有魔法——ASP.NET MVC 与数据库之ORM ASP.N ...

  5. ASP.NET没有魔法——ASP.NET MVC IoC

    之前的文章介绍了MVC如何通过ControllerFactory及ControllerActivator创建Controller,而Controller又是如何通过ControllerBase这个模板 ...

  6. ASP.NET没有魔法——ASP.NET MVC 过滤器(Filter)

    上一篇文章介绍了使用Authorize特性实现了ASP.NET MVC中针对Controller或者Action的授权功能,实际上这个特性是MVC功能的一部分,被称为过滤器(Filter),它是一种面 ...

  7. ASP.NET没有魔法——ASP.NET MVC 模型绑定解析(下篇)

    上一篇<ASP.NET没有魔法——ASP.NET MVC 模型绑定解析(上篇)>文章介绍了ASP.NET MVC模型绑定的相关组件和概念,本章将介绍Controller在执行时是如何通过这 ...

  8. ASP.NET没有魔法——ASP.NET 身份验证与Identity

    前面的文章中为My Blog加入了文章的管理功能(ASP.NET没有魔法——ASP.NET MVC使用Area开发一个管理模块),但是管理功能应该只能由“作者”来访问,那么要如何控制用户的访问权限?也 ...

  9. ASP.NET没有魔法——ASP.NET Identity 的“多重”身份验证

    ASP.NET Identity除了提供基于Cookie的身份验证外,还提供了一些高级功能,如多次输入错误账户信息后会锁定用户禁止登录.集成第三方验证.账户的二次验证等,并且ASP.NET MVC的默 ...

随机推荐

  1. 配置VNC SERVER 远程访问

    1.安装软件包 # yum install tigervnc-server -y 2. 配置VNC用户 # vim /etc/sysconfig/vncservers VNCSERVERS=" ...

  2. 201521123091 《Java程序设计》第2周学习总结

    Java 第二周总结 第二周的作业. 一个简陋的目录 1.本章学习总结 2.Java Q&A 3.使用码云管理Java代码 4.PTA实验 5.小任务 1.本章学习总结 基本数据类型 Stri ...

  3. 第一周作业.四则运算生成器(基于python)

    题目 从<构建之法>第一章的 "程序" 例子出发,像阿超那样,花二十分钟写一个能自动生成小学四则运算题目的命令行 "软件",满足以下需求: 除了整数 ...

  4. 201521123011 《java程序设计》 第9周学习总结

    1. 本周学习总结 1.1 以你喜欢的方式(思维导图或其他)归纳总结异常相关内容. 2. 书面作业 本次PTA作业题集异常 1.常用异常 题目5-1 1.1 截图你的提交结果(出现学号) 1.2 自己 ...

  5. JAVA课程设计+五子棋(团队博客)

    JAVA课程设计 利用所学习的JAVA知识设计一个五子棋小游戏 1.团队名称.团队成员介绍(菜鸟三人组) 杨泽斌[组长]:201521123049 网络1512 叶文柠[组员]:20152112305 ...

  6. 201521123027<java程序设计>第14周作业总结

    1.本周作业总结 1.1 以你喜欢的方式(思维导图或其他)归纳总结多数据库相关内容. 2.书面作业 Q1. MySQL数据库基本操作 建立数据库,将自己的姓名.学号作为一条记录插入.(截图,需出现自己 ...

  7. Java:extends和implements的区别+用法

    Java代码中的extends和implements让我感到很迷惑,现在终于弄明白它们之间的区别和用法了. [c-sharp] view plain copy //定义一个Runner接口 publi ...

  8. ROS学习记录(四)————怎样建立一个package包?

    功能包是什么? 英文表述package,我可没有在炫英文啊,我的英文很烂的,只是在提醒大家,在ROS系统中,这个词使用的频率非常之高,你必须记住它,要不就没法正确的看懂信息.言归正传,package是 ...

  9. 语句的分号、逗号和函数中var的使用

    1语句 分号 语句的结尾的分号不是必须的,但建议不要省略它,避免错误. 2逗号 1同时定义多个变量用逗号分开 2数组的最后一位,建议不要加上逗号,在有的浏览器中会导致,在逗号后添加一个undefine ...

  10. 归纳一下input中span提示以及input中onchange事件

    一.当input中不含有onclick事件的时候 定义一个class为tip1的span: <td><input  type=text name='POSTNAME' nameVal ...