今天我来缕一下MVC的路由机制,因为使用MVC已经快一年了,之前也只是上手,没有系统去理会。项目完了,结合实际使用,回过头来深入一下。

MVC 学习索引(点击即可)

一个请求进入IIS后

传统ASP.NET 路由部分

1、IIS根据文件类型将请求转交给相应的处理程序,如果属于ASP.NET文件,则将请求转发给aspnet_isapi.dll。(注:在II6和IIS7上的处理方式是有区别的)

2、 HTTP处理模块UrlRoutingModule接收到请求后,循环调用其RouteCollection集合中的RouteBase对象,找出匹配的RouteBase。

3、根据匹配的RouteBase对象返回的RoueData对象,获取RouteHandler。

4、RouteHandler返回一个HTTP处理程序(IHttpHandler),最终通过此处理程序处理请求,生成应答内容。

5.、如果RouteHandler为MvcRouteHandler,并且其返回的HTTP处理程序为MvcHandler,则进入到MVC框架,MvcHandler对象负责调用适当的控制器和活动方法,生成应答内容。

MVC 路由部分 

关键类说明

1、UrlRoutingModule类

此类事路由系统的核心类,其主要功能是根据请求上下文找出合适的RouteBase对象。属性RouteCollection是一个RouteBase对象集合,UrlRoutingModule接收到请求后,循环RouteCollection集合中的RouteBase对象,调用其GetRouteData方法,如果该方法返回的RouteData对象不为null,则终止循环,将RouteData对象存入RequestContext。然后根据RouteData的RouteHandler获取合适的IHttpHandler处理程序。

UrlRoutingModule实际上是一个ASP.NET的HTTP 处理模块,所以它通过配置文件的<httpMoudles>配置节点来添加的。

2、RouteTable类

用于存储应用程序的路由集合,静态属性Routes返回应用程序的路由集合,它实际等同于UrlRoutingModule的RouteCollection属性。通过RouteTable.Routes.Add方法可以添加自定义的RouteBase对象。

3、RouteBase类

表示一个ASP.NET路由的基类[System.Web.Routing],所有的路由都应该继承自此类。

 GetRouteData方法检查传入的HttpContextBase信息是否符合路由规则,符合则返回一个RouteData对象,不符合则返回null,此方法由UrlRoutingModule类在循环RouteTable.Routes集合时调用。

GetVirtualPath方法根据路由数据生成相应的Url。

4、Route类

是RouteBase的一个实现,主要添加了几个属性:

Constraints: 对URL的约束条件

DataTokens:传递到路由处理程序的自定义值

Defaults:Url不包含指定参数时得默认值

RouteHandler:一个路由处理程序(IRouteHandler)

5、IRouteHandler接口

路由处理程序接口,包含一个GetHttpHandler方法,用于返回一个IHttpHandler处理程序对象。

6、MvcRouteHandler类

Mvc框架实现的一个路由处理程序,其GetHttpHandler方法返回一个MvcHandler对象

  1. #region IRouteHandler Members
  2. IHttpHandler IRouteHandler.GetHttpHandler(RequestContext requestContext) {
  3. return GetHttpHandler(requestContext);
  4. }
  5. #endregion

7、MvcHandler

由MvcRouteHandler返回,根据请求信息,调用合适的控制器和方法,生成应答内容。

  1. public class MvcHandler : IHttpAsyncHandler, IHttpHandler, IRequiresSessionState {
  2. private static readonly object _processRequestTag = new object();
  3. private ControllerBuilder _controllerBuilder;
  4. internal static readonly string MvcVersion = GetMvcVersionString();
  5. public static readonly string MvcVersionHeaderName = "X-AspNetMvc-Version";
  6. public MvcHandler(RequestContext requestContext) {
  7. if (requestContext == null) {
  8. throw new ArgumentNullException("requestContext");
  9. }
  10. RequestContext = requestContext;
  11. }
  12. internal ControllerBuilder ControllerBuilder {
  13. get {
  14. if (_controllerBuilder == null) {
  15. _controllerBuilder = ControllerBuilder.Current;
  16. }
  17. return _controllerBuilder;
  18. }
  19. set {
  20. _controllerBuilder = value;
  21. }
  22. }
  23. public static bool DisableMvcResponseHeader {
  24. get;
  25. set;
  26. }
  27. protected virtual bool IsReusable {
  28. get {
  29. return false;
  30. }
  31. }
  32. public RequestContext RequestContext {
  33. get;
  34. private set;
  35. }
  36. protected internal virtual void AddVersionHeader(HttpContextBase httpContext) {
  37. if (!DisableMvcResponseHeader) {
  38. httpContext.Response.AppendHeader(MvcVersionHeaderName, MvcVersion);
  39. }
  40. }
  41. protected virtual IAsyncResult BeginProcessRequest(HttpContext httpContext, AsyncCallback callback, object state) {
  42. HttpContextBase iHttpContext = new HttpContextWrapper(httpContext);
  43. return BeginProcessRequest(iHttpContext, callback, state);
  44. }
  45. protected internal virtual IAsyncResult BeginProcessRequest(HttpContextBase httpContext, AsyncCallback callback, object state) {
  46. return SecurityUtil.ProcessInApplicationTrust(() => {
  47. IController controller;
  48. IControllerFactory factory;
  49. ProcessRequestInit(httpContext, out controller, out factory);
  50. IAsyncController asyncController = controller as IAsyncController;
  51. if (asyncController != null) {
  52. // asynchronous controller
  53. BeginInvokeDelegate beginDelegate = delegate(AsyncCallback asyncCallback, object asyncState) {
  54. try {
  55. return asyncController.BeginExecute(RequestContext, asyncCallback, asyncState);
  56. }
  57. catch {
  58. factory.ReleaseController(asyncController);
  59. throw;
  60. }
  61. };
  62. EndInvokeDelegate endDelegate = delegate(IAsyncResult asyncResult) {
  63. try {
  64. asyncController.EndExecute(asyncResult);
  65. }
  66. finally {
  67. factory.ReleaseController(asyncController);
  68. }
  69. };
  70. SynchronizationContext syncContext = SynchronizationContextUtil.GetSynchronizationContext();
  71. AsyncCallback newCallback = AsyncUtil.WrapCallbackForSynchronizedExecution(callback, syncContext);
  72. return AsyncResultWrapper.Begin(newCallback, state, beginDelegate, endDelegate, _processRequestTag);
  73. }
  74. else {
  75. // synchronous controller
  76. Action action = delegate {
  77. try {
  78. controller.Execute(RequestContext);
  79. }
  80. finally {
  81. factory.ReleaseController(controller);
  82. }
  83. };
  84. return AsyncResultWrapper.BeginSynchronous(callback, state, action, _processRequestTag);
  85. }
  86. });
  87. }
  88. protected internal virtual void EndProcessRequest(IAsyncResult asyncResult) {
  89. SecurityUtil.ProcessInApplicationTrust(() => {
  90. AsyncResultWrapper.End(asyncResult, _processRequestTag);
  91. });
  92. }
  93. private static string GetMvcVersionString() {
  94. // DevDiv 216459:
  95. // This code originally used Assembly.GetName(), but that requires FileIOPermission, which isn't granted in
  96. // medium trust. However, Assembly.FullName *is* accessible in medium trust.
  97. return new AssemblyName(typeof(MvcHandler).Assembly.FullName).Version.ToString(2);
  98. }
  99. protected virtual void ProcessRequest(HttpContext httpContext) {
  100. HttpContextBase iHttpContext = new HttpContextWrapper(httpContext);
  101. ProcessRequest(iHttpContext);
  102. }
  103. protected internal virtual void ProcessRequest(HttpContextBase httpContext) {
  104. SecurityUtil.ProcessInApplicationTrust(() => {
  105. IController controller;
  106. IControllerFactory factory;
  107. ProcessRequestInit(httpContext, out controller, out factory);
  108. try {
  109. controller.Execute(RequestContext);
  110. }
  111. finally {
  112. factory.ReleaseController(controller);
  113. }
  114. });
  115. }
  116. private void ProcessRequestInit(HttpContextBase httpContext, out IController controller, out IControllerFactory factory) {
  117. // If request validation has already been enabled, make it lazy. This allows attributes like [HttpPost] (which looks
  118. // at Request.Form) to work correctly without triggering full validation.
  119. bool? isRequestValidationEnabled = ValidationUtility.IsValidationEnabled(HttpContext.Current);
  120. if (isRequestValidationEnabled == true) {
  121. ValidationUtility.EnableDynamicValidation(HttpContext.Current);
  122. }
  123. AddVersionHeader(httpContext);
  124. RemoveOptionalRoutingParameters();
  125. // Get the controller type
  126. string controllerName = RequestContext.RouteData.GetRequiredString("controller");
  127. // Instantiate the controller and call Execute
  128. factory = ControllerBuilder.GetControllerFactory();
  129. controller = factory.CreateController(RequestContext, controllerName);
  130. if (controller == null) {
  131. throw new InvalidOperationException(
  132. String.Format(
  133. CultureInfo.CurrentCulture,
  134. MvcResources.ControllerBuilder_FactoryReturnedNull,
  135. factory.GetType(),
  136. controllerName));
  137. }
  138. }
  139. private void RemoveOptionalRoutingParameters() {
  140. RouteValueDictionary rvd = RequestContext.RouteData.Values;
  141. // Get all keys for which the corresponding value is 'Optional'.
  142. // ToArray() necessary so that we don't manipulate the dictionary while enumerating.
  143. string[] matchingKeys = (from entry in rvd
  144. where entry.Value == UrlParameter.Optional
  145. select entry.Key).ToArray();
  146. foreach (string key in matchingKeys) {
  147. rvd.Remove(key);
  148. }
  149. }
  150. #region IHttpHandler Members
  151. bool IHttpHandler.IsReusable {
  152. get {
  153. return IsReusable;
  154. }
  155. }
  156. void IHttpHandler.ProcessRequest(HttpContext httpContext) {
  157. ProcessRequest(httpContext);
  158. }
  159. #endregion
  160. #region IHttpAsyncHandler Members
  161. IAsyncResult IHttpAsyncHandler.BeginProcessRequest(HttpContext context, AsyncCallback cb, object extraData) {
  162. return BeginProcessRequest(context, cb, extraData);
  163. }
  164. void IHttpAsyncHandler.EndProcessRequest(IAsyncResult result) {
  165. EndProcessRequest(result);
  166. }
  167. #endregion
  168. }

值得一提的是,在MVC3中已经实现异步处理(IHttpAsyncHandler)

8、StopRoutingHandler类

表示一个“不处理URL的路由处理类”,  比如MVC在RouteCollection类型上扩展了一个IgnoreRoute方法,用于指示路由系统忽略处理指定的url。其实现方式是生成一个Route对象,指定其RouteHandler属性为一个StopRoutingHandler对象。

9、IRouteConstraint接口

用于构建Route.Constraints属性,表示一个约束条件。Match方法用于检查url是否符合路由规则,符合返回true,否则false。

MVC路由机制(转)的更多相关文章

  1. WebApi-1 与MVC路由机制比较

    在MVC里面,默认路由机制是通过url路径去匹配对应的action方法 public class RouteConfig { public static void RegisterRoutes(Rou ...

  2. MVC路由机制

      按照传统,在很多Web框架中(如经典的ASP.JSP.PHP.ASP.NET等之类的框架),URL代表的是磁盘上的物理文件.例如,当看到请求http://example.com/albums/li ...

  3. asp.net MVC 路由机制

    1:ASP.NET的路由机制主要有两种用途: -->1:匹配请求的Url,将这些请求映射到控制器 -->2:选择一个匹配的路由,构造出一个Url 2:ASP.NET路由机制与URL重写的区 ...

  4. asp.net MVC 路由机制 Route

    1:ASP.NET的路由机制主要有两种用途: -->1:匹配请求的Url,将这些请求映射到控制器 -->2:选择一个匹配的路由,构造出一个Url 2:ASP.NET路由机制与URL重写的区 ...

  5. Asp.net MVC路由机制

    C:/Windows/Microsoft.NET/Framwork/v4.0.30319/config/web.config-> httpModules-> System.Web.Rout ...

  6. C# 通过反射实现类似MVC路由的机制

    最近封装了个功能非常类似于MVC的路由.//MVC路由机制先找到Controller Action 什么是反射 反射(Reflection)是.NET中的重要机制,通过放射,可以在运行时获 得.NET ...

  7. C#进阶系列——WebApi 路由机制剖析:你准备好了吗?

    前言:从MVC到WebApi,路由机制一直是伴随着这些技术的一个重要组成部分. 它可以很简单:如果你仅仅只需要会用一些简单的路由,如/Home/Index,那么你只需要配置一个默认路由就能简单搞定: ...

  8. 【C#】 WebApi 路由机制剖析

    C#进阶系列——WebApi 路由机制剖析:你准备好了吗? 转自:https://blog.csdn.net/wulex/article/details/71601478 2017年05月11日 10 ...

  9. C#进阶系列——WebApi 路由机制剖析:你准备好了吗? 转载https://www.cnblogs.com/landeanfen/p/5501490.html

    阅读目录 一.MVC和WebApi路由机制比较 1.MVC里面的路由 2.WebApi里面的路由 二.WebApi路由基础 1.默认路由 2.自定义路由 3.路由原理 三.WebApi路由过程 1.根 ...

随机推荐

  1. JMeter学习笔记--JMeter执行顺序规则

    JMeter执行顺序规则: 配置元件 前置处理器 定时器 采样器 后置处理器(除非服务器响应为空) 断言 监听器 只有当作用域内存在采样器时,定时器.断言.前置/后置处理器才会被执行,逻辑控制器和采样 ...

  2. atcoder之A Great Alchemist

    C - A Great Alchemist Time limit : 2sec / Stack limit : 256MB / Memory limit : 256MB Problem Carol i ...

  3. mysql 返回多列的方式

    SELECT * FROM (SELECT 'success' as _result) a,(SELECT @gid as gid) b;

  4. DOA——MUSIC算法

    一.均匀圆阵(UCA, Uniform Circular Array)的MUSIC算法 假设一个半径为R的M元均匀圆阵的所有阵元均位于坐标系X-Y平面内,第k-1个阵元坐标为,第i个窄带信号波长为,来 ...

  5. 今天遇到的一个bug,折腾了一早上,不过解决了,还是很高兴

    1.总结出错的问题 当我在用flask做项目的时候,需要创建表,创建表的时候,我用的是Flask-Migrate组件,直接用python manage.py init ,python manage.p ...

  6. Azure 怎么开通FTP

    1. 需要在Azure Portal设置端口:21, 1035, 1036, 1037,1038,1039,1040 2. 需要内网放开端口:21, 1035, 1036, 1037,1038,103 ...

  7. WIN10中运行ASP出错

    一个项目用ASP做的,想在WIN中IIS建立网站部署起来,开始怎么弄都不行,运行总是出现那句英文,后来才知道要在IIS中的网站的ASP选项中的调试属性中把发送错误到到浏览器打开,这样才能发现程序报错, ...

  8. 在verilog中调用VHDL模块

    习惯了自己发现一些小问题,既然发现了,就记下来吧,不然又要忘了,这是多么悲痛的领悟. 今天在用vivado进行块设计时所生成的顶层模块居然是用VHDL语言描述的,这时郁闷了,表示只看过VHDL语法但没 ...

  9. 日期时间函数(1)-time()&gmtime()&strftime()&localtime()

    ◆time() 取得当前时间.此函数会返回从公元1970年1月1日的UTC时间从0时0分0秒算起到现在所经过的秒数.如果参数t为非空指针的话, 此函数也会将返回值存到t指针所指的内存. 成功则返回秒数 ...

  10. LeetCode: Valid Number 解题报告

    Valid NumberValidate if a given string is numeric. Some examples:"0" => true" 0.1 ...