博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
白话学习MVC(三)页面周期二
阅读量:7110 次
发布时间:2019-06-28

本文共 8700 字,大约阅读时间需要 29 分钟。

这一节就是介绍负责处理请求的MvcHandlerProcessRequest方法里的两个方法。

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.ControllerBaseprotected 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
// System.Web.Mvc.Controllerpublic IActionInvoker ActionInvoker{    get    {        if (this._actionInvoker == null)        {            this._actionInvoker = this.CreateActionInvoker(); //此方法 New了一个ControllerActionInvoker实例,并返回。        }        return this._actionInvoker;    }    set    {        this._actionInvoker = value;    }}

 

上述执行的this.ActionInvoker.InvokeAction(base.ControllerContext, requiredString)

即:执行ControllerActionInvoker实例的InvokeAction(...)方法

此方法执行的大概流程:

Action的执行包括两部分:Action方法本身的执行;相关筛选器的执行;

  1. 获取ControllerDescriptor对象,此对象的作用是:封装描述控制器的信息,如控制器的名称、类型和操作。
  2. 获取ActionDescriptor对象,此对象的作用:提供有关操作方法的信息,如操作方法的名称、控制器、参数、特性和筛选器。
  3. 查找Controller和Action声明的所有Attribute(筛选器Filter),并执行相关的筛选器。
  4. 获取Action需要的参数
  5. 执行Action
  6. 将ActionResult呈现到客户端

ASP.NET MVC的筛选器是基于AOP(面向方面编程)的设计,我们将一些非业务的逻辑实现在响应的筛选器,并以一种横切(Crosscutting)的方式应用到Action方法上。在Action方法执行前后,这些筛选器会自动执行。ASP.NET MVC提供了AuthorizationFilter,ActionFilter,ResultFilter和ExceptionFilter四种筛选器。

// System.Web.Mvc.ControllerActionInvokerpublic 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)。返回的类型作用:对使用 特性时所需的信息进行封装。 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
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和数据装配的到一块。

自此请求结束。

执行顺序如图:

result

此图摘自:http://kb.cnblogs.com/page/47224/

 

转载地址:http://hdlhl.baihongyu.com/

你可能感兴趣的文章
Python图表绘制工具:Matplotlib_Part 1
查看>>
去中心化交易所在2019年的发展趋势
查看>>
第2章 css边框属性
查看>>
Android 组件化之路
查看>>
react学习笔记
查看>>
Retrofit系列
查看>>
我的js日记-对象字面量知识串烧
查看>>
算法与数据结构1800题 之线性表 (三)
查看>>
node中间层实现文件上
查看>>
spring cloud构建互联网分布式微服务云平台-高可用的服务注册中心
查看>>
分布式服务防雪崩熔断器,Hystrix理论+实战。
查看>>
从0开始学习Stream
查看>>
Python爬取豆瓣电影的短评数据并进行词云分析处理
查看>>
Android开发之从零开始学RxJava 2.x(一)认识Rxjava
查看>>
(十三)spring cloud微服务分布式云架构-服务容错保护(Hystrix断路器)
查看>>
39 Combination Sum
查看>>
未来人工智能可能会拥有情绪
查看>>
如何优雅地使用 rm 防止误删除?
查看>>
servlet 的实现方法
查看>>
linux dhcp服务器 超级作用域
查看>>