LoveCherry

技术无极限

博客园 首页 新随笔 联系 订阅 管理
  182 Posts :: 0 Stories :: 2496 Comments :: 553 Trackbacks
 

ASP.NET MVC深度接触:ASP.NET MVC请求生命周期

 

        翻译自: ASP.NET MVC In-Depth: The Life of an ASP.NET MVC Request 

        
这篇博文的目的旨在详细描述ASP.NET MVC请求从开始到结束的每一个过程。我希望能理解在浏览器输入URL并敲击回车来请求一个ASP.NET MVC网站的页面之后发生的任何事情。

       为什么需要关心这些?有两个原因。首先是因为ASP.NET MVC是一个扩展性非常强的框架。例如,我们可以插入不同的ViewEngine来控制网站内容呈现的方式。我们还可以定义控制器生成和分配到某个请求的方式。因为我想发掘任何ASP.NET MVC页面请求的扩展点,所以我要来探究请求过程中的一些步骤。

       其次,我对测试驱动开发佷感兴趣。要为控制器写单元测试,我们就必须理解控制器的依赖项。在写测试的时候,我需要使用诸如Typemock IsolatorRhino MocksMock框架来模拟某些对象。如果不了解页面请求生命周期就不能进行有效的模拟。

两个警告

       首先,要给大家两个警告。

       第一个警告:我在ASP.NET MVC Preview2对外发布之后写了此文。ASP.NET MVC框架在Beta前还会变化很大。因此,我在此文中描述的任何东西都会在几个月后不再有效。因此,如果你在20085月之后读此文的话,不要相信任何你读到的东西。

       第二,此文不是ASP.NET MVC的概览。我只是枯草地介绍了ASP.NET MVC请求的生命周期。好了,别说我没有提醒你。

生命周期步骤概览

       当我们对ASP.NET MVC网站发出一个请求的时候,会发生5个主要步骤:

1、步骤1——创建RouteTable

       ASP.NET应用程序第一次启动的时候才会发生第一步。RouteTableURL映射到Handler

2、步骤2——UrlRoutingModule拦截请求

       第二步在我们发起请求的时候发生。UrlRoutingModule拦截了每一个请求并且创建和执行合适的Handler

3、步骤3——执行MvcHandler

       MvcHandler创建了控制器,并且把控制器传入ControllerContext,然后执行控制器。

4、步骤4——执行控制器

       控制器检测要执行的控制器方法,构建参数列表并且执行方法。

5、步骤5——调用RenderView方法

       大多数情况下,控制器方法调用RenderView()来把内容呈现回浏览器。Controller.RenderView()方法把这个工作委托给某个ViewEngine来做。

       让我们详细研究每一个步骤。

步骤1——创建RouteTable

       当我们请求普通ASP.NET应用程序页面的时候,对于每一个页面请求都会在磁盘上有这样一个页面。例如,如果我们请求一个叫做SomePage.aspx的页面,在WEB服务器上就会有一个叫做SomePage.aspx的页面。如果没有的话,会得到一个错误。

       从技术角度说,ASP.NET页面代表一个类,并且不是普通类。ASP.NET页面是一个Handler。换句话说,ASP.NET页面实现了IhttpHandler接口并且有一个ProcessRequest()方法用于在请求页面的时候接受请求。ProcessRequest()方法负责生成内容并把它发回浏览器。

       因此,普通ASP.NET应用程序的工作方式佷简单明了。我们请求页面,页面请求对应磁盘上的某个页面,这个页面执行ProcessRequest()方法并把内容发回浏览器。

       ASP.NET MVC应用程序不是以这种方式工作的。当我们请求一个ASP.NET MVC应用程序的页面时,在磁盘上不存在对应请求的页面。而是,请求被路由转到一个叫做控制器的类上。控制器负责生成内容并把它发回浏览器。

       当我们写普通ASP.NET应用程序的时候,会创建很多页面。在URL和页面之间总是一一对应进行映射。每一个页面请求对应相应的页面。

       相反,当我们创建ASP.NET MVC应用程序的时候,创建的是一批控制器。使用控制器的优势是可以在URL和页面之间可以有多对一的映射。例如,所有如下的URL都可以映射到相同的控制器上。

http://MySite/Products/1

http://MySite/Products/2

http://MySite/Products/3

       这些URL映射到一个控制器上,通过从URL中提取产品ID来显示正确的产品。这种控制器方式比传统的ASP.NET方式更灵活。控制器方式可以产品更显而易见的URL

       那么,某个页面请求是怎么路由到某个控制器上的呢?ASP.NET MVC应用程序有一个叫做路由表(Route Table)的东西。路由表映射某个URL到某个控制器上。

       一个应用程序有一个并且只会有一个路由表。路由表在Global.asax文件中创建。清单1包含了在使用Visual Studio新建ASP.NET MVC Web应用程序时默认的Global.asax文件。

清单 1 – Global.asax

   1:  using System;

   2:  using System.Collections.Generic;

   3:  using System.Linq;

   4:  using System.Web;

   5:  using System.Web.Mvc;

   6:  using System.Web.Routing;

   7:   

   8:  namespace TestMVCArch

   9:  {

  10:      public class GlobalApplication : System.Web.HttpApplication

  11:      {

  12:          public static void RegisterRoutes(RouteCollection routes)

  13:          {

  14:              // Note: Change the URL to "{controller}.mvc/{action}/{id}" to enable

  15:              //       automatic support on IIS6 and IIS7 classic mode

  16:   

  17:              routes.Add(new Route("{controller}/{action}/{id}", new MvcRouteHandler())

  18:              {

  19:                  Defaults = new RouteValueDictionary(new { action = "Index", id = "" }),

  20:              });

  21:   

  22:              routes.Add(new Route("Default.aspx", new MvcRouteHandler())

  23:              {

  24:                  Defaults = new RouteValueDictionary(new { controller = "Home", action = "Index", id = "" }),

  25:              });

  26:          }

  27:   

  28:          protected void Application_Start(object sender, EventArgs e)

  29:          {

  30:              RegisterRoutes(RouteTable.Routes);

  31:          }

  32:      }

  33:  }

       应用程序的路由表由RouteTable.Routes的静态属性表示。这个属性表示了路由对象的集合。在清单1列出的Global.asax文件中,我们在应用程序首次启动时为路由表增加两个路由对象(Application_Start()方法在第一次请求网站页面的时候被调用一次)。

       路由对象负责把URL映射到Handler。在清单1中,我们创建了两个路由对象。这2个对象都把URL映射到MvcRouteHandler。第一个路由映射任何符合{controller}/{action}/{id}模式的URLMvcRouteHandler。第二个路由映射某个URL Default.aspxMvcRouteHandler

       顺便说一下,这种新的路由构