003. Asp.Net Routing与MVC 之一: 请求如何到达MVC
基础知识
本文用到的基础知识: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的更多相关文章
- 详解ASP.NET MVC的请求生命周期
本文的目的旨在详细描述asp.net mvc请求从开始到结束的每一个过程. 我希望能理解在浏览器输入url并敲击回车来请求一个asp.net mvc网站的页面之后发生的任何事情. 为什么需要关心这些? ...
- ASP.NET MVC的请求生命周期
我希望能理解在浏览器输入URL并敲击回车来请求一个ASP.NET MVC网站的页面之后发生的任何事情. 为什么需要关心这些?有两个原因.首先是因为ASP.NET MVC是一个扩展性非常强的框架.例如, ...
- 005. Asp.Net Routing与MVC 之三: 路由在MVC的使用
上次讲到请求如何激活Controller和Action,这次讲下MVC中路由的使用.本次两个关注点: 遗留:ModelBinder.BindModel的过程 MVC中路由的使用 MVC 5中的Acti ...
- Asp.net MVC进入请求管道的过程
Asp.net MVC进入请求管道的过程 Asp.Net MVC 跟AspNet 入口解释 Asp.Net MVC请求处理过程 mvc 请求模型 mvc的原理 mvc模型 NewMVCPipleLin ...
- ASP.NET中HttpApplication中ProcessRequest方法中运行的事件顺序;ASP.NET WebForm和MVC总体请求流程图
ASP.NET中HttpApplication中ProcessRequest方法中运行的事件顺序 1.BeginRequest 開始处理请求 2.AuthenticateRequest 授权验证请求 ...
- 001. Asp.Net Routing与MVC 之(基础知识):URL
URL(Uniform Resoure Locator:统一资源定位器)是WWW页的绝对地址.URL地址格式排列为:scheme://host:port/path. 例如 http://www.zn. ...
- 002. Asp.Net Routing与MVC 之(基础知识):HttpModule 与 HttpHandler
本文By 杨工. 一. Http.sys http.sys 从Win2003和WinXP SP2开始,就成为windows操作系统内核驱动程序,能够让任何应用程序通过它提供的接口,以http协议进行信 ...
- ASP.NET路由[ASP.NET Routing]
ASP.NET路由[ASP.NET Routing] ASP.NET路由允许你在使用URL时不必匹配到网站中具体的文件,因为这个URL不必匹配到一个文件,你使用了描述用户行为且更容易被用户理解的URL ...
- .NET/ASP.NET Routing路由(深入解析路由系统架构原理)
阅读目录: 1.开篇介绍 2.ASP.NET Routing 路由对象模型的位置 3.ASP.NET Routing 路由对象模型的入口 4.ASP.NET Routing 路由对象模型的内部结构 4 ...
随机推荐
- 开启 mysql 远程访问
如何开启MySQL的远程帐号-1)首先以 root 帐户登陆 MySQL 在 Windows 主机中点击开始菜单,运行,输入“cmd”,进入控制台,然后cd 进入MySQL 的 bin 目录下,然后输 ...
- iOS判断数组不为空
用([array count]==0 )来判断是否为空,都是坑,如果array为空的话,执行count就会直接报错,程序崩溃退出. 正确判断NSArray是否为空的方法: if(array != ni ...
- Python学习(基础简绍)
今天终于开始了python的学习,至于python的历史我就不说了,百度百科中太详细了,我这里说就是关公面前耍大刀,太自不量力了,所以,废话不多说,直接讲讲我惊天学习Python的收获吧. 1.Pyt ...
- vs
https://www.visualstudio.com/downloads/download-visual-studio-vs
- UIAppearance
1> 只要遵守了UIAppearance协议,还要实现这个方法才能调用appearance相关方法 2> 只有被UI_APPEARANCE_SELECTOR宏修饰的属性,才能设置 // 获 ...
- 查询时,如何保存获取相关路径url
作为新人,总是会有许多小问题不懂,不知道如何解决的. 这不,这次,遇到了路径获取问题. 在Jsp页面中,获取当前路径,在<script></script>中添加 var ur ...
- Class 'Illuminate\Html\HtmlServiceProvider' not found或者form表单不能正常使用解决办法
在laravel框架中,form不能正常使用如何处理. 网上搜到的解决方案通常都是一致的,下面分类考虑: 1,打开根目录composer.json 文件, require 里面增加: 如果larave ...
- Win7 64位 VS2015环境使用SDL2-2.0.4
之前在VS中使用SDL2,如果只链接SDL2.lib,会提示 error LNK2019: unresolved external symbol _main referenced in functio ...
- WINCE 获取智能设备唯一编号
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; usin ...
- 【Visual Lisp】图元选择集专题
图元选择集专题;;★★★01.选择集操作★★★(setq ss (ssadd));;创建一个空选择集(ssadd (car(entsel)) ss);;将点取的图元添加到ss选择集中,可以不用setq ...