带你读开源—ASP.NET_MVC(二)

来源:互联网 发布:linux shell 编程入门 编辑:程序博客网 时间:2024/05/18 03:57

        上篇文章从整体上介绍了ASP.NET MVC的请求处理流程,大概分为“路由”、“控制器”、“视图”以及“模型”,下面便按照流程依次展开。

        一、路由

        提到路由,实际上分为ASP.NET的核心路由引擎和MVC路由。核心路由引擎是不开源的(微软留了一手),它负责解析浏览器端传来的URL,并为之分配控制器。

这里我们要分析的是MVC路由,即MvcRouteHandler,该类显式实现了IRouteHandler接口,它的GetHttpHandler方法返回了一个MvcHandler对象,而MvcHandler实现了IHttpHandler接口,所以它包含一个ProcessRequest方法,如下:

      

  protected internal virtual voidProcessRequest(HttpContextBase httpContext)        {            IController controller;            IControllerFactory factory;            ProcessRequestInit(httpContext, outcontroller, out factory);             try            {               controller.Execute(RequestContext);            }            finally            {               factory.ReleaseController(controller);            }        }

代码段 1

这个ProcessRequest方法相信大家都会觉得脸熟吧?不错,我们在ASP.NET WebForm开发中,经常会用到一般处理程序,即.ashx文件,这个文件中的类就实现了IHttpHandler接口,也有一个ProcessRequest方法。

好了,这个ProcessRequest方法就是路由定位到控制器后,执行的核心操作。也就是说,controller.Execute(RequestContext)语句的执行,导致了HTML响应的生成及回送浏览器。简单吧?我们在这里只是提到了最核心、最骨架的部分,没有涉及细节,为的就是不让大家被细枝末节所干扰。接下来就该分析控制器了。

二、控制器

代码段1中的controller是接口IController的一个实例,而接口IController很简单,只有一个方法如下:

<pre name="code" class="csharp">    public interface IController    {        void Execute(RequestContextrequestContext);    }


代码段 2

Controller的实例化是由【ProcessRequestInit(httpContext, out controller, out factory)】这个语句完成的,下面我们看一下ProcessRequestInit这个方法中实例化Controller的部分,不考虑细节,直奔主题。

   

     private voidProcessRequestInit(HttpContextBase httpContext, out IController controller, outIControllerFactory factory)        {            // If request validation hasalready been enabled, make it lazy. This allows attributes like [HttpPost](which looks            // at Request.Form) to workcorrectly without triggering full validation.            // Tolerate null HttpContext fortesting.            HttpContext currentContext =HttpContext.Current;            if (currentContext != null)            {                bool?isRequestValidationEnabled =ValidationUtility.IsValidationEnabled(currentContext);                if (isRequestValidationEnabled== true)                {                   ValidationUtility.EnableDynamicValidation(currentContext);                }            }             AddVersionHeader(httpContext);            RemoveOptionalRoutingParameters();             // Get the controller type            string controllerName =RequestContext.RouteData.GetRequiredString("controller");             // Instantiate the controller andcall Execute            factory =ControllerBuilder.GetControllerFactory();            controller =factory.CreateController(RequestContext, controllerName);            if (controller == null)            {                throw newInvalidOperationException(                    String.Format(                        CultureInfo.CurrentCulture,                       MvcResources.ControllerBuilder_FactoryReturnedNull,                        factory.GetType(),                        controllerName));            }        }

代码段 3

代码段3中的【controller = factory.CreateController(RequestContext,controllerName)】语句,就是实例化控制器的地方,这里根据路由系统定位的控制器信息(即我们在Controller文件夹中定义的各个控制器类),利用反射创建控制器对象。当然,这里面还有很多实现细节,比如控制器工厂、请求验证等,为了保持脉络清晰,在此略过,下文再谈。

IController接口在MVC中有若干个内置的实现类,包括ControllerBase以及IAsyncController,而Controller是ControllerBase的子类,是我们最常用的控制器基类。

其实,我们完全可以自己实现IController,例如:

publicclass MyController : IController{public voidExecute(RequestContext requestContext){requestContext.HttpContext.Response.Write(“Hello”);}}

代码段 4

怎么样?SoEasy!完全可以不用什么高大上的Razor引擎之类的东东。但是这样做会导致极强的耦合,我们需要自己解析拼接HTML,这可是个累人的活儿。

我们还是看看MVC的Controller类是怎么实现的吧。Controller继承于ControllerBase类,ControllerBase实现了Execute方法(代码段5),而Controller重写了ControllerBase的ExecuteCore方法(代码段6)。

      

  protected virtual voidExecute(RequestContext requestContext)        {            if (requestContext == null)            {                throw newArgumentNullException("requestContext");            }            if (requestContext.HttpContext ==null)            {                throw newArgumentException(MvcResources.ControllerBase_CannotExecuteWithNullHttpContext,"requestContext");            }             VerifyExecuteCalledOnce();            Initialize(requestContext);             using(ScopeStorage.CreateTransientScope())            {                ExecuteCore();            }        }

代码段 5

        

protected override void ExecuteCore()        {            // If code in this method needs tobe updated, please also check the BeginExecuteCore() and            // EndExecuteCore() methods ofAsyncController to see if that code also must be updated.             PossiblyLoadTempData();            try            {                string actionName =GetActionName(RouteData);                if(!ActionInvoker.InvokeAction(ControllerContext, actionName))                {                   HandleUnknownAction(actionName);                }            }            finally            {                PossiblySaveTempData();            }        }

代码段 6

我们看一下ExecuteCore方法,其核心语句是【if (!ActionInvoker.InvokeAction(ControllerContext, actionName))】,这条语句就是执行某个具体Action的地方,该语句执行完后,HTTP响应就被发回了浏览器。这里用到了ActionInvoker.InvokeAction方法,其中的ActionInvoker是IActionInvoker接口的实例,该接口定义也相当简单,如下:

    public interface IActionInvoker    {        bool InvokeAction(ControllerContextcontrollerContext, string actionName);    }


代码段 7

MVC内置的IActionInvoker实现类有ControllerActionInvoker和IAsyncActionInvoker,后者是异步类,先不管它,这里我们重点分析一下ControllerActionInvoker。

ControllerActionInvoker的InvokeAction方法实现较为复杂,有大概90行代码。今天有点累了,明天继续。

0 0
原创粉丝点击