Asp.net MVC生命周期
Asp.net应用程序管道处理用户请求时特别强调"时机",对Asp.net生命周期的了解多少直接影响我们写页面和控件的效率。因此在2007年和2008年我在这个话题上各写了一篇文章:
对于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.
ResolveRequestCache event
Occurs when ASP.NET finishes an authorization event to let the caching modules serve requests from the cache, bypassing execution of the event handler (for example, a page or an XML Web service).
源文档 <http://msdn.microsoft.com/en-us/library/system.web.httpapplication.resolverequestcache.aspx>
PostMapRequestHandler event
Occurs when ASP.NET has mapped the current request to the appropriate event handler.
源文档 <http://msdn.microsoft.com/en-us/library/system.web.httpapplication.postmaprequesthandler.aspx>
我们使用VS2008中Asp.net Mvc模板创建一个Demo完成后续的讨论,当我们访问/Home的时候发生了什么呢?
- Request 请求到来
- IIS 根据请求特征将处理权移交给 ASP.NET
- UrlRoutingModule将当前请求在 Route Table中进行匹配
- UrlRoutingModule在RouteCollection中查找Request匹配的RouteHandler,默认是MvcRouteHandler MvcRouteHandler 创建 MvcHandler实例.
- MvcHandler执行 ProcessRequest.
- MvcHandler 使用 IControllerFactory 获得实现了IController接口的实例,找到对应的HomeController
- 根据Request触发HomeController的Index方法
- Index将执行结果存放在ViewData
- HomeController的Index方法返回 ActionResult
- Views/Home/Index.aspx将 ViewData呈现在页面上
- Index.aspx执行ProcessRequest方法
- 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 = new RequestContext(context, routeData);
IHttpHandler httpHandler = routeHandler.GetHttpHandler(requestContext);
if (httpHandler == null)
{
throw new InvalidOperationException(string.Format(CultureInfo.CurrentUICulture, RoutingResources.UrlRoutingModule_NoHttpHandler, new object[] { routeHandler.GetType() }));
}
RequestData data2 = new RequestData();
data2.OriginalPath = context.Request.Path;
data2.HttpHandler = httpHandler;
context.Items[_requestDataKey] = data2;
context.RewritePath("~/UrlRouting.axd");
}
}
}

MvcHandler.ProcessRequest()中首先使用HttpContextWrapper对HttpContext进行封装,封装的目的是为了解耦以获得可测试性.然后从RequestContext.RouteData中提取Controller名称.
ControllerBuilder.GetControllerFactory --> ControllerFactory.CreateController --> IController.Execute
ControllerBase实现了IController接口,在Initialize时将RequestContext封装成为ControllerContext,Controller继承自ControllerBase并实现抽象方法ExecuteCore()

在ExecuteCore中,Controller首先从RouteData中获得ActionName,然后执行ActionInvoker.InvokeAction.
在ActionInvoker中我们可以看到各种Filter,这是一种AOP实践:在Action方法执行的前后执行若干方法.这里有四种Filter:ActionFilters,ResultFilters,AuthorizationFilters,ExceptionFilters.这四种Filter并不是封闭的,都有对应的接口,这四个只是默认实现.Filter的执行顺序是:AuthorizationFilter--->Action Filter.OnActionExecuting--->Action Method--->ActionFilter.OnActionExecuted.InvokeActionMethodWithFilters返回的结果是ActionExecutedContext,接下来将Controller执行OnResultExecuting 方法.ActionResult执行的结果可以是ViewResult,JsonResult,RedirectResult,ContentResult,或者是自定义的Result类型.
如果返回的类型是ViewResult,我们先看一下ViewReuslt的继承关系:ViewResult-->ViewResultBase-->ActionResult,ViewResult包含两个属性View和ViewEngineCollection,实际上是包含了两个接口的实现:IViewEngine定义了怎么定位View/Partial View.IView定义了如何RenderView.默认的实现时WebFormView和WebFormViewEngine.
Filter OnResultExecuted 最后一步了,可以这里捕获异常.上面我们说过还有ExceptionFilters,如果前面过程中的异常没有被捕获那么最终都会到冒泡到ExceptionFilters.
- RouteData中获得ActionName
- ActionInvoker.InvokeAction
- 通过ControllerContext获取ControllerDescriptor
- FindAction-获取ActionDescriptor
- GetFilters
- ModelBinder把Request中的数据转换成Action方法需要的参数
- AuthorizationFilter
- Action Filter.OnActionExecuting
- Action
- ActionFilter.OnActionExecuted
- ResultFilter.OnResultExecuting
- ActionResult Execution
- ResultFilter.OnResultExecuted
- WebFormViewEngine.CreateView
- WebFormView.Render
- ResultFilter.OnExecuted

Asp.net MVC生命周期的更多相关文章
- ASP.NET MVC 生命周期
本文的目的旨在详细描述ASP.NET MVC请求从开始到结束的每一个过程.我希望能理解在浏览器输入URL并敲击回车来请求一个ASP.NET MVC网站的页面之后发生的任何事情. 为什么需要关心这些?有 ...
- ASP.NET MVC生命周期介绍(转)
本文以IIS7中asp.net应用程序生命周期为例,介绍了asp.net mvc的生命周期. asp.net应用程序管道处理用户请求时特别强调"时机",对asp.net生命周期的了 ...
- [收藏]Asp.net MVC生命周期
一个HTTP请求从IIS移交到Asp.net运行时,Asp.net MVC是在什么时机获得了控制权并对请求进行处理呢?处理过程又是怎样的? 以IIS7中asp.net应用程序生命周期为例,下图是来自M ...
- 1.3 ASP.NET MVC生命周期
ASP.NET MVC的执行生命周期主要分为三个阶段,分别是网址路由对比.执行控制器与动作.执行视图并返回结果.从ASP.NET MVC接受HTTP请求到返回HTTP响应的过程如下图所示.
- asp.net mvc生命周期学习
ASP.NET MVC是一个扩展性非常强的框架,探究其生命周期对用Mock框架来模拟某些东西,达到单元测试效果,和开发扩展我们的程序是很好的. 生命周期1:创建routetable.把URL映射到ha ...
- ASP.NET MVC生命周期与管道模型
先来熟悉下asp.net请求管道 1.当客户端发送http://localhost:80/home/index请求时 2.首先到达服务端的内核模块HTTP.SYS(它监听80端口),通过访问注册表 ...
- 【深入ASP.NET原理系列】--ASP.NET页面生命周期
前言 ASP.NET页面运行时候,页面将经历一个生命周期,在生命周期中将执行一系列的处理步骤.包括初始化.实例化控件.还原和维护状态.运行时间处理程序代码以及进行呈现.熟悉页面生命周期非常重要,这样我 ...
- 微软Asp.net MVC5生命周期流程图
.NET WEB Development blog 发布了Asp.net MVC5生命周期文档, 这个文档类似Asp.net应用程序生命周期,您以前开发ASP.NET WEB应用程序应该 ...
- MVC学习笔记---MVC生命周期
Asp.net应用程序管道处理用户请求时特别强调"时机",对Asp.net生命周期的了解多少直接影响我们写页面和控件的效率.因此在2007年和2008年我在这个话题上各写了一篇文章 ...
随机推荐
- 使用 Windows AIK 创建自定的客户端系统WIM文件
Windows 7/2008 的AIK 3.0下载页面:地址链接 1.8G [3.1补充包为1.4G] 安装3.0后,升级为3.1方法: xcopy E:\ "C:\Program File ...
- 关于jsp中response.sendRedirect显示错误
今天在jsp中作判断时,当不同条件时利用response.sendRedirect(“url”)来转向不同的页面,首先是判断验证码,当错误时就转向错误页面:当正确时,才进行用户名和密码的判断,同样也r ...
- gerrit error: unpack failed: error Permission denied
gerrit服务器迁移后,clone和pull代码到本地,都没问题. 但是,push时,报错: 查看了下git版本库存储目录,发现git下版本库镜像文件owner都是root.因为之前安装的gerri ...
- windows下python3.4安装scikit-learn
python3.4.0_64位下安装numpy-1.11.1 安装步骤: 1.在终端CMD中输入: python -m pip install -U pip 2.找到 下载的 numpy-1.1 ...
- 每天一个Linux命令
每天一个Linux命令(1):ls命令 每天一个Linux命令(2):cd命令 每天一个Linux命令(3):pwd命令 每天一个 Linux 命令(4):mkdir 每天一个 Linux 命令(5) ...
- switch语句
应用条件语句可以很方便地使程序实现分支,但是出现分支比较多的时候,虽然可以用嵌套的if语句来解决,但是程序结构会显得复杂,甚至凌乱.为方便实现多情况选择,C++提供了一种switch开关语句. 一 ...
- VGA逐行扫描控制器的Verilog建模
前言:因为VGA是一种模拟图像传输数据接口,所要将数字信号用DAC转换成模拟量.本文用的一款ADI公司高精度的视频IC,实则一款高带宽的视频DAC.因为VGA时序较为简单,并且网上的VGA驱动基本大同 ...
- MySQL-5.6.13免安装版配置方法
MySQL-5.6.13免安装版配置方法 1. 下载MySQL Community Server 5.6.13 2. 解压MySQL压缩包 将以下载的MySQL压缩包解压到自定义目录下,我的 ...
- httperf学习笔记(CentOS-6.6环境下安装配置)
新工作已经找到了,最近在忙着熟悉环境,昨天领导让我接触下httperf压力测试工具 百度了下,相关的文档,准备着手配置一个测试环境基于linux系统httperf+autobench+gnuplot, ...
- lua 和 c
lua程序其实本身并不能执行,它必须依靠c语言编写的解释器来解释执行,或者说解释器为lua脚本的执行,提供了一个运行环境(lua_state),其中包括函数堆栈,内存分配和回收等机制. 理论上,lua ...