003. Asp.Net Routing与MVC 之一: 请求如何到达MVC

前言

本文用到的基础知识:URL、HttpModule 与 HttpHandler、IIS7.0的请求处理过程。

URL
      参见《基础URL》,

HttpModule与HttpHandler
请读《HttpModule 、HttpHandler》

IIS7.0的请求处理过程
请读《IIS7的》
《IIS架构》

OK,现在我们来看请求如何到达MVC:

一、请求如何到达Asp.Net Routing

我们知道IIS网站的配置可以分为两个块:全局 Web.Config 和本站 Web.Config 。

Asp.Net Routing属于全局性的,所以它配置在全局Web.Config 中,我们可以在如下路径中找到:

“$\Windows\Microsoft.NET\Framework\版本号\Config\Web.config“

   1: <?xml version="1.0" encoding="utf-8"?>
   2: <!-- the root web configuration file -->

   3: <configuration>

   4:     <system.web>

   5:         <httpModules>

   6:             <add name="UrlRoutingModule-4.0" type="System.Web.Routing.UrlRoutingModule" />

   7:         </httpModules>

   8:     </system.web>

   9: </configuration>

通过在全局Web.Config中注册 System.Web.Routing.UrlRoutingModule,IIS请求处理管道接到请求后,就会加载 UrlRoutingModule类型的Init()方法。其源码入下:

   1: //UrlRoutingModule 位于 System.web.dll 文件中,利用Reflector 可以查看到其源码
   2: [TypeForwardedFrom("System.Web.Routing, Version=3.5.0.0, Culture=Neutral, PublicKeyToken=31bf3856ad364e35")]

   3: public class UrlRoutingModule : IHttpModule

   4: {

   5:     // Fields

   6:     private static readonly object _contextKey = new object();

   7:     private static readonly object _requestDataKey = new object();

   8:     private RouteCollection _routeCollection;

   9:     // Methods

  10:     protected virtual void Dispose()  {}

  11:  

  12:     //在II7处理管道中注册了的IHttpModule类型,其_Init()会被执行,以在II7处理管道中注册事件处理方法。

  13:     protected virtual void Init(HttpApplication application)

  14:     {

  15:         if (application.Context.Items[_contextKey] == null)

  16:         {

  17:             application.Context.Items[_contextKey] = _contextKey;

  18:             //这里为UrlRoutingModule 注册了一个PostResolveRequestCache 事件处理方法:OnApplicationPostResolveRequestCache().

  19:             application.PostResolveRequestCache += new EventHandler(this.OnApplicationPostResolveRequestCache);

  20:         }

  21:     }

  22:  

  23:     //发生PostResolveRequestCache 事件时,该方法被调用

  24:     private void OnApplicationPostResolveRequestCache(object sender, EventArgs e)

  25:     {

  26:         HttpContextBase context = new HttpContextWrapper(((HttpApplication) sender).Context);

  27:         //执行真正的处理 PostResolveRequestCache()

  28:         this.PostResolveRequestCache(context);

  29:     }

  30:  

  31:     [Obsolete("This method is obsolete. Override the Init method to use the PostMapRequestHandler event.")]

  32:     public virtual void PostMapRequestHandler(HttpContextBase context)

  33:     {

  34:     }

  35:  

  36:      //发生PostResolveRequestCache 事件时真正的处理

  37:     public virtual void PostResolveRequestCache(HttpContextBase context)

  38:     {

  39:         //获取路由信息(RouteCollection是其本身的属性,见this.RouteCollection)

  40:         RouteData routeData = this.RouteCollection.GetRouteData(context);

  41:         if (routeData != null)

  42:         {

  43:             //从routeData 获取 RouteHandler

  44:             // 既然routeData 内容其实来自System.Web.Routing.RouteTable.Routes

  45:             // 那么System.Web.Routing.RouteTable.Routes 里的RouteHandler到底是哪来的呢?我们需要去MVC项目里看看

  46:             IRouteHandler routeHandler = routeData.RouteHandler;

  47:             if (routeHandler == null)

  48:             {

  49:                 throw new InvalidOperationException(string.Format(CultureInfo.CurrentUICulture, 

  50:                                 SR.GetString("UrlRoutingModule_NoRouteHandler"), new object[0]));

  51:             }

  52:             if (!(routeHandler is StopRoutingHandler))

  53:             {

  54:                 //构建请求上下文

  55:                 RequestContext requestContext = new RequestContext(context, routeData);

  56:                 context.Request.RequestContext = requestContext;

  57:                 //调用routeHandler.GetHttpHandler(),获取的IHttpHandler 类型实例 

  58:                 IHttpHandler httpHandler = routeHandler.GetHttpHandler(requestContext);

  59:                 if (httpHandler == null)

  60:                 {

  61:                     throw new InvalidOperationException(string.Format(CultureInfo.CurrentUICulture, 

  62:                                     SR.GetString("UrlRoutingModule_NoHttpHandler"), new object[] { routeHandler.GetType() }));

  63:                 }

  64:                 if (httpHandler is UrlAuthFailureHandler)

  65:                 {

  66:                     if (!FormsAuthenticationModule.FormsAuthRequired)

  67:                     {

  68:                         throw new HttpException(0x191, SR.GetString("Assess_Denied_Description3"));

  69:                     }

  70:                     UrlAuthorizationModule.ReportUrlAuthorizationFailure(HttpContext.Current, this);

  71:                 }

  72:                 else

  73:                 {

  74:                     //合适条件下,把之前将获取的IHttpHandler 类型实例 映射到IIS HTTP处理管道中

  75:                     context.RemapHandler(httpHandler);

  76:                 }

  77:             }

  78:         }

  79:     }

  80:  

  81:     void IHttpModule.Dispose()

  82:     {

  83:         this.Dispose();

  84:     }

  85:  

  86:     void IHttpModule.Init(HttpApplication application)

  87:     {

  88:         this.Init(application);

  89:     }

  90:  

  91:     // Properties

  92:     public RouteCollection RouteCollection

  93:     {

  94:         get

  95:         {

  96:             //恩,原来真实内容来自System.Web.Routing.RouteTable.Routes

  97:             if (this._routeCollection == null)

  98:             {

  99:                 this._routeCollection = RouteTable.Routes;

 100:             }

 101:             return this._routeCollection;

 102:         }

 103:         set

 104:         {

 105:             this._routeCollection = value;

 106:         }

 107:     }

 108: }

下边是PostResolveRequestCache方法里的几句核心代码:

   1: //PostResolveRequestCache方法里的核心代码:
   2:  

   3: //获取路由信息(RouteCollection是其本身的属性,见this.RouteCollection)

   4: RouteData routeData = this.RouteCollection.GetRouteData(context);

   5: //从routeData 获取 RouteHandler

   6: // 既然routeData 内容其实来自System.Web.Routing.RouteTable.Routes

   7: // 那么System.Web.Routing.RouteTable.Routes 里的RouteHandler到底是哪来的呢?我们需要去MVC项目里看看

   8: IRouteHandler routeHandler = routeData.RouteHandler;

   9:  

  10: //调用routeHandler.GetHttpHandler(),获取的IHttpHandler 类型实例 

  11: IHttpHandler httpHandler = routeHandler.GetHttpHandler(requestContext);

  12:  

  13: //合适条件下,把之前将获取的IHttpHandler 类型实例 映射到IIS HTTP处理管道中

  14: context.RemapHandler(httpHandler);

好吧,我们需要去MVC项目里看看。众所周知,项目启动是从Global开始的,那就看看它。下边是代码:

   1: //这是一个普通MVC5 WebApp的Global.asax.cs
   2: namespace WebApplication1

   3: {

   4:     public class MvcApplication : System.Web.HttpApplication

   5:     {

   6:         protected void Application_Start()

   7:         {

   8:             AreaRegistration.RegisterAllAreas();

   9:             FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);

  10:             //这里要注册路由了

  11:             RouteConfig.RegisterRoutes(RouteTable.Routes);

  12:             BundleConfig.RegisterBundles(BundleTable.Bundles);

  13:         }

  14:     }

  15:  

  16:     //为方便起见,我把项目App_Start/RouteConfig.cs内容放在一起

  17:     public class RouteConfig

  18:     {

  19:         public static void RegisterRoutes(RouteCollection routes)

  20:         {

  21:             routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

  22:             //玄机就在这了,这个MapRoute位于System.Web.Mvc.RouteCollectionExtensions

  23:             //看RouteCollectionExtensions里面做了什么

  24:             routes.MapRoute(

  25:                 name: "Default",

  26:                 url: "{controller}/{action}/{id}",

  27:                 defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }

  28:             );

  29:         }

  30:     }

  31: }

下边是System.Web.Mvc.RouteCollectionExtensions.MapRoute 众多重载的最终执行者代码:

   1: //System.Web.Mvc.RouteCollectionExtensions.MapRoute 众多重载的最终执行者代码
   2: [SuppressMessage("Microsoft.Design", "CA1054:UriParametersShouldNotBeStrings", MessageId = "2#", Justification = "This is not a regular URL as it may contain special routing characters.")]

   3: public static Route MapRoute(this RouteCollection routes, string name, string url, object defaults, object constraints, string[] namespaces)

   4: {

   5:     if (routes == null)

   6:     {

   7:         throw new ArgumentNullException("routes");

   8:     }

   9:     if (url == null)

  10:     {

  11:         throw new ArgumentNullException("url");

  12:     }

  13:  

  14:     //终于找到了,“new MvcRouteHandler()”,

  15:     //直接把一个 MvcRouteHandler 实例塞到 System.Web.Routing 的初始化方法里了!

  16:     Route route = new Route(url, new MvcRouteHandler())

  17:     {

  18:         Defaults = CreateRouteValueDictionaryUncached(defaults),

  19:         Constraints = CreateRouteValueDictionaryUncached(constraints),

  20:         DataTokens = new RouteValueDictionary()

  21:     };

  22:  

  23:     ConstraintValidation.Validate(route);

  24:  

  25:     if ((namespaces != null) && (namespaces.Length > 0))

  26:     {

  27:         route.DataTokens[RouteDataTokenKeys.Namespaces] = namespaces;

  28:     }

  29:  

  30:     routes.Add(name, route);

  31:  

  32:     return route;

  33: }

终于找到了!

综上所述,一个请求从 IIS 到达 MvcRouteHandler 的顺序如下:

一、IIS接到请求:

IIS接到一个请求,检查请求的应用是否已初始化;

若应用未初始化,为应用分配应用池程序资源,及其他应用程序域信息,加载全局和本站web.config信息以设定配置;

开始应用初始化;

二、开始应用初始化:

1.1、在应用程序域,为应用程序创建环境对象(HostingEnvironment??)和响应对象(HttpContext、HttpRequest 和 HttpResponse);

创建应用的 HttpApplication 类型实例(即Global.asax.cs 实例),以启动应用;

1.2、在Global.asax.cs中,调用程序 RegisterRoutes 注册路由。

1.3、在 RegisterRoutes 中,调用 System.Web.Mvc.RouteCollectionExtensions.MapRoute()逐条注册。

1.4、在MapRoute中,直接把 MvcRouteHandler 类型实例塞到 System.Web.Routing 的初始化方法里,以填充System.Web.Routing.RouteTable.Routes数据。

三、初始化完成,处理请求:

1、HttpApplication 启动HTTP管道模型开始处理请求

HTTP管道处理已注册的 IHttpModule 事件:System.Web.Routing.UrlRoutingModule.OnApplicationPostResolveRequestCache();

随即OnApplicationPostResolveRequestCache 调用 PostResolveRequestCache()

PostResolveRequestCache方法从System.Web.Routing.RouteTable.Routes的数据中获取IHttpHandler 类型;

在2.4中被直接塞入的MvcRouteHandler 类型实例,被映射到 IIS HTTP处理管道中。

最终,IIS HTTP处理管道调用 MvcRouteHandler 处理请求,并返回Response内容。

至此,请求 成功透过 Asp.Net Routing机制到达 MVC 处理程序。

下次讲 Asp.Net Routing在MVC项目中的使用

----------------------------------------

http://www.cnblogs.com/fsjohnhuang/articles/2332074.html

http://msdn.microsoft.com/zh-cn/library/cc668201%28v=vs.100%29.aspx

http://www.cnblogs.com/isdavid/archive/2013/05/28/3103228.html

http://www.iis.net/learn/get-started/introduction-to-iis/introduction-to-iis-architecture

http://blog.csdn.net/darren__chan/article/details/8215646

http://msdn.microsoft.com/zh-cn/library/bb470252%28v=vs.100%29.aspx

http://www.bdqn.cn/news/201309/11384.shtml

----------------------------------------

003. Asp.Net Routing与MVC 之一: 请求如何到达MVC

时间: 2024-08-10 19:16:24

003. Asp.Net Routing与MVC 之一: 请求如何到达MVC的相关文章

004. Asp.Net Routing与MVC 之二: 请求如何激活Controller和Action

上篇讲到 请求到达 MvcRouteHandler ,并且透过 IRouteHandler.GetHttpHandler 获取到了真正的处理程序 MvcHandler 这次我们看看,MvcHandler是如何依据请求,来激活对应的controller和Action来处理请求的. 一.先看看MvcHandler 的核心内容 1: public class MvcHandler : IHttpAsyncHandler, IHttpHandler, IRequiresSessionState 2: {

详解ASP.NET MVC的请求生命周期

本文的目的旨在详细描述asp.net mvc请求从开始到结束的每一个过程. 我希望能理解在浏览器输入url并敲击回车来请求一个asp.net mvc网站的页面之后发生的任何事情. 为什么需要关心这些?有两个原因.首先是因为asp.net mvc是一个扩展性非常强的框架.例如,我们可以插入不同的viewengine来控制网站内容呈现的方式.我们还可以定义控制器生成和分配到某个请求的 方式.因为我想发掘任何asp.net mvc页面请求的扩展点,所以我要来探究请求过程中的一些步骤. 其次,如果你对测

ASP.NET MVC入门到精通——14.MVC请求管道

本系列目录:ASP.NET MVC4入门到精通系列目录汇总 ASP.NET MVC的请求管道和ASP.NET请求管道基本上一模一样,如果你对ASP.NET请求管道十分熟悉的话,你只要关注一下不同点.看懂下面两张图,你就基本上明了了,不明天的地方,用reflector工具查看MVC的源码,没其它的..NET框架的源码里面几乎涉猎了各种设计模式.这一节的内容,我也不知道怎么说,都在图里面了,看图比直接用文字说明要明了得多,比较这些东西还是比较抽象的,如果你时间充裕,建议看下MVC的源码.怎么看?就找

003.ASP.NET MVC集中管理Session

原文链接:http://www.codeproject.com/Tips/790387/Session-in-ASP-NET-MVC 1.前言 今天有得有失啊,看到这篇,专心记下里面的精华吧 2.一般在Web程序中,使用Session可能会有以下的用途 a.检查用户是否登录 b.保存权限信息 c.保存临时数据 有时,我们会频繁地改变Session保存的对象,现在,我们尝试在一个Controller中集中管理Session,这样可以应用于其它的Controller,达到重用的效果 3.在开始之前,

ASP.NET中HttpApplication中ProcessRequest方法中执行的事件顺序;ASP.NET WebForm和MVC整体请求流程图

ASP.NET中HttpApplication中ProcessRequest方法中执行的事件顺序 1.BeginRequest  开始处理请求 2.AuthenticateRequest 授权验证请求,获取用户授权信息 3.PostAuthenticateRequest 获取成功 4.AunthorizeRequest 授权,一般来检查用户是否获得权限 5.PostAuthorizeRequest 获得授权 6.ResolveRequestCache 获取页面缓存结果(如果没有则执行) 7.Po

MVC的请求生命周期

当一个asp.net mvc应用程序提出请求,为了响应请求,包含一些请求执行流程步骤! 在asp.net mvc应用程序Http request 和Http response 过程中,主要包含8个步骤: 1)RouteTable(路由表)的创建     2)UrlRoutingModule 请求拦截     3)Routing engine 确定route     4)route handler 创建相关的IHttpHandler实例     5)IHttpHandler实例确定Controll

.NET/ASP.NET Routing路由(深入解析路由系统架构原理)

出处:http://www.cnblogs.com/wangiqngpei557/ 阅读目录: 1.开篇介绍 2.ASP.NET Routing 路由对象模型的位置 3.ASP.NET Routing 路由对象模型的入口 4.ASP.NET Routing 路由对象模型的内部结构 4.1UrlRoutingModule 对象内部结构 4.2RouteBase.Route.RouteCollection.RouteTable 路由核心对象模型 4.3RouteValueDictionary.Rou

【转】.NET/ASP.NET Routing路由(深入解析路由系统架构原理)

阅读目录: 1.开篇介绍 2.ASP.NET Routing 路由对象模型的位置 3.ASP.NET Routing 路由对象模型的入口 4.ASP.NET Routing 路由对象模型的内部结构 4.1]UrlRoutingModule 对象内部结构 4.2]RouteBase.Route.RouteCollection.RouteTable 路由核心对象模型 4.3]RouteValueDictionary.RouteData.RequestContext 路由数据对象模型 4.4]IRou

ASP.NET路由[ASP.NET Routing]

ASP.NET路由[ASP.NET Routing] ASP.NET路由允许你在使用URL时不必匹配到网站中具体的文件,因为这个URL不必匹配到一个文件,你使用了描述用户行为且更容易被用户理解的URL. ASP.NET MVC框架和ASP.NET动态数据(Dynamic Data)扩展路由为MVC应用和动态数据应用增加了特色. 在不使用路由的ASP.NET应用中,一个新的请求会被映射到一个物理文件并由该文件处理这个请求,例如一个.aspx文件.例如,如下请求http://server/appli