zoukankan      html  css  js  c++  java
  • 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);
        }
        //省略
    }
  • 相关阅读:
    python scrapy爬取前程无忧招聘信息
    scrf 原理及flask-wtf防护
    Django 惰性机制
    Django 中配置MySQL数据库
    Django的安装命令
    python装饰器
    python面向对象之继承
    OSI七层模型
    面向对象
    python函数
  • 原文地址:https://www.cnblogs.com/koeltp/p/7406928.html
Copyright © 2011-2022 走看看