详解ASP.NET MVC的请求生命周期(2)

 

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

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

顺便说一下,这种新的路由构架可以脱离ASP.NET MVC独立使用。Global.asax文件映射URL到MvcRouteHandler。然而,我们可以选择把URL路由到不同类型的Handler上。这里说的路由构架包含在一个叫做System.Web.Routing.dll的独立程序集中。我们可以脱离MVC使用路由。

步骤2:UrlRoutingModule拦截请求

当我们对ASP.NET MVC应用程序发起请求的时候,请求会被UrlRoutingModule HTTP Module拦截。HTTP Module是特殊类型的类,它参与每一次页面请求。例如,传统ASP.NET包含了FormsAuthenticationModule HTTP Module用来使用表单验证实现页面访问安全性。

UrlRoutingModule拦截请求后做的第一件事情就是包装当前的HttpContext为HttpContextWrapper2对象。HttpContextWrapper2类和派生自HttpContextBase的普通HttpContext类不同。创建的HttpContext的包装可以使使用诸如Typemock Isolator或Rhino Mocks的Mock对象框进行模拟变得更简单。

接着,Module把包装后的HttpContext传给在之前步骤中创建的RouteTable。HttpContext包含了URL、表单参数、查询字符串参数以及和当前请求关联的cookie。如果在当前请求和路由表中的路由对象之间能找到匹配,就会返回路由对象。

如果UrlRoutingModule成功获取了RouteData对象,Module然后就会创建表示当前HttpContext和RouteData的RouteContext对象。Module然后实例化基于RouteTable的新HttpHandler,并且把RouteContext传给Handler的构造函数。

对于ASP.NET MVC应用程序,从RouteTable返回的Handler总是MvcHandler(MvcRouteHandler返回MvcHandler)。只要UrlRoutingModule匹配当前请求到路由表中的路由,就会实例化带有当前RouteContext的MvcHandler。

Module进行的最后一步就是把MvcHandler设置为当前的HTPP Handler。ASP.NET应用程序自动调用当前HTTP Handler的ProcessRequest()方法然后转入下一步。

步骤3:执行MvcHandler

在之前的步骤中,表示某个RouteContext的MvcHandler被设置作为当前的HTTP Handler。ASP.NET应用程总是会发起一系列的事件,包括Star、BeginRequest、PostResolveRequestCache、 PostMapRequestHandler、PreRequestHandlerExecute和EndRequest事件(非常多的应用程序事件——对于完整列表,请查阅Visual Studio 2008文档中的HttpApplication类)。

之前内容中描述的所有东西都在PostResolveRequestCache和PostMapRequestHandler中发生。当前HTTP Handler的ProcessRequest()方法在PreRequestHandlerExecute事件之后被调用。

当之前内容中创建的MvcHandler对象的ProcessRequest()被调用的时候,会创建一个新的控制器。控制器由ControllerFactory创建。由于我们可以创建自己的ControllerFactory,所以这又是一个可扩展点。默认的ControllerFactory名字相当合适,叫做DefaultControllerFactory。

RequestContext以及控制器的名字被传入ControllerFactory.CreateController()方法来获得一个控制器。然后,从RequestContext和控制器构造ControllerContext对象。最后,调用控制器类的Execute()方法。在调用Execute()方法的时候会给方法传入ControllerContext。

步骤4:执行控制器

Execute()方法首先创建TempData对象(在Ruby On Rails中叫做Flash对象)。TempData可以用于保存下次请求必须的临时数据(TempData和会话状态差不多,不长期占用内存)。

接着,Execute()方法构建请求的参数列表。这些参数从请求参数中提取,将会被作为方法的参数。参数会被传入执行的控制器方法。

Execute()通过对控制器类进行反射来找到控制器的方法。控制器类是我们写的。Execute()方法找到了我们控制器类中的方法后就执行它。Execute()方法不会执行被装饰NonAction特性的方法。

至此,就进入了自己应用程序的代码。

步骤5:调用RenderView方法

通常,我们的控制器方法最后会调用RenderView()或RedirectToAction()方法。RenderView()方法负责把视图(页面)呈现给浏览器。

当我们调用控制器RenderView()方法的时候,调用会委托给当前ViewEngine的RenderView()方法。ViewEngine是另外一个扩展点。默认的ViewEngine是WebFormViewEngine。然而,我们可以使用诸如Nhaml的其它ViewEngine。

WebForm的ViewEngine.RenderView()方法创建了一个叫做ViewLocator的类来寻找视图。然后,它使用BuildManager来创建ViewPage类的实例。然后,如果页面有ViewData就会设置ViewData。最后,ViewPage 的RenderView()方法被调用。

ViewPage类从System.Web.UI.Page基类(和用于传统ASP.NET的页面一样)派生。RenderView()方法做的最后一个工作就是调用页面类的ProcessRequest()。调用视图的ProcessRequest()生成内容的方式和普通ASP.NET页面生成内容的方式一致。

可扩展点

ASP.NET MVC生命周期在设计的时候包含了很多可扩展点。我们可以自定义通过插入自定义类或覆盖既有类来自定义框架的行为。下面是这些扩展点的概要:

路由对象:当我们创建路由表的时候,调用RouteCollection.Add()方法来增加新的路由对象。Add()方法接受了RouteBase对象。我们可以通过派生RouteBase基类来实现自己的路由对象。

MvcRouteHandler :当创建MVC应用程序的时候,我们把URL映射到MvcRouteHandler对象上。然而,我们可以把URL映射到实现IRouteHandler接口的任何类上。路由类的构造函数接受任何实现IRouteHandler接口的对象。

MvcRouteHandler.GetHttpHandler() : MvcRouteHandler 类的GetHttpHandler()方法是virtual方法。默认情况下,MvcRouteHandler返回MvcHandler。如果愿意的话,我们可以覆盖GetHttpHandler()方法来返回不同的Handler。

ControllerFactory :我们可以通过System.Web.MVC.ControllerBuilder.Current.SetControllerFactory()方法指定一个自定义类来创建自定义的控制器工厂。控制器工厂负责为某个控制器名和RequestContext返回控制器。

控制器:我们可以通过实现Icontroller接口来实现自定义控制器。这个接口只有一个Execute(ControllerContext controllerContext)方法。

ViewEngine:我们可以为控制器指定自定义的ViewEngine。通过为公共的Controller.ViewEngine属性指定ViewEngine来把ViewEngine指定给控制器。ViewEngine必须实现IviewEngine接口,接口只有一个方法:RenderView(ViewContext viewContext)。

ViewLocator :ViewLocator把视图名映射到实际视图文件上。我们可以通过WebFormViewEngine.ViewLocator的属性来执行自定义的ViewLocator。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值