MVC Controller的激活

各Controller的繼承關係html

Controller最重要的是對Execute方法的調用,當目標Controller對象被激活後,對請求的後續處理和最終響應均是經過執行這個Execute方法來完成。它就定義在IController接口中,以下所示:緩存

public interface IController
{
    void Execute(RequestContext requestContext);
}

因爲定義在IController接口的Execute方法是以同步的方式執行的,爲了異步方式,又另定義了一個IAsyncController接口,它派生於IController接口,Controller的異步執行經過前後調用BeginExecute/EndExecute方法來完成。以下所示:session

public interface IAsyncController : IController
{
    IAsyncResult BeginExecute(RequestContext requestContext, AsyncCallback callback, object state);
    void EndExecute(IAsyncResult asyncResult);
}

默認做爲全部Controller基類的ControllerBase實現了IController接口,ControllerBase是一個抽像類,它「顯示」的實現了IController中的Execute方法,而後它會調用這個類中受保護的虛方法Execute,然後者最終又會調用抽象方法ExecuteCore。以下所示:mvc

public abstract class ControllerBase : IController
{
    //省略
    public ControllerContext ControllerContext { get; set; }
    
    void IController.Execute(RequestContext requestContext)
    {
        Execute(requestContext);
    }
    protected virtual void Execute(RequestContext requestContext)
    {
        //省略
        VerifyExecuteCalledOnce();
        Initialize(requestContext);

        using (ScopeStorage.CreateTransientScope())
        {
            ExecuteCore();
        }
    }

    protected abstract void ExecuteCore();
    
    protected virtual void Initialize(RequestContext requestContext)
    {
        ControllerContext = new ControllerContext(requestContext, this);
    }
    //省略
}

從上面咱們能夠看到受保護的虛方法Execute在調ExecuteCore抽像方法以前,會執行受保護的虛方法Initialize方法初始化ControllerContext屬性。ControllerContext以下所示:app

public class ControllerContext
{ 
    public virtual ControllerBase Controller { get; set; }
    public virtual HttpContextBase HttpContext
    {
        get
        {
            if (_httpContext == null)
            {
                _httpContext = (_requestContext != null) ? _requestContext.HttpContext : new EmptyHttpContext();
            }
            return _httpContext;
        }
        set { _httpContext = value; }
    }
    public virtual RouteData RouteData
    {
        get
        {
            if (_routeData == null)
            {
                _routeData = (_requestContext != null) ? _requestContext.RouteData : new RouteData();
            }
            return _routeData;
        }
        set { _routeData = value; }
    }
    public RequestContext RequestContext
    {
        get
        {
            if (_requestContext == null)
            {
                // still need explicit calls to constructors since the property getters are virtual and might return null
                HttpContextBase httpContext = HttpContext ?? new EmptyHttpContext();
                RouteData routeData = RouteData ?? new RouteData();

                _requestContext = new RequestContext(httpContext, routeData);
            }
            return _requestContext;
        }
        set { _requestContext = value; }
    }
    
    public ControllerContext(HttpContextBase httpContext, RouteData routeData, ControllerBase controller)
                : this(new RequestContext(httpContext, routeData), controller)
    {
    }
    public ControllerContext(RequestContext requestContext, ControllerBase controller)
    {
        //省略
        RequestContext = requestContext;
        Controller = controller;
    }
}

顧名思義,ControllerContext就是基於某個Controller對象上下文。從上面咱們能夠看出ControllerContext主要是對Controller、RequestContext對象的封裝。而對RequestContext又是對HttpContext和RouteData的封裝。框架

 VS幫咱們建立的Controller默認都是繼承自抽像類Controller,它是ControllerBase的子類,以下所示:異步

public abstract class Controller : ControllerBase, IActionFilter, IAuthenticationFilter, IAuthorizationFilter, IDisposable, IExceptionFilter, IResultFilter, IAsyncController, IAsyncManagerContainer
{
    protected virtual bool DisableAsyncSupport
    {
        get { return false; }
    }
    
    IAsyncResult IAsyncController.BeginExecute(RequestContext requestContext, AsyncCallback callback, object state)
    {
        return BeginExecute(requestContext, callback, state);
    }

    void IAsyncController.EndExecute(IAsyncResult asyncResult)
    {
        EndExecute(asyncResult);
    }
    protected virtual IAsyncResult BeginExecute(RequestContext requestContext, AsyncCallback callback, object state)
    {
        if (DisableAsyncSupport)
        {
            //同步
            Action action = () =>
            {
                Execute(requestContext);
            };
            //省略
        }
        else
        {
           //異步
           //省略
        }
    }


    protected virtual void EndExecute(IAsyncResult asyncResult)
    {
        AsyncResultWrapper.End(asyncResult, _executeTag);
    }

}

public interface IAsyncManagerContainer
{
    AsyncManager AsyncManager { get; }
}

 Controller還顯示地實現了IAsyncController接口和ASP.NET MVC 5種過慮器接口,以及一個特別的IAsyncManagerContainer接口,它提供了一個AsyncManger對象爲異步操做的執行提供參數傳遞操做計數和超時控制等功能,除此以外Controller還爲咱們實現IDispose接口,在Controller執行結束以後會調用其Dispose方法以完成相應的資源回收工做。async

從抽像類Controller的定義上來看,它實現了IAsyncController,而IAsyncController繼承自IController,這意味着它既能夠採用同步(調用Execute方法)又能夠採用異步(調用BeginExecute/EndExecute)的方法執行。可是調用BeginExecute/EndExecute方法也不必定是以異步的方式執行。如上代碼所示中它有一個DisableAsyncSupport屬性,它默認值爲False。ide

 

在ASP.NET MVC中還定義了一個AsyncController類,從名稱上咱們能夠看出這是一個異步Controller。但這裏指的是Action方法的異步,而不是Controller的異步執行。以下所示:函數

public abstract class AsyncController : Controller
{
}

這是一個繼承自抽像類Controller的一個「空」類型,由於在ASP.NET MVC 3.0時,異步的執行是經過XxxAsync/XxxCompleted的形式定義,以這種方式定義的異步Action方法必須定義在繼承自AsyncController的類型中。考慮到向後兼容,因而就一直保留了下來。不過在 ASP.NET MVC4.0及之後,提供了新的異步Action方法定義方式。它直接定義在咱們建立的繼承自抽像Controller類的子類Controller中就行了,Action方法返回類型爲Task既可。

 Controller的激活

首先來看一下IControllerFactory接口,以下所示:

public interface IControllerFactory
{
    IController CreateController(RequestContext requestContext, string controllerName);
    SessionStateBehavior GetControllerSessionBehavior(RequestContext requestContext, string controllerName);
    void ReleaseController(IController controller);
}

 從上代碼咱們看到Controller對象的激活最終是經過CreateController方法來完成的。除了負責建立Controller對象外,還須要處理Controller對象的釋放,這個定義在ReleaseController方法中。IControllerFactory還定義一個方法 GetControllerSessionBehavior,返回一個枚舉類型SessionStateBehavior,它表示請求處理過程當中會話狀態支持的模式。具體採用何種會話狀態模式取決於當前HTTP上下文(經過HttpContext的靜態屬性Current表示)。在 ASP.NET 3.0及以前的版本,咱們是不能對當前HttpContext會話狀態模式進行動態修改。ASP.NET 4.0爲HttpContext定義了以下SetSessionStateBehavior方法,相同的方法在HttpContextBase、HttpContextWrapper都有定義。

public abstract class HttpContextBase : IServiceProvider
{
    public virtual void SetSessionStateBehavior(SessionStateBehavior sessionStateBehavior)
    {
    }
}
public class HttpContextWrapper : HttpContextBase
{
    public override void SetSessionStateBehavior(SessionStateBehavior sessionStateBehavior)
    {
        this._context.SetSessionStateBehavior(sessionStateBehavior);
    }
}

public sealed class HttpContext : IServiceProvider, IPrincipalContainer
{
    public void SetSessionStateBehavior(SessionStateBehavior sessionStateBehavior)
    {
        //省略
        this.SessionStateBehavior = sessionStateBehavior;
    }
}

  用於激活Controller對象的ControllerFactory最終是經過ControllerBuilder註冊到MVC框架中的,代碼以下:

public class ControllerBuilder
{
    private static ControllerBuilder _instance = new ControllerBuilder();
    public static ControllerBuilder Current
    {
        get { return _instance; }
    }
    public ControllerBuilder(): this(null)
    {
    }

    internal ControllerBuilder(IResolver<IControllerFactory> serviceResolver)
    {
        _serviceResolver = serviceResolver ?? new SingleServiceResolver<IControllerFactory>(
                                                    () => _factoryThunk(),
                                                    new DefaultControllerFactory { ControllerBuilder = this },
                                                    "ControllerBuilder.GetControllerFactory");
    }
    public void SetControllerFactory(IControllerFactory controllerFactory)
    {
        //省略
        _factoryThunk = () => controllerFactory;
    }

    public void SetControllerFactory(Type controllerFactoryType)
    {
       //省略
        _factoryThunk = delegate
        {
            return (IControllerFactory)Activator.CreateInstance(controllerFactoryType);
        };
    }

    public IControllerFactory GetControllerFactory()
    {
        return _serviceResolver.Current;
    }
}

 從上代碼片斷中,咱們能夠看到一個Current屬性返回當前使用的ControllerBuilder對象,以及兩個SetControllerFactory方法重載實現針對ControllerFactory的註冊和一個GetControllerFactory方法用於獲取ControllerFactory對象。 關於兩個重載方法,它們的不一樣之處在於第一個是傳入一個IControllerFactory對象,第二個是傳入一個IControllerFactory類型。若是是經過第二個的方法註冊ControllerFactory,那麼咱們在每次獲取時,都要經過反射得到某個ControllerFactory的實例,MVC將不會對它所建立的Controller進行緩存。而第一個則直接將IControllerFactory對象返回。從性能方面考慮,第一種的方式更好一些,在構造函數中咱們也能夠看到默認就是經過new一個DefaultControllerFactory對象。

 

在《簡說mvc路由》一文中咱們介紹過MVC是經過UrlRoutingModule對HttpApplication上的PostResovleRequestCache事件的註冊攔截請求。而後從RouteTable的靜態屬性Routes中對請求實施路由解析生成一個RouteData對象,而後藉助RouteData的RouteHandler屬性獲得最終的被映射到當前請求的HttpHandler。

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"];
        //省略
        IControllerFactory controllerFactory = _controllerFactory ?? ControllerBuilder.Current.GetControllerFactory();
        return controllerFactory.GetControllerSessionBehavior(requestContext, controllerName);
    }
}

 在上一篇文章中,咱們知道MVC框架中,對RouteHandler默認實現就是MvcRouteHandler。在MvcRouteHandler中維護着一個ControllerFactory對象,該對象能夠在構造函數中指定,若是沒有指定,那麼它會調用當前ControllerBuilder對象GetControllerFactory方法獲得這個對象。在實例化Route時,咱們傳的是new MvcRouteHandler()時,是調用無參構造函數的,因此在這裏_controllerFactory確定爲null,而在上面ControllerBuilder類的代碼片斷中,Current是經過new了一個ControllerBuilder無參構造函數,因此MVC默認ControllerFactory的實現是DefaultControllerFactory。不過這裏得到ControllerFactory只是用於設置會話狀態方式。真正得到ControllerFactory用於建立Controller對象體如今MvcHandler的BeginProcessRequest方法中。

 接下來咱們主要看IHttpHandler的實現類MvcHandler,以下所示:

public class MvcHandler : IHttpAsyncHandler, IHttpHandler, IRequiresSessionState
{
    internal ControllerBuilder ControllerBuilder
    {
        get
        {
            if (_controllerBuilder == null)
            {
                _controllerBuilder = ControllerBuilder.Current;
            }
            return _controllerBuilder;
        }
        set { _controllerBuilder = value; }
    }
    protected internal virtual IAsyncResult BeginProcessRequest(HttpContextBase httpContext, AsyncCallback callback, object state)
    {
        IController controller;
        IControllerFactory factory;
        ProcessRequestInit(httpContext, out controller, out factory);

        IAsyncController asyncController = controller as IAsyncController;
        if (asyncController != null)
        {
            // asynchronous controller

            // Ensure delegates continue to use the C# Compiler static delegate caching optimization.
            BeginInvokeDelegate<ProcessRequestState> beginDelegate = delegate(AsyncCallback asyncCallback, object asyncState, ProcessRequestState innerState)
            {
                try
                {
                    return innerState.AsyncController.BeginExecute(innerState.RequestContext, asyncCallback, asyncState);
                }
                catch
                {
                    innerState.ReleaseController();
                    throw;
                }
            };

            EndInvokeVoidDelegate<ProcessRequestState> endDelegate = delegate(IAsyncResult asyncResult, ProcessRequestState innerState)
            {
                try
                {
                    innerState.AsyncController.EndExecute(asyncResult);
                }
                finally
                {
                    innerState.ReleaseController();
                }
            };
            ProcessRequestState outerState = new ProcessRequestState() 
            {
                AsyncController = asyncController, Factory = factory, RequestContext = RequestContext
            };
            
            SynchronizationContext callbackSyncContext = SynchronizationContextUtil.GetSynchronizationContext();
            return AsyncResultWrapper.Begin(callback, state, beginDelegate, endDelegate, outerState, _processRequestTag, callbackSyncContext: callbackSyncContext);
        }
        else
        {
            // synchronous controller
            Action action = delegate
            {
                try
                {
                    controller.Execute(RequestContext);
                }
                finally
                {
                    factory.ReleaseController(controller);
                }
            };

            return AsyncResultWrapper.BeginSynchronous(callback, state, action, _processRequestTag);
        }
    }
    private void ProcessRequestInit(HttpContextBase httpContext, out IController controller, out IControllerFactory factory)
    {
        //省略
        string controllerName = RequestContext.RouteData.GetRequiredString("controller");
        //省略
        factory = ControllerBuilder.GetControllerFactory();
        controller = factory.CreateController(RequestContext, controllerName);
        //省略
    }
}

 從上咱們能夠看到MvcHandler同時實現了IHttpAsyncHandler和IHttpHandler接口,因此它老是以異步的方式被執行(調用BeginProcessRequest和EndProcessRequest方法)。調用ProcessRequestInit方法中,經過RequestContext的RouteData屬性得到controller名稱,而後經過本類的ControllerBuilder屬性得到ControllerFactory類的實例factory,而後經過它得到Controller的對象,而後調用Controller中的Execute方法或異步BeginExecute/EndExecute方法。

關於DefaultControllerFactory建立Controller以下所示:

public class DefaultControllerFactory : IControllerFactory
{
    private IControllerActivator ControllerActivator
    {
        get
        {
            if (_controllerActivator != null)
            {
                return _controllerActivator;
            }
            _controllerActivator = _activatorResolver.Current;
            return _controllerActivator;
        }
    }

    public virtual IController CreateController(RequestContext requestContext, string controllerName)
    {
        if (requestContext == null)
        {
            throw new ArgumentNullException("requestContext");
        }

        if (String.IsNullOrEmpty(controllerName) && !requestContext.RouteData.HasDirectRouteMatch())
        {
            throw new ArgumentException(MvcResources.Common_NullOrEmpty, "controllerName");
        }

        Type controllerType = GetControllerType(requestContext, controllerName);
        IController controller = GetControllerInstance(requestContext, controllerType);
        return controller;
    }

    protected internal virtual IController GetControllerInstance(RequestContext requestContext, Type controllerType)
    {
        //省略
        return ControllerActivator.Create(requestContext, controllerType);
    }
    //省略
}
相關文章
相關標籤/搜索