MVC页面周期二
原文地址:http://www.cnblogs.com/wupeiqi/archive/2013/03/25/2981636.html
这一节就是介绍负责处理请求的MvcHandler的ProcessRequest方法里的两个方法。
public class MvcHandler : IHttpAsyncHandler, IHttpHandler, IRequiresSessionState
{
protected virtual void ProcessRequest(HttpContext httpContext)
{
//使用HttpContextWrapper对HttpContext进行封装,封装的目的是为了解耦以获得可测试性.然后从RequestContext.RouteData中提取Controller名称.
HttpContextBase httpContext2 = new HttpContextWrapper(httpContext);
this.ProcessRequest(httpContext2);
}
protected internal virtual void ProcessRequest(HttpContextBase httpContext)
{
IController controller;
IControllerFactory controllerFactory;
this.ProcessRequestInit(httpContext, out controller, out controllerFactory); //获取到Controler实例
try
{
//当前Controler对象的Action的创建与执行(执行包括:加载TempData, 创建及执行Action,处理Action返回的ActionResult ,保存TempData数据)
controller.Execute(this.RequestContext);
}
finally
{
//释放当前Controler对象
controllerFactory.ReleaseController(controller);
}
}
}
下面就来介绍红色字体的两个方法。
第一处红色字体部分:ProcessRequestInit(...)方法
private void ProcessRequestInit(HttpContextBase httpContext, out IController controller, out IControllerFactory factory)
{
//使用指定的 HTTP 上下文来添加版本标头。如:添加一个Http Header: HTTP/1.1 200 OK … X-AspNetMvc-Version: 2.0…
this.AddVersionHeader(httpContext);
this.RemoveOptionalRoutingParameters();
//RequestContext.RouteData中提取Controller名称。如:Home/Index的话,就获取到Home
string requiredString = this.RequestContext.RouteData.GetRequiredString("controller");
factory = this.ControllerBuilder.GetControllerFactory();//获取一个用于创建Controller实例的ControllerFactory.默认DefaultControllerFactory
controller = factory.CreateController(this.RequestContext, requiredString);//根据ControllerFactory创建Controller对象。
if (controller == null)
{
throw new InvalidOperationException(string.Format(CultureInfo.CurrentUICulture,MvcResources.ControllerBuilder_FactoryReturnedNull,new object[]
{
factory.GetType(),
requiredString
}));
}
}
由于使用了out关键字,这个方法中的执行过程中所得到的值,即:赋值给ProcessRequest方法中声明的Controller和ControllerFactory
第二处红色字体部分:controller.excute(...)方法
执行当前Controller实例的excute方法(继承自ControllerBase的方法)。action的创建和执行
// System.Web.Mvc.ControllerBase
protected virtual void Execute(RequestContext requestContext)
{
if (requestContext == null)
{
throw new ArgumentNullException("requestContext");
}
this.VerifyExecuteCalledOnce();
this.Initialize(requestContext); //创建ControllerContext类的一个实例
this.ExecuteCore(); //加载TempData,创建执行Action,处理Action返回的ActionResult,保存TempData
}
当前Controller实例的ExecuteCore方法
// System.Web.Mvc.Controller
protected override void ExecuteCore() { this.PossiblyLoadTempData();//加载TempData----------详细可读此博客
try { string requiredString = this.RouteData.GetRequiredString("action"); //从匹配好的路由中获取到访问的Action名称 if (!this.ActionInvoker.InvokeAction(base.ControllerContext, requiredString)) //创建Action,并处理Action返回的ActionResult { this.HandleUnknownAction(requiredString); } } finally { this.PossiblySaveTempData();//保存TempData } }
this.ActionInvoker即:Controller类的ActionInvoker属性。
this.ActionInvoker就是获的一个ControllerActionInvoker实例,该类负责调用控制器的操作方法。
View Code
上述执行的this.ActionInvoker.InvokeAction(base.ControllerContext, requiredString)
即:执行ControllerActionInvoker实例的InvokeAction(...)方法
此方法执行的大概流程:
Action的执行包括两部分:Action方法本身的执行;相关筛选器的执行;
- 获取ControllerDescriptor对象,此对象的作用是:封装描述控制器的信息,如控制器的名称、类型和操作。
- 获取ActionDescriptor对象,此对象的作用:提供有关操作方法的信息,如操作方法的名称、控制器、参数、特性和筛选器。
- 查找Controller和Action声明的所有Attribute(筛选器Filter),并执行相关的筛选器。
- 获取Action需要的参数
- 执行Action
- 将ActionResult呈现到客户端
ASP.NET MVC的筛选器是基于AOP(面向方面编程)的设计,我们将一些非业务的逻辑实现在响应的筛选器,并以一种横切(Crosscutting)的方式应用到Action方法上。在Action方法执行前后,这些筛选器会自动执行。ASP.NET MVC提供了AuthorizationFilter,ActionFilter,ResultFilter和ExceptionFilter四种筛选器。
// System.Web.Mvc.ControllerActionInvoker
public virtual bool InvokeAction(ControllerContext controllerContext, string actionName)
{
if (controllerContext == null)
{
throw new ArgumentNullException("controllerContext");
}
if (string.IsNullOrEmpty(actionName))
{
throw new ArgumentException(MvcResources.Common_NullOrEmpty, "actionName");
}
ControllerDescriptor controllerDescriptor = this.GetControllerDescriptor(controllerContext);//获取控制器信息
ActionDescriptor actionDescriptor = this.FindAction(controllerContext, controllerDescriptor, actionName);//获取Action信息
if (actionDescriptor != null)
{
FilterInfo filters = this.GetFilters(controllerContext, actionDescriptor);//检索有关操作筛选器的信息,并返回封装了有用筛选器(Filters)信息的对象。
try
{
//使用指定的操作描述符和控制器上下文来调用指定的授权筛选器(Filter)。返回的类型作用:对使用 AuthorizeAttribute 特性时所需的信息进行封装。
AuthorizationContext authorizationContext = this.InvokeAuthorizationFilters(controllerContext, filters.AuthorizationFilters, actionDescriptor);
//如果筛选器AuthorizationFilter不为空
if (authorizationContext.Result != null)
{
this.InvokeActionResult(controllerContext, authorizationContext.Result);//执行此Action上的筛选器AuthorizationFilter(Action执行之前)
}
else
{
if (controllerContext.Controller.ValidateRequest) //如果请求启用了请求验证
{
ControllerActionInvoker.ValidateRequest(controllerContext);
}
//获取Action所需要的参数
IDictionary<string, object> parameterValues = this.GetParameterValues(controllerContext, actionDescriptor);
ActionExecutedContext actionExecutedContext = this.InvokeActionMethodWithFilters(controllerContext, filters.ActionFilters, actionDescriptor, parameterValues);
this.InvokeActionResultWithFilters(controllerContext, filters.ResultFilters, actionExecutedContext.Result);
}
}
catch (ThreadAbortException)
{
throw;
}
catch (Exception exception)
{
ExceptionContext exceptionContext = this.InvokeExceptionFilters(controllerContext, filters.ExceptionFilters, exception);
if (!exceptionContext.ExceptionHandled)
{
throw;
}
this.InvokeActionResult(controllerContext, exceptionContext.Result);//参数二,就是指返回的ActionResult的类型。
}
return true;
}
return false;
}
用于处理请求的ASP.NET MVC 框架采用管道式设计,整个处理流程具有三个基本的环节,即:Action方法的执行、生成ActionResult和执行ActionResult。
ActionResult是一个抽象类,其中有一个抽象方法ExcuteResult。
这里的ActionResult是指继承了它,并实现了其抽象方法ExcuteResult。
有:EmptyResult、ContentResult、FileResult、JavaScripResult、JsonResult、ViewResult.....
执行ActionResult就是调用返回的ActionResult类的ExecuteResult方法。
例:假如Action方法中返回的是个ViewResult类型。
Action的返回的ActionResult就是一个ViewResult类。
这个ViewResult类的ExecuteResult(controllerContext)方法被执行。
protected virtual void InvokeActionResult(ControllerContext controllerContext, ActionResult actionResult) //假如返回的是一个ViewResult类型
{
actionResult.ExecuteResult(controllerContext);
}
此时请求到ViewResult后,ExecuteResult方法被调用,且看此方法的内部实现:
ViewResult类继承自ViewResultBase中的ExecuteResult方法。
//public class ViewResult : ViewResultBase
//public abstract class ViewResultBase : ActionResult
public override void ExecuteResult(ControllerContext context)
{
if (context == null)
{
throw new ArgumentNullException("context");
}
if (String.IsNullOrEmpty(ViewName))
{
ViewName = context.RouteData.GetRequiredString("action");
}
ViewEngineResult result = null;
if (View == null)
{
result = FindView(context);//通过视图引擎获取到ViewEngineResult ,此时模板页面【aspx】被加载成了对应的ViewPage类
View = result.View;
}
TextWriter writer = context.HttpContext.Response.Output;
ViewContext viewContext = new ViewContext(context, View, ViewData, TempData, writer);
View.Render(viewContext, writer);//通过FindView去搜索这个view找到这个view后通过viewRender(viewcontext,writer)进行渲染 最终生成html返回给客户 。
if (result != null)
{
result.ViewEngine.ReleaseView(context, View);
}
}
内部主要是通过ViewResult的FindView方法通过ViewEngine去加载具体的Aspx页面或者是cshtml页面生成对应的page类【针对Aspx】,然后再调用IView接口的Render方法将请求信息+ViewData的信息以等一块渲染成Html并写回到客户端。
在此阶段我们发现IViewEngine内部的实现这是到规定路径下去加载Aspx页面生成对应的ViewPage类。
IView接口的Render方法才是真正的去将Html和数据装配的到一块。
自此请求结束。
执行顺序如图:


浙公网安备 33010602011771号