找回密码
 立即注册
首页 业界区 业界 Asp.net MVC生命周期

Asp.net MVC生命周期

米嘉怡 2025-5-29 20:28:09
    Asp.net应用程序管道处理用户请求时特别强调"时机",对Asp.net生命周期的了解多少直接影响我们写页面和控件的效率。因此在2007年和2008年我在这个话题上各写了一篇文章:

  • 《日志不说谎--Asp.net的生命周期》
  • 《日志不说谎--Asp.net的生命周期 【结题】》
  • 《两个粒度看Asp.net生命周期》
对于Asp.net MVC,我对它的生命周期还是兴趣很浓,于是提出两个问题:
一个HTTP请求从IIS移交到Asp.net运行时,Asp.net MVC是在什么时机获得了控制权并对请求进行处理呢?处理过程又是怎样的?
1.png
 
 
以IIS7中asp.net应用程序生命周期为例,下图是来自MSDN的一张HTTP请求处理过程发生事件的简图,后面我列出了一个完整的事件列表。既然Asp.net Mvc还是以Asp.net运行时为基础那么它必然要在Asp.net应用程序的生命周期中对请求进行截获。第一反应当然是去web.config里面去翻翻,我们可以看到UrlRoutingModule的配置节:
 
       
下面要做的就顺理成章了,用Reflector打开这个程序集,可以看到以下代码:
 
2.gif
3.gif
Code
 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).
源文档  
 
 PostMapRequestHandler event
Occurs when ASP.NET has mapped the current request to the appropriate event handler.
源文档  
 
    我们使用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文件切入,下面是一段样例代码,这里初始化了路由表,请特别特别注意注释部分:
 
4.gif
5.gif
Code
     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.
 

6.gif
7.gif
PostResolveRequestCache
8.gif
    public virtual void PostResolveRequestCache(HttpContextBase context)
9.gif
10.gif
11.png
{
12.gif
    RouteData routeData = this.RouteCollection.GetRouteData(context);
13.gif
    if (routeData != null)
14.gif
15.gif
    
16.png
{
17.gif
        IRouteHandler routeHandler = routeData.RouteHandler;
18.gif
        if (routeHandler == null)
19.gif
20.gif
        
21.png
{
22.gif
            throw new InvalidOperationException(string.Format(CultureInfo.CurrentUICulture, RoutingResources.UrlRoutingModule_NoRouteHandler, new object[0]));
23.gif
        }
24.gif
        if (!(routeHandler is StopRoutingHandler))
25.gif
26.gif
        
27.png
{
28.gif
            RequestContext requestContext = new RequestContext(context, routeData);
29.gif
            IHttpHandler httpHandler = routeHandler.GetHttpHandler(requestContext);
30.gif
            if (httpHandler == null)
31.gif
32.gif
            
33.png
{
34.gif
35.gif
                throw new InvalidOperationException(string.Format(CultureInfo.CurrentUICulture, RoutingResources.UrlRoutingModule_NoHttpHandler, new object[] 
36.png
{ routeHandler.GetType() }));
37.gif
            }
38.gif
            RequestData data2 = new RequestData();
39.gif
            data2.OriginalPath = context.Request.Path;
40.gif
            data2.HttpHandler = httpHandler;
41.gif
            context.Items[_requestDataKey] = data2;
42.gif
            context.RewritePath("~/UrlRouting.axd");
43.gif
        }
44.gif
    }
45.gif
}
46.gif
47.png
 
  
MvcHandler.ProcessRequest()中首先使用HttpContextWrapper对HttpContext进行封装,封装的目的是为了解耦以获得可测试性.然后从RequestContext.RouteData中提取Controller名称.
ControllerBuilder.GetControllerFactory --> ControllerFactory.CreateController --> IController.Execute
ControllerBase实现了IController接口,在Initialize时将RequestContext封装成为ControllerContext,Controller继承自ControllerBase并实现抽象方法ExecuteCore()
 
48.png
 

 
在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
49.png
 
 
控制权归还到HttpApplication完成后续的生命周期.
 
嗯哼,全文完.
 
      最后跑题一句:要找工作了,有好机会联系我:mailto:ligaoren@gmail.com

 
50.png
51.png


来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
您需要登录后才可以回帖 登录 | 立即注册