前言
本文用到的基础知识: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,布布扣,bubuko.com
003. Asp.Net Routing与MVC 之一: 请求如何到达MVC
原文:http://www.cnblogs.com/acejason/p/3869731.html