欢迎访问我的个人博客:三秋邦

MVC Controller的激活

各Controller的继承关系

Controller最重要的是对Execute方法的调用,当目标Controller对象被激活后,对请求的后续处理和最终响应均是通过执行这个Execute方法来完成。它就定义在IController接口中,如下所示:

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

由于定义在IController接口的Execute方法是以同步的方式执行的,为了异步方式,又另定义了一个IAsyncController接口,它派生于IController接口,Controller的异步执行通过先后调用BeginExecute/EndExecute方法来完成。如下所示:

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

默认作为所有Controller基类的ControllerBase实现了IController接口,ControllerBase是一个抽像类,它“显示”的实现了IController中的Execute方法,然后它会调用这个类中受保护的虚方法Execute,而后者最终又会调用抽象方法ExecuteCore。如下所示:

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如下所示:

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方法以完成相应的资源回收工作。

从抽像类Controller的定义上来看,它实现了IAsyncController,而IAsyncController继承自IController,这意味着它既可以采用同步(调用Execute方法)又可以采用异步(调用BeginExecute/EndExecute)的方法执行。但是调用BeginExecute/EndExecute方法也不一定是以异步的方式执行。如上代码所示中它有一个DisableAsyncSupport属性,它默认值为False。

 

在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);
    }
    //省略
}

 

posted @ 2017-08-22 16:15  追夢  阅读(961)  评论(0编辑  收藏  举报
欢迎访问我的个人博客:三秋邦