基础知识

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

URL

HttpModule与HttpHandler

IIS7.0的请求处理过程

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:                 //调用 IRouteHandler.GetHttpHandler(),获取的IHttpHandler 类型实例 

  58:                 //IHttpHandler 类型实例 ,是由 IRouteHandler.GetHttpHandler获取的,我们去MVC源码里看

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

  60:                 if (httpHandler == null)

  61:                 {

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

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

  64:                 }

  65:                 if (httpHandler is UrlAuthFailureHandler)

  66:                 {

  67:                     if (!FormsAuthenticationModule.FormsAuthRequired)

  68:                     {

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

  70:                     }

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

  72:                 }

  73:                 else

  74:                 {

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

  76:                     context.RemapHandler(httpHandler);

  77:                 }

  78:             }

  79:         }

  80:     }

  81:  

  82:     void IHttpModule.Dispose()

  83:     {

  84:         this.Dispose();

  85:     }

  86:  

  87:     void IHttpModule.Init(HttpApplication application)

  88:     {

  89:         this.Init(application);

  90:     }

  91:  

  92:     // Properties

  93:     public RouteCollection RouteCollection

  94:     {

  95:         get

  96:         {

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

  98:             if (this._routeCollection == null)

  99:             {

 100:                 this._routeCollection = RouteTable.Routes;

 101:             }

 102:             return this._routeCollection;

 103:         }

 104:         set

 105:         {

 106:             this._routeCollection = value;

 107:         }

 108:     }

 109: }

下边是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: //调用 IRouteHandler.GetHttpHandler(),获取的IHttpHandler 类型实例 

  11: //IHttpHandler 类型实例 ,是由 IRouteHandler.GetHttpHandler获取的,我们去MVC源码里看

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

  13:  

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

  15: context.RemapHandler(httpHandler);

二、MVCRouteHandler从哪来

好吧,我们需要去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: }

三、请求到达真正的处理程序:MVCHandler

IRouteHandler 里只有一个方法 IHttpHandler GetHttpHandler();

   1: namespace System.Web.Routing

   2: {

   3:     // 摘要: 

   4:     //     定义类必须实现才能处理匹配路由模式的请求的协定。

   5:     [TypeForwardedFrom("System.Web.Routing, Version=3.5.0.0, Culture=Neutral, PublicKeyToken=31bf3856ad364e35")]

   6:     public interface IRouteHandler

   7:     {

   8:         // 摘要: 

   9:         //     提供处理请求的对象。//

  10:         // 参数: 

  11:         //   requestContext:

  12:         //     一个对象,封装有关请求的信息。

  13:         // 返回结果: 

  14:         //     一个处理请求的对象。

  15:         IHttpHandler GetHttpHandler(RequestContext requestContext);

  16:     }

  17: }

MvcRouteHandler 是 IRouteHandler的实现,它实现的GetHttpHandler如下:

   1: //IRouteHandler.IRouteHandler() 的实现如下

   2:         protected virtual IHttpHandler GetHttpHandler(RequestContext requestContext)

   3:         {

   4:             requestContext.HttpContext.SetSessionStateBehavior(GetSessionStateBehavior(requestContext));

   5:             //返回一个 MvcHandler的实例,至此,当IIS请求处理管道,执行熬 Handler.Exe 时,请求真正达到MVC

   6:             return new MvcHandler(requestContext);

   7:         }

终于找到了!

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

1、IIS接到请求:

1.1、IIS接到一个请求,检查请求的应用是否已初始化;
1.2、若应用未初始化,为应用分配应用池程序资源,及其他应用程序域信息,加载全局和本站web.config信息以设定配置;
1.3、开始应用初始化;

2、开始应用初始化:

2.1、在应用程序域,为应用程序创建环境对象(HostingEnvironment??)和响应对象(HttpContext、HttpRequest 和 HttpResponse);
2.2、创建应用的 HttpApplication 类型实例(即Global.asax.cs 实例),以启动应用;
2.3、在 Global.asax.cs 中,调用程序 RegisterRoutes 注册路由;
2.4、在 RegisterRoutes 中,调用 System.Web.Mvc.RouteCollectionExtensions.MapRoute() 逐条注册;
2.5、在 MapRoute中,直接把 MvcRouteHandler 类型实例塞到 System.Web.Routing 的初始化方法里,以填充 System.Web.Routing.RouteTable.Routes 数据;

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

3.1、HttpApplication 启动HTTP管道模型开始处理请求;
3.2、HTTP 管道处理已注册的 IHttpModule 事件:System.Web.Routing.UrlRoutingModule.OnApplicationPostResolveRequestCache();
3.3、随即 OnApplicationPostResolveRequestCache 调用 PostResolveRequestCache();
3.4、PostResolveRequestCache 方法从 System.Web.Routing.RouteTable.Routes 的数据中获取 IHttpHandler 类型;
3.5、在2.4中被直接塞入的 MvcRouteHandler 类型实例,被映射到 IIS HTTP处理管道中;
3.6、最终,IIS HTTP处理管道调用 MvcHandler 处理请求,并返回 Response 内容;

至此,请求 成功透过 Asp.Net 到达 MvcHandler 处理程序。

系列一共计划三篇

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

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

Asp.Net Routing与MVC 之三: 路由在MVC的使用

参考了一堆文章,下边是传送门

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

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

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

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

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

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

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

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

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

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

    本文的目的旨在详细描述asp.net mvc请求从开始到结束的每一个过程. 我希望能理解在浏览器输入url并敲击回车来请求一个asp.net mvc网站的页面之后发生的任何事情. 为什么需要关心这些? ...

  2. ASP.NET MVC的请求生命周期

    我希望能理解在浏览器输入URL并敲击回车来请求一个ASP.NET MVC网站的页面之后发生的任何事情. 为什么需要关心这些?有两个原因.首先是因为ASP.NET MVC是一个扩展性非常强的框架.例如, ...

  3. 005. Asp.Net Routing与MVC 之三: 路由在MVC的使用

    上次讲到请求如何激活Controller和Action,这次讲下MVC中路由的使用.本次两个关注点: 遗留:ModelBinder.BindModel的过程 MVC中路由的使用 MVC 5中的Acti ...

  4. Asp.net MVC进入请求管道的过程

    Asp.net MVC进入请求管道的过程 Asp.Net MVC 跟AspNet 入口解释 Asp.Net MVC请求处理过程 mvc 请求模型 mvc的原理 mvc模型 NewMVCPipleLin ...

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

    ASP.NET中HttpApplication中ProcessRequest方法中运行的事件顺序 1.BeginRequest  開始处理请求 2.AuthenticateRequest 授权验证请求 ...

  6. 001. Asp.Net Routing与MVC 之(基础知识):URL

    URL(Uniform Resoure Locator:统一资源定位器)是WWW页的绝对地址.URL地址格式排列为:scheme://host:port/path. 例如 http://www.zn. ...

  7. 002. Asp.Net Routing与MVC 之(基础知识):HttpModule 与 HttpHandler

    本文By 杨工. 一. Http.sys http.sys 从Win2003和WinXP SP2开始,就成为windows操作系统内核驱动程序,能够让任何应用程序通过它提供的接口,以http协议进行信 ...

  8. ASP.NET路由[ASP.NET Routing]

    ASP.NET路由[ASP.NET Routing] ASP.NET路由允许你在使用URL时不必匹配到网站中具体的文件,因为这个URL不必匹配到一个文件,你使用了描述用户行为且更容易被用户理解的URL ...

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

    阅读目录: 1.开篇介绍 2.ASP.NET Routing 路由对象模型的位置 3.ASP.NET Routing 路由对象模型的入口 4.ASP.NET Routing 路由对象模型的内部结构 4 ...

随机推荐

  1. 122. Best Time to Buy and Sell Stock(二) leetcode解题笔记

    122. Best Time to Buy and Sell Stock II Say you have an array for which the ith element is the price ...

  2. js模块和级联

    1.模块 模块模式的一般形式是:一个定义了私有变量和函数的函数,利用闭包创建可以访问私有变量和函数的特权函数,最后返回这个特权函数,或者把它们保存到一个可访问的地方.使用模块模式就可以摒弃全局变量的使 ...

  3. andorid frameanimation

    Android中的逐帧动画 先来说说什么是逐帧动画,逐帧动画是一种常见的动画形式(Frame By Frame),其原理是在“连续的关键帧”中分解动画动作,也就是在时间轴的每帧上逐帧绘制不同的内容,使 ...

  4. .net 发展史

    2002年年初 -Visual Studio 2002 & .Net Framework 1.0 2003年春天 -Visual Studio 2003 & .Net Framewor ...

  5. pragma

    在所有的预处理指令中,#pragma指令可能是最复杂的了,它的作用是设定编译器的状态或者是指示编译器完成一些特定的动作.#pragma指令对每个 编译器给出了一个方法,在保持与C和C++语言完全兼容的 ...

  6. java JFrame窗体真正关闭

    程序: package JFrame.bao; import java.awt.event.WindowAdapter;import java.awt.event.WindowEvent; impor ...

  7. node3

  8. 一个实现了View接口的Fragment

    小程序并不新鲜,模式上先有百度轻应用,后有支付宝的各类小服务,再来还有腾讯自家QQ右下角的应用宝:技术上也就是FaceBook RN的那一套.一个技术上无创新,形式上无创意的事物,凭什么勾起了开发者们 ...

  9. 【NHibernate】列“ReservedWord”不属于表 ReservedWords

    NHibernate+FluentNHibernate+MySql 运行时黄页显示下边的异常,项目中找了半天没出现过这个列的关键字. [ArgumentException: 列“ReservedWor ...

  10. JDBC Boilerplate

    public class Student{ private Integer studId; private String name; private String email; private Dat ...