zoukankan      html  css  js  c++  java
  • ASP.NET MVC4学习笔记之Controller的激活

    一. 高层相关类说明

      当路由系统根据请求Url收集路由信息后,下一步就要将路由信息传给Controller激活系统,Controller激活系统负责实现了IController接口的Controller类实例化。它的相关类族体系如下图所示:

    MvcHandler实现了IHttpHandler, IHttpAsyncHandler,IRequiresSessionState三个接口,其中IHttpHandler, IHttpAsyncHandler分别是HttpHandler同步与异步的实现,IRequiresSessionState是个标记接口,表示需要Session支持. 

    IController, IAsyncController, ControllerBase, Controller 是一个继承体系,IController是控制器接口,只定义了一个方法Execute方法表示执行入口,

    IAsyncController是控制器的异步执行版本,ControllerBase是控制器基类,为控制器执行做一些初始化和环境准备工作,实现了Execute方法并在其内调用保护的抽像方法ExecuteCore.这个地方应用了Templete Method模式. Controller实现了一堆接口, 为我们编程提供方便, 定义了大量的属性和方法,具体的后面章节专门讲解.

    IControllerFactory 表示的是控制器的创建工厂,其中定义了三个方法, CreateController方法创建IController的实例, GetControllerSessionBehavior方法获取Controller的会话行为,我们可以在自定义的Controller的上应用SessionStateAttribute指定会话行为。ReleaseController负责释放使用完的Controller实例。

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

    ControllerBuilder 是负责实例化IController和IControllerFactory的接口,封装具体的创建算法。提供了一个静态只读属性Current表示当前的ControllerBuilder对象。

    二. MvcHandler中IController与IControllerFactory的创建与执行

    1. 主体过程ProcessRequest方法,代码如下所示, 创建的过程委托给私有方法ProcessRequestInit

    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);
      }
    }

     2. ProcessRequestInit方法的主要代码如下所示,我们可以看到最终的创建工作是交给了ControllerBuilder对象.

    private void ProcessRequestInit(HttpContextBase httpContext, out IController controller, out IControllerFactory factory)
    {
      //其它代码
      // 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(...)
      }
    }

     三.ControllerBuilder解析

     1.接口定义如下:

      public class ControllerBuilder

      {
        public ControllerBuilder();

        public static ControllerBuilder Current { get; }  //
        public HashSet<string> DefaultNamespaces { get; } //默认命名空间,用于Controller类型解析过程

        public IControllerFactory GetControllerFactory(); 
        public void SetControllerFactory(IControllerFactory controllerFactory); //设置自定义ControllerFactory
        public void SetControllerFactory(Type controllerFactoryType); //设置自定义ControllerFactory的类型, 
      }

      ControllerBuilder主要封装了IControllerFactory的创建过程,也许命名叫ControllerFactoryBuilder更合适,从接口可以看出,我们可以传入自定义

    实现的IControllerFactory。

     2. 内部引用的几个主要类说明:

      

       IResolver<T> 只定义了一个泛型属性,表示获取相关类型的一个实例;

       SingleServiceResolver<TService> 顾名思义,表示单一服务类型解析,它实现在了IResolver接口, 在ControllerBuilder内部使用的是SingleServiceResolver<IControllerFactory>;

       DefaultControllerFactory 系统提供的默认的Controller创建工厂实现;

     3. 内部IControllerFactory创建过程

        在ControllerBuilder实例化时,调用默认构造函数,而默认构造函数调用如下的内部构造函数,serviceResolver传值为null,

      internal ControllerBuilder(IResolver<IControllerFactory> serviceResolver)

      {
        _serviceResolver = serviceResolver ?? new SingleServiceResolver<IControllerFactory>(
           () => _factoryThunk(),
           new DefaultControllerFactory { ControllerBuilder = this },
            "ControllerBuilder.GetControllerFactory");
      }

      _factoryTunk() 是一个返回IControllerFactory的委托(Func<IControllerFactory>),默认值是() => null; 其主要目的是当传入自定义IControllerFactory时做统一处理,

      public void SetControllerFactory(IControllerFactory controllerFactory)

      {
        _factoryThunk = () => controllerFactory;
      }

      ControllerBuilder返回IControllerFactory的方法内部实现如下:

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

        从上面的代码中我们可以看出Factory的创建过程进一步委托给了SingleServiceResolver对象,现在我们看看SingleServiceResolver究竟是怎么创建对象的

    .SingleServiceResolver<TService> 类型

      SingleServiceResolver其实ASP.NET MVC许多基础类型创建所遵询的一个模式. 它的构造函数如下:

      public SingleServiceResolver(Func<TService> currentValueThunk, TService defaultValue, string callerMethodName)

      {
        //省略检查代码

        _resolverThunk = () => DependencyResolver.Current; //  DependencyResolver.Current表示系统全局的对象解析器
        _currentValueFromResolver = new Lazy<TService>(GetValueFromResolver);  //从全局的Resolver器中创建对象
        _currentValueThunk = currentValueThunk; //当前传入的创建委托
        _defaultValue = defaultValue;   //默认值
        _callerMethodName = callerMethodName;
      }

      返回实例的代码如下

      public TService Current
      {
        get { return _currentValueFromResolver.Value ?? _currentValueThunk() ?? _defaultValue; }
      }

          从中我们可以看出SingleServiceResolver解析对象的过程:

      1. 首先从尝试从全局的对象解析器(DependencyResolver)中创建对象

      2. 否则尝试利用当前的功能委托来创建对象

      3. 最后返回对象的默认值

        在IControllerFactory创建中,默认情况下第1种和第2种情况都不起作用,所以返回的是DefaultControllerFactory, 现在我们终于得到了IControllerFactory实例,现在来看看它是怎么生成Controller实例的。

    五.DefaultControllerFactory解析

      DefaultControllerFactory实现了IControllerFactory, 故名思义,它的主要作用就是Controller实例的创建与释放,会话模式的获取。

     1. Controller类型的实例化

      Controller实例的创建实现在CreateController方法中,主要的代码如下:

      public virtual IController CreateController(RequestContext requestContext, string controllerName)

      {
        //省略其它代码
        Type controllerType = GetControllerType(requestContext, controllerName);
        IController controller = GetControllerInstance(requestContext, controllerType);
        return controller;
      }

      可以看到分成了两步走,首先查找确定Controller的类型,接着再利用类型创建其实例。下面来具体的看看相关的方法

      1.1 Controller类型的查找

      类型的查找实现在GetControllerType方法中,代码如下:

      protected internal virtual Type GetControllerType(RequestContext requestContext, string controllerName)

      {

        // 省略其它代码

        //1. 首先检查在定制路由规则时指定的命名空间

        object routeNamespacesObj;

        Type match;

        if (requestContext != null && routeData.DataTokens.TryGetValue(RouteDataTokenKeys.Namespaces, out routeNamespacesObj))
        {
          IEnumerable<string> routeNamespaces = routeNamespacesObj as IEnumerable<string>;
          if (routeNamespaces != null && routeNamespaces.Any())
          {
            HashSet<string> namespaceHash = new HashSet<string>(routeNamespaces, StringComparer.OrdinalIgnoreCase);
            match = GetControllerTypeWithinNamespaces(routeData.Route, controllerName, namespaceHash);

            // the UseNamespaceFallback key might not exist, in which case its value is implicitly "true"
            if (match != null || false.Equals(routeData.DataTokens[RouteDataTokenKeys.UseNamespaceFallback]))
            {
              // got a match or the route requested we stop looking
              return match;
            }
          }
          }

      // 检查默认的命名空间
      if (ControllerBuilder.DefaultNamespaces.Count > 0)
      {
        HashSet<string> namespaceDefaults = new HashSet<string>(ControllerBuilder.DefaultNamespaces, StringComparer.OrdinalIgnoreCase);
        match = GetControllerTypeWithinNamespaces(routeData.Route, controllerName, namespaceDefaults);
        if (match != null)
        {
          return match;
        }
      }

      //检查所有的命名空间,也就是只要有Controller名唯一匹配的就返回相应的Controller类型
      return GetControllerTypeWithinNamespaces(routeData.Route, controllerName, null /* namespaces */);

       这个方法是查找Controller类型的骨架,查找是由三个层次的命名空间组成,

     1.首先从制定路由规则时指定的命名空间中查找,但一般我们指定路由规则时没有指定命名空间,这里有还有一个参数UseNamespaceFallback表示是否查找后备命名空间,这个参数默认为true. 

      2. 从默认的命名空间ControllerBuilder.DefaultNamespaces中查找

      3. 从所有的命名空间中查找,查找唯一能匹配的Controller

      在以上查找中,都会调用GetControllerTypeWithinNamespaces方法,现在来看看这个方法的实现

      private Type GetControllerTypeWithinNamespaces(RouteBase route, string controllerName, HashSet<string> namespaces)
      {
        // Once the master list of controllers has been created we can quickly index into it
        ControllerTypeCache.EnsureInitialized(BuildManager);

        ICollection<Type> matchingTypes = ControllerTypeCache.GetControllerTypes(controllerName, namespaces);
        switch (matchingTypes.Count)
        {
          case 0:
          // no matching types
            return null;

          case 1:
          // single matching type
            return matchingTypes.First();

          default:
            // multiple matching types
          throw CreateAmbiguousControllerException(route, controllerName, matchingTypes);
        }
       }

       从以上的代码中我们可以看到查找工作又进一步委托给了ControllerTypeCache这个内部类型,这个类型是特意为实现快速查找Controller类型而设计的一个数据结构,在内部它把所有的Controller通过反射把数据组织成如下形式:

       controllerAName      namespace1,  Type

                     namespace2,   Type

       controllerBName     namespace1,  Type

                     namespace2,   Type

                 ...

      当我们调用ControllerTypeCache.GetControllerTypes,传入controllerName, namespaces参数时,首先会通过controllerName得到匹配的namespace和Type列表,

    再利用传入的namespaces参数与列表中的每个namespace进行比较,匹配则将相应的类型加入返回列表,如果传入的namespaces为null, 则直接将列表中所有的类型都加入返回列表,在GetControllerTypeWithinNamespaces方法中我们检查返回结果,如果只有一个类型,这是我们想要的结果,则直接返回,有一个以上则抛出Ambiguous异常。至此我们确定了Controller的类型,现在来看看Controller的实例化。

        1.2 Controller类型的实例化

        在前面我们已经看到,Controller类型实例化是实现在GetControllerInstance方法中,代码如下:

        protected internal virtual IController GetControllerInstance(RequestContext requestContext, Type controllerType)

        {

          //省略非关键代码
          return ControllerActivator.Create(requestContext, controllerType);
        }

      直接调用了ControllerActivator来创建实例,ControllerActivator是一个类型为IControllerActivator的属性,IControllerActivator的定义如下:

       public interface IControllerActivator

      {
        IController Create(RequestContext requestContext, Type controllerType);
      }

      具体来看看ControllerActivator属性的定义,

        private IControllerActivator ControllerActivator
       {
          get
          {
            if (_controllerActivator != null)
            {
              return _controllerActivator;
            }
            _controllerActivator = _activatorResolver.Current;
            return _controllerActivator;
          }
      }

      这里_controllerActivator在DefaultControllerFactory构造函数中初始化,代表传入自定义的Controller激活器.具有最高的优先级。

    _activatorResolver是IResolver<IControllerActivator>类型, 也是在构造函数中初始化,允许自定义实现IResolver<IControllerActivator>,具有第二高的优先级,

    但在默认情况一下,前面两个参数都为null, _activatorResolver被实例化为SingleServiceResolver<IControllerActivator>类型。具体我们来看看DefaultControllerFactory的构造函数:

      internal DefaultControllerFactory(IControllerActivator controllerActivator, IResolver<IControllerActivator> activatorResolver, IDependencyResolver     dependencyResolver)

      {
        if (controllerActivator != null)
        {
          _controllerActivator = controllerActivator;
        }
        else
        {
          _activatorResolver = activatorResolver ?? new SingleServiceResolver<IControllerActivator>(
            () => null,
            new DefaultControllerActivator(dependencyResolver),
            "DefaultControllerFactory constructor");
        }
      }

      SingleServiceResolver<T>泛型类前面已分析,这里不再赘述,从上面的代码中我们看到,默认情况下Controller实例化最终落在了DefaultControllerActivator的头上,

    再来看看该类型的实现:

      private class DefaultControllerActivator : IControllerActivator

      {
        private Func<IDependencyResolver> _resolverThunk;

        public DefaultControllerActivator()
          : this(null)
        {
        }

        public DefaultControllerActivator(IDependencyResolver resolver)
        {
          if (resolver == null)
          {
            _resolverThunk = () => DependencyResolver.Current;
          }
          else
           {
            _resolverThunk = () => resolver;
           }
          }

       public IController Create(RequestContext requestContext, Type controllerType)
       {
         try
         {
          return (IController)(_resolverThunk().GetService(controllerType) ?? Activator.CreateInstance(controllerType));
        }
        catch (Exception ex)
        {
          throw new InvalidOperationException(...)
        }
       }
      }

       DefaultControllerActivator构造函数允许传一个IDependencyResolver 对象,从上面的代码中我们可以看出,优先使用该对象创建Conroller实例,

    如果该对象为null,则尝试使用系统默认的DependencyResolver,如果前面的两者IDependencyResolver创建失败,再使用Activator.CreateInstance实列化.

    在默认情况一下,Controller实例是通过DependencyResolver.Current实列化,最终也是调用Activator.CreateInstance实例化的。

     2. Controller实例的释放

       释放的实现代码很简单,即检查Controller是否实现了IDisposable 接口,如果实现该接口则调用其Dispose()方法。

      public virtual void ReleaseController(IController controller)

      {
        IDisposable disposable = controller as IDisposable;
        if (disposable != null)
        {
          disposable.Dispose();
        }
      }

    3.Controller会话行为的设置

      3.1 会话行为获取

        controller会话行为的获取是通过反射得到应用在Controller上的SessionStateAttribute,具体的实现在代码在GetControllerSessionBehavior中,

        protected internal virtual SessionStateBehavior GetControllerSessionBehavior(RequestContext requestContext, Type controllerType)
        {
          if (controllerType == null)
          {
            return SessionStateBehavior.Default;
          }

          return _sessionStateCache.GetOrAdd(
            controllerType,
            type =>
            {
              var attr = type.GetCustomAttributes(typeof(SessionStateAttribute), inherit: true)
              .OfType<SessionStateAttribute>()
              .FirstOrDefault();

              return (attr != null) ? attr.Behavior : SessionStateBehavior.Default;
          });
        }

        从上面的代码中可以看出,如果没在Controller上的指定特别的Session行为,会返回SessionStateBehavior.Default,表示由IHttpHandler实现的会话标记接口来确定会话行为,MvcHandler标记了IRequiresSessionState,表示Session可读可写.

      3.2 会话行为设置

        会话行为设置是在MvcRouteHandler中,具本的代码如下:

        protected virtual IHttpHandler GetHttpHandler(RequestContext requestContext)

        {

          //设置会话行为
          requestContext.HttpContext.SetSessionStateBehavior(GetSessionStateBehavior(requestContext));
          return new MvcHandler(requestContext);
        }

        protected virtual SessionStateBehavior GetSessionStateBehavior(RequestContext requestContext)
        {

          //省略非关键代码

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

    六总结

        在本小节中,我们在源代码级别分析了ControllerFacotry和Controller实例的创建过程,从中可以看出ASP.NET MVC框架定义很多的扩展点,

      下一节我们来看看具体Controller激活相关的扩展应用。

  • 相关阅读:
    springboo 添加logback日志
    logback配置日志输出
    认知升级:提升理解层次的NLP思维框架
    2019第29周日
    《如何有效社交》晨读笔记
    控制论模型&心流模型&波模型
    数学中常见的思维模型
    分布式服务跟踪系统
    Spring Cloud Sleuth
    微服务调用跟踪
  • 原文地址:https://www.cnblogs.com/jjyjjyjjy/p/3597647.html
Copyright © 2011-2022 走看看