- 本文以IIS7中asp.net应用程序生命周期为例,介绍了asp.net mvc的生命周期。
asp.net应用程序管道处理用户请求时特别强调"时机",对asp.net生命周期的了解多少直接影响我们写页面和控件的效率。对于asp.net mvc,我对它的生命周期兴趣很浓,于是对ASP.NET MVC生命周期提出两个问题:
一个HTTP请求从IIS移交到asp.net运行时,asp.net mvc是在什么时机获得了控制权并对请求进行处理呢?处理过程又是怎样的?
以IIS7中asp.net生命周期为例,上图是来自MSDN的一张HTTP请求处理过程发生事件的简图,后面我列出了一个完整的事件列表。既然asp.net mvc还是以asp.net运行时为基础那么它必然要在asp.net应用程序的生命周期中对请求进行截获。第一反应当然是去web.config里面去翻翻,我们可以看到UrlRoutingModule的配置节:
< add name="UrlRoutingModule" type="System.Web.Routing.UrlRoutingModule, System.Web.Routing, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
下面要做的就顺理成章了,用Reflector打开这个程序集,可以看到以下代码:
- protected virtual void Init(HttpApplication application)
- {
- application.PostResolveRequestCache += new EventHandler(this.OnApplicationPostResolveRequestCache);
- application.PostMapRequestHandler += new EventHandler(this.OnApplicationPostMapRequestHandler);
- }
看到这里我们的第一个问题实际上已经有了答案:时机是在PostResolveRequestCache和PostMapRequestHandler.
我们使用VS2008中asp.net mvc模板创建一个Demo完成后续的讨论,当我们访问/Home的时候发生了什么呢?
1、Request 请求到来
2、IIS 根据请求特征将处理权移交给 asp.net
3、UrlRoutingModule将当前请求在 Route Table中进行匹配
4、UrlRoutingModule在RouteCollection中查找Request匹配的RouteHandler,默认是mvcRouteHandler mvcRouteHandler 创建 mvcHandler实例.
5、mvcHandler执行 ProcessRequest.
6、mvcHandler 使用 IControllerFactory 获得实现了IController接口的实例,找到对应的HomeController
7、根据Request触发HomeController的Index方法
8、Index将执行结果存放在ViewData
9、HomeController的Index方法返回 ActionResult
10、Views/Home/Index.aspx将 ViewData呈现在页面上
11、Index.aspx执行ProcessRequest方法
12、Index.aspx执行Render方法 输出到客户端
通过阅读asp.net mvc的源码,我们可以得到更为详细的处理过程,我尽可能的忽略掉枝节,强调请求处理的流程.我们从Global.asax.cs文件切入,下面是一段样例代码,这里初始化了路由表,请特别特别注意注释部分:
- public class mvcApplication : System.Web.HttpApplication
- {
- public static void RegisterRoutes(RouteCollection routes)
- {
- routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
- //The controller route value is a special value that the System.Web.mvc.mvcHandler class uses to call into the IControllerFactory interface.
- //The basic route handler is an instance of IRouteHandler named mvcRouteHandler.
- //We have complete control and could provide our own implementation of IRouteHandler if we wished.
- routes.MapRoute(
- "Default", // Route name
- "{controller}/{action}/{id}", // URL with parameters
- new { controller = "Home", action = "Index", id = "" } // Parameter defaults
- );
- }
- protected void Application_Start()
- {
- RegisterRoutes(RouteTable.Routes);
- }
UrlRoutingMoudule在PostResolveRequestCache阶段从RouteCollection中获取当前请求的RouteData.RouteData包含了一个请求处理对应的Controller和Action,RouteData这个作用贯穿请求的处理过程.RouteData中提取RouteHandler,这里默认是mvcRouteHandler,mvcRouteHandler获取HttpHandler,这里默认的是mvcHandler.
- PostResolveRequestCache
- public virtual void PostResolveRequestCache(HttpContextBase context)
- {
- RouteData routeData = this.RouteCollection.GetRouteData(context);
- if (routeData != null)
- {
- IRouteHandler routeHandler = routeData.RouteHandler;
- if (routeHandler == null)
- {
- throw new InvalidOperationException(string.Format(CultureInfo.CurrentUICulture, RoutingResources.UrlRoutingModule_NoRouteHandler, new object[0]));
- }
- if (!(routeHandler is StopRoutingHandler))
- {
- RequestContext requestContext =