zoukankan      html  css  js  c++  java
  • 白话学习MVC(三)页面周期二

    这一节就是介绍负责处理请求的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.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
    // System.Web.Mvc.Controller
    public 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.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和数据装配的到一块。

    自此请求结束。

    执行顺序如图:
    result

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

  • 相关阅读:
    BZOJ_2039_[2009国家集训队]employ人员雇佣_ 最小割
    BZOJ_4238_电压_树上差分+dfs树
    BZOJ_4516_[Sdoi2016]生成魔咒_后缀数组+ST表+splay
    BZOJ_3048_[Usaco2013 Jan]Cow Lineup _双指针
    BZOJ_3689_异或之_可持久化Trie+堆
    BZOJ_2006_[NOI2010]超级钢琴_贪心+堆+ST表
    BZOJ_3675_[Apio2014]序列分割_斜率优化
    BZOJ_4518_[Sdoi2016]征途_斜率优化
    BZOJ_1407_[Noi2002]Savage_EXGCD
    [转载]ubuntu常用命令
  • 原文地址:https://www.cnblogs.com/wupeiqi/p/2981636.html
Copyright © 2011-2022 走看看