MVC Controller

先回顾下之前的MVC执行过程:

一个HttpRequest是如何被ASP.NET和ASP.NET MVC框架执行的:经过IIS和ASP.NET处理后,Core Routing会首先根据URL匹配物理路径上的文件,如果不能匹配则由核心路由模块执行路由,路由被匹配后,MvcRouteHandler会将这个请求“带入”MVC框架,执行Controller和Action。

 

Controller是如何被创建以及执行的呢?

我们看一下MVCRouteHander的源码:

View Code
namespace System.Web.Mvc
{
    public class MvcRouteHandler : IRouteHandler
    {
        private IControllerFactory _controllerFactory;

        public MvcRouteHandler()
        {
        }

        public MvcRouteHandler(IControllerFactory controllerFactory)
        {
            _controllerFactory = controllerFactory;
        }

        protected virtual IHttpHandler GetHttpHandler(RequestContext requestContext)
        {
            requestContext.HttpContext.SetSessionStateBehavior(GetSessionStateBehavior(requestContext));
            return new MvcHandler(requestContext);
        }

        protected virtual SessionStateBehavior GetSessionStateBehavior(RequestContext requestContext)
        {
            string controllerName = (string)requestContext.RouteData.Values["controller"];
            if (String.IsNullOrWhiteSpace(controllerName))
            {
                throw new InvalidOperationException(MvcResources.MvcRouteHandler_RouteValuesHasNoController);
            }

            IControllerFactory controllerFactory = _controllerFactory ?? ControllerBuilder.Current.GetControllerFactory();
            return controllerFactory.GetControllerSessionBehavior(requestContext, controllerName);
        }

        #region IRouteHandler Members

        IHttpHandler IRouteHandler.GetHttpHandler(RequestContext requestContext)
        {
            return GetHttpHandler(requestContext);
        }

        #endregion
    }
}

MvcRouteHandler的实现仅仅是通过GetHttpHandler方法返回一个MvcHandler实例。

再来看一下MvcHandler的实现:

 

 


核心方法依然是ProcessRequest(异步版BeginProceessRequest)。

protected internal virtual void ProcessRequest(HttpContextBase httpContext)
        {
            IController controller;
            IControllerFactory factory;
            ProcessRequestInit(httpContext, out controller, out factory);

            try
            {
                controller.Execute(RequestContext);
            }
            finally
            {
                factory.ReleaseController(controller);
            }
        }
ProcessRequestInit方法实现了Controller的创建

private void ProcessRequestInit(HttpContextBase httpContext, out IController controller, out IControllerFactory factory)
        {
            // If request validation has already been enabled, make it lazy. This allows attributes like [HttpPost] (which looks
            // at Request.Form) to work correctly without triggering full validation.
            // Tolerate null HttpContext for testing.
            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 and call Execute
            factory = ControllerBuilder.GetControllerFactory();
            controller = factory.CreateController(RequestContext, controllerName);
            if (controller == null)
            {
                throw new InvalidOperationException(
                    String.Format(
                        CultureInfo.CurrentCulture,
                        MvcResources.ControllerBuilder_FactoryReturnedNull,
                        factory.GetType(),
                        controllerName));
            }
        }

MvcHandler从RouteData中获得controller名字负责创建一个ControllerBuilder的实例,并通过ControllerBuilder的GetControllerFactory返回一个IControllerFactory的实例,这个实例就是DefaultControllerFactory,它的 CreateController方法负责创建需要的Controller实例

 

// Get the controller type
string controllerName = RequestContext.RouteData.GetRequiredString("controller");
// Instantiate the controller and call Execute
factory = ControllerBuilder.GetControllerFactory();
controller = factory.CreateController(RequestContext, controllerName);

 


Controller的执行:

Controller继承自ControllerBase,而Controller又继承自IController,而IController的定义非常简单:

namespace System.Web.Mvc
{
    public interface IController
    {
        void Execute(RequestContext requestContext);
    }
}

只有一个Execute()接口。从接口定义可以看出,当Controller被“调用”的时候,应该负责完成Execute方法,参数RequestContext封装了HttpContext。

打开Controller源文件并没有发现Execute()方法的实现,那么它应该在ControllerBase中,查看ControllerBase发现,在,Execute在内部调用ExecuteCore,ExecuteCore作为一个抽象方法,延迟到Controller中实现。ControllerBase只提供了诸如TempData、ViewData等,Controller的ExecuteCore方法真正invoke了action机制,是action的入口。下面的代码是ExecuteCore的实现:

 

 protected override void ExecuteCore()
        {
            // If code in this method needs to be updated, please also check the BeginExecuteCore() and
            // EndExecuteCore() methods of AsyncController to see if that code also must be updated.

            PossiblyLoadTempData();
            try
            {
                string actionName = RouteData.GetRequiredString("action");
                if (!ActionInvoker.InvokeAction(ControllerContext, actionName))
                {
                    HandleUnknownAction(actionName);
                }
            }
            finally
            {
                PossiblySaveTempData();
            }
        }

 

可以看到RouteData在这里又提供了action参数,可以想象InvokeAction方法依靠这个action的名字调用action,并实现诸多验证机制

 

 

posted @ 2012-07-17 00:59  Johnny Yan  阅读(2231)  评论(0编辑  收藏  举报