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

        上篇文章从整体上介绍了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行代码。今天有点累了,明天继续。

你可能感兴趣的:(带你读开源—ASP.NET_MVC(二))