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的时候发生了什么呢?

  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.

    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

控制权归还到HttpApplication完成后续的生命周期.

嗯哼,全文完.

MVC学习笔记---MVC生命周期的更多相关文章

  1. MVC学习笔记---MVC生命周期及管道

    ASP.NET和ASP.NET MVC的HttpApplication请求处理管道有共同的部分和不同之处,本系列将体验ASP.NET MVC请求处理管道生命周期的19个关键环节. ①以IIS6.0为例 ...

  2. MVC学习笔记---MVC的处理管线

    漫步ASP.NET MVC的处理管线   ASP.NET MVC从诞生到现在已经好几个年头了,这个框架提供一种全新的开发模式,更符合web开发本质.你可以很好的使用以及个性化和扩展这个框架,但这需要你 ...

  3. Angular 5.x 学习笔记(2) - 生命周期钩子 - 暂时搁浅

    Angular 5.x Lifecycle Hooks Learn Note Angular 5.x 生命周期钩子学习笔记 标签(空格分隔): Angular Note on cnblogs.com ...

  4. Java Web学习笔记-Servle生命周期

    Servlet会在服务器启动或第一次请求该Servlet的时候开始生命周期,在服务器停止的时候结束生命周期. 无论请求多少次Servlet,最多只有一个Servlet实例.多个客户端并发请求Servl ...

  5. android学习笔记 activity生命周期&任务栈&activity启动模式

    activity生命周期 完整生命周期 oncreate->onstart->onresume->onpause->onstop->ondestory 使用场景:应用程序 ...

  6. iOS学习笔记—ViewController/生命周期

    ViewController是iOS应用程序中重要的部分,是应用程序数据和视图之间的重要桥梁,ViewController管理应用中的众多视图.iOS的SDK中提供很多原生ViewController ...

  7. Vue2学习笔记:实例生命周期

    实例生命周期 每个 Vue 实例在被创建之前都要经过一系列的初始化过程.例如,实例需要配置数据观测(data observer).编译模版.挂载实例到 DOM ,然后在数据变化时更新 DOM .在这个 ...

  8. VUE 学习笔记 二 生命周期

    1.除了数据属性,Vue 实例还暴露了一些有用的实例属性与方法.它们都有前缀 $,以便与用户定义的属性区分开来 var data = { a: 1 } var vm = new Vue({ el: ' ...

  9. Android学习笔记_18_Activity生命周期 及 跳转方式

    一.Activity有三个状态: 1.当它在屏幕前台时(位于当前任务堆栈的顶部),它是激活或运行状态.它就是响应用户操作的Activity. 2. 当它上面有另外一个Activity,使它失去了焦点但 ...

随机推荐

  1. C#实现通过程序自动抓取远程Web网页信息的代码

    http://www.jb51.net/article/9499.htm 通过程序自动的读取其它网站网页显示的信息,类似于爬虫程序.比方说我们有一个系统,要提取BaiDu网站上歌曲搜索排名.分析系统在 ...

  2. js闭包理解

    js闭包的作用是使函数外可以访问函数内部的变量,是通过 在函数内部 定义 访问函数内变量 的函数实现的,内部的一个函数产生一个闭包 function a() { var i=0; return fun ...

  3. java 打包jar文件以在没有安装JDK或JRE的机子上运行

    前言: java号称“一次编译,到处运行”,但这有个前提,那就是你的机子上得安装java环境.对于开发人员或其他一些比较懂计算机的人来说这没什么,但是对于一些不懂计算机的人来说这会很麻烦,他们更希望的 ...

  4. nuget pack

    nuget spec nuget setApiKey yourkeynuget pack PluginMvc.Framework.csproj -Prop Configuration=Releasen ...

  5. 常用webshell提权方法总结

    pcAnywhere提权:1.利用pcAnywhere提权,前提条件是pcAnywhere默认安装到默认路径,以及它的目录安全权限有users权限,如果管理员删除了users和power users用 ...

  6. Java JNI 编程进阶 实例+c++数据类型与jni数据类型转换

    原文:http://www.iteye.com/topic/295776 JNI一直以来都很少去关注,但却是我心中的一个结,最近这几天刚好手头有点时间,因此抽空看了一下这方面的东西,整理了一份文档,J ...

  7. JS 循环遍历JSON数据

    JSON数据如:{"options":"[{/"text/":/"王家湾/",/"value/":/" ...

  8. msmms (一) sms与mms区别

    sms与mms区别 SMS,Short Messaging Service短信业务,可以通过手机等移动设备发送文本型短信.SMS这个术语最早在80年代初期出现,但一直到了90年代初才开始进入商用市场, ...

  9. 关于vue.js 组件的调用

    包子初学vue.js,有很多不明白的地方还请大家多多指教,在组件的调用的时候,包子有点懵,因为感觉调用组件的方式非常的麻烦,每一个都要实例化,不过,通过不断询问大牛们,我找到了,动态加载组件的方法~~ ...

  10. thinkphp中where方法

    今天来给大家讲下查询最常用但也是最复杂的where方法,where方法也属于模型类的连贯操作方法之一,主要用于查询和操作条件的设置.where方法的用法是ThinkPHP查询语言的精髓,也是Think ...