标签:
首先我们知道http是一种无状态的请求,他的生命周期就是发出请求开始,到得到响应结束。那么MVC应用程序从发出请求到获得响应,都做了些什么呢?
本文我们会详细讨论MVC应用程序的生命周期和一个请求,从一个控件到另一个控件是怎样被处理的。我们还会详细介绍一下整个请求的生命周期中,用到的相关组件。在平常的开发过程中,我们可能知道怎样去使用MVC框架来处理相关的请求,大部分的时候我们只是在controller和action方法之间做相关的处理。
当我最开始学习使用mvc的时候,困扰我的一个问题就是,一个请求的流程控制是怎样的呢?从view到controller再到action之间经历了什么?那个时候我还不清楚HTTP module和HTTP handler在处理一个请求中扮演什么样的角色,起什么样的作用呢。毕竟MVC是一个web开发框架,肯定包含了http module和http handler在整个请求过程中。其实还有很多相关的组件包含在一个完整的mvc应用程序请求生命周期里,在整个请求过程中他们都扮演者非常重要的角色。尽管大部分时候我们都使用的是框架提供的默认的函数,但是如果我们了解了每个控件所扮演的角色,我们就可以轻松的扩展和使用我们自己实现的方法,就目前来说MVC是扩展性比较强的框架。下面是本章节的主要内容:
先看看下面这张图,描述了请求管道中的控件和所扮演的角色:
上图就是一个完整的mvc应用程序的一个http请求到响应的整个儿所经历的流程。从UrlRoutingModule拦截请求到最终ActionResult执行ExecuteResult方法生成响应。
下面我们就来详细讲解一下这些过程都做了些什么。
UrlRoutingModule
MVC应用程序的入口UrlRoutingModule
首先发起一个请求,会被UrlRoutingModule拦截。
从上图中我们看到UrlRoutingModule实现了接口IHttpModule,所以UrlRoutingModule是一种HttpModule。在这之前,所有的请求还不确定是被谁处理。就是在这个UrlRoutingModule里,决定了这个request是否被MVC应用程序处理。UrlRouting module会从路由表中选择一个相匹配的路由规则。
那么UrlRouting Module是如何选择匹配规则的呢?
我们看看我们新建的MVC应用程序,在App_Start文件夹下面有一个RouteConfig.cs类,这个类的内容如下:
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 ApiDemo 9 { 10 public class RouteConfig 11 { 12 public static void RegisterRoutes(RouteCollection routes) 13 { 14 routes.IgnoreRoute("{resource}.axd/{*pathInfo}"); 15 16 routes.MapRoute( 17 name: "Default", 18 url: "{controller}/{action}/{id}", 19 defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional } 20 ); 21 } 22 } 23 }
我们在这个类里面,主要是给路由表添加路由规则。在看看上面的UrlRoutingModule类,里面有一个RoutCollection属性,所以UrlRoutingModule能够获取路由表中的所有规则,这里值得注意的是,路由规则的匹配是有顺序的,如果有多个规则都能够匹配,UrlRoutingModule至选择第一个匹配的规则就返回,不再继续往下匹配了。相反的如果一个请求,没有匹配到任何路由,那么该请求就不回被处理。
RouteHandler
生成MvcHander
在上面路由匹配的过程中,与匹配路由相关联的MvcRouteHandler ,MvcRouteHandler 实现了IRouteHandler 接口。MvcRouteHandler 主要是用来获取对MvcHandler的引用。MvcHandler实现了IhttpHandler接口。
当MvcRouteHandler 被创建的时候,就会调用PostResolveRequestCache()方法。PostResolveRequestCache()方法的定义如下:
1 public virtual void PostResolveRequestCache(HttpContextBase context) { 2 RouteData routeData = this.RouteCollection.GetRouteData(context); 3 if (routeData != null) { 4 IRouteHandler routeHandler = routeData.RouteHandler; 5 6 IHttpHandler httpHandler = routeHandler.GetHttpHandler(requestContext);
PostResolveRequestCache()方法主要做的工作如下:
1、PostResolveRequestCache()是在UrlRoutingModule类里面,UrlRoutingModule类里面有一个RoutCollection属性,而这个属性有一个GetRouteData()方法,
我们看到PostResolveRequestCache()方法中恰好调用了GetRouteData()这个方法,然后返回了一个RouteData对象。
2、RouteData里面有一个IRouteHandler类型的属性RouteHandler ,而调用GetRouteData()返回的RouteData对象里的RouteHandler就是MvcRouteHandler。
3、MvcRouteHandler类有一个GetHttpHandler方法,返回的是一个IHttpHandler类型的对象,返回的就是对MvcHandler对象的引用,绑定到一个MvcHandler的实例。
下面我们就看看MvcHandler做了些什么:
MvcHandler就是最终对request进行处理。
MvcHandler的定义如下:
我们可以看到MvcHandler就是一个普通的Http Handler.我们知道一个http handler需要实现一个ProcessRequest()的方法,这个方法就是处理request的核心。所以MvcHandler实现了ProcessRequest()方法。
ProcessRequest()定义如下:
1 // Copyright (c) Microsoft Open Technologies, Inc.<pre>// All rights reserved. See License.txt in the project root for license information. 2 void IHttpHandler.ProcessRequest(HttpContext httpContext) 3 { 4 ProcessRequest(httpContext); 5 } 6 protected virtual void ProcessRequest(HttpContext httpContext) 7 { 8 HttpContextBase iHttpContext = new HttpContextWrapper(httpContext); 9 ProcessRequest(iHttpContext); 10 } 11 protected internal virtual void ProcessRequest(HttpContextBase httpContext) { 12 SecurityUtil.ProcessInApplicationTrust(() => { 13 IController controller; 14 IControllerFactory factory; 15 ProcessRequestInit(httpContext, out controller, out factory); 16 try 17 { 18 controller.Execute(RequestContext); 19 } 20 finally 21 { 22 factory.ReleaseController(controller); 23 } 24 }); 25 }
从上面的代码可以看出调用了一个ProcessRequestInit()方法,定义如下:
1 private void ProcessRequestInit(HttpContextBase httpContext, 2 out IController controller, out IControllerFactory factory) { 3 // If request validation has already been enabled, make it lazy. 4 // This allows attributes like [HttpPost] (which looks 5 // at Request.Form) to work correctly without triggering full validation. 6 bool? isRequestValidationEnabled = 7 ValidationUtility.IsValidationEnabled(HttpContext.Current); 8 if (isRequestValidationEnabled == true) { 9 ValidationUtility.EnableDynamicValidation(HttpContext.Current); 10 } 11 AddVersionHeader(httpContext); 12 RemoveOptionalRoutingParameters(); 13 // Get the controller type 14 string controllerName = RequestContext.RouteData.GetRequiredString("controller"); 15 // Instantiate the controller and call Execute 16 factory = ControllerBuilder.GetControllerFactory(); 17 controller = factory.CreateController(RequestContext, controllerName); 18 if (controller == null) { 19 throw new InvalidOperationException( 20 String.Format( 21 CultureInfo.CurrentCulture, 22 MvcResources.ControllerBuilder_FactoryReturnedNull, 23 factory.GetType(), 24 controllerName)); 25 } 26 }
在ProcessRequestInit()方法中首先创建了ControllerFactory()的对象 factory.然后ControllerFactory创建了相关Controller的实例.最终调用了Controller的Excute()方法。
好我们再来看看ControllerFactory:
主要是用来生成Controller对象
ControllerFactory实现了接口IControllerFactory.
Controller
到这里我们大概就知道了,MvcHandler通过ProcessRequest()方法最终创建了Controller对象,这里我们都应该知道,Controller里面包含很多的Action方法,每一次请求至少一个Action方法会被调用。为了明确的实现IController接口,框架里面有一个ControllerBase的类已经实现了IController接口,其实我们自己的Controller也可以不继承ControllerBase,只要实现IController接口即可。
1 public abstract class ControllerBase : IController 2 { 3 protected virtual void Execute(RequestContext requestContext) 4 { 5 if (requestContext == null) 6 { 7 throw new ArgumentNullException("requestContext"); 8 } 9 if (requestContext.HttpContext == null) 10 { 11 throw new ArgumentException( 12 MvcResources.ControllerBase_CannotExecuteWithNullHttpContext, 13 "requestContext"); 14 } 15 VerifyExecuteCalledOnce(); 16 Initialize(requestContext); 17 using (ScopeStorage.CreateTransientScope()) 18 { 19 ExecuteCore(); 20 } 21 } 22 protected abstract void ExecuteCore(); 23 // .......
controller对象实际上使用ActionInvoker来调用Action方法的,当Controller对象被创建后,会执行Controller对象的基类ControllerBase类里面的Excute方法。Excute方法又调用了ExcuteCore()方法。Controller类里面实现了ExcuteCore()方法。ExcuteCore调用了ActionInvoker的InvokerAction方法来调用Action方法。
ActionInvoker方法有很重要的责任来查找Controller中的Action方法并且调用。
ActionInvoker是一个实现了IActionInvoker接口的对象:
bool InvokeAction( ControllerContext controllerContext, string actionName )
Controller类里面暴露了一个ActionInvoker 属性,会返回一个ControllerActionInvoker 。ActionInvoker通过CreateActionInvoker()方法来创建ControllerActionInvoker对象。
public IActionInvoker ActionInvoker { get { if (_actionInvoker == null) { _actionInvoker = CreateActionInvoker(); } return _actionInvoker; } set { _actionInvoker = value; } } protected virtual IActionInvoker CreateActionInvoker() { return new ControllerActionInvoker(); }
我们看到CreateActionInvoker()是一个Virtual方法,我们可以实现自己的ActionInvoker.
ActionInvoker类需要匹配Controller中详细的Action来执行,而这些详细的信息是由ControllerDescriptor 提供的。ControllerDescriptor 和ActionDescriptor在ActionInvoker中扮演重要的角色。这两个分别是对Controler和Action的详细描述。ControllerDescriptor 描述了Controller的相关信息比如name,action,type等。
ActionDescriptor 描述了Action相关的详情,比如name,controller,parameters,attributes和fiflters等。
ActionDescriptor 中一个中要的方法就是FindAction(),这个方法返回一个ActionDescriptor 对象,所以ActionInvoker知道该调用哪个Action。
ActionResult
到目前为止,我们看到了Action方法被ActionInvoker调用。所有的Action方法有一个特性,就是返回一个ActionResult类型的数据。
public abstract class ActionResult { public abstract void ExecuteResult(ControllerContext context); }
ExecuteResult()是一个抽象方法,所以不同的子类可以提供不同的ExecuteResult()实现。
ActionResult执行后响应输出到客户端。
ViewResult几乎是大部分应用程序的返回类型,主要通过ViewEngine引擎来展示view的。ViewEngine可能主要就是生成Html元素的引擎。Framwork提供了2种引擎,Razor View Engine 和Web Form View Engine.如果你想自定义引擎,你可以创建一个引擎只要实现IViewEngine接口即可。
IViewEngine 有下面几个方法:
1、FindPartialView :当controller需要返回一个PartialView的时候,FindPartialView方法 就会被调用。
2、FindView
3、ReleaseView :主要用来有ViewEngine释放资源
ViewResultBase 和ViewResult是比较重要的两个类。ViewResultBase 包含下面的实现代码:
if (View == null) { result = FindView(context); //calls the ViewResult‘s FindView() method View = result.View; } ViewContext viewContext = new ViewContext(context, View, ViewData, TempData); View.Render(viewContext, context.HttpContext.Response.Output); protected abstract ViewEngineResult FindView(ControllerContext context); //this is implemented by //the ViewResult
protected override ViewEngineResult FindView(ControllerContext context) { ViewEngineResult result = ViewEngineCollection.FindView(context, ViewName, MasterName); if (result.View != null) { return result; } //rest of the code omitted }
当ViewResult的方法ExecuteResult被调用后,ViewResultBase 的ExecuteResult 方法被调用,然后ViewResultBase 调用ViewResult的FindView 。紧接着ViewResult 返回ViewEngineResult,之后ViewEngineResult调用Render()方法来绘制html输出响应。
总结:如果我们理解了整个过程中发生了什么,哪些类和哪些方法被调用,我们就可以在需要扩展的地方轻松的进行扩展。
标签:
原文地址:http://www.cnblogs.com/yplong/p/5582576.html