zoukankan      html  css  js  c++  java
  • [Web API] Web API 2 深入系列(3) 激活HttpController

    目录

    1. HttpController

    2. 创建HttpController

      • IAssembliesResolver
      • IHttpControllerTypeResolver
      • HttpControllerTypeCache
      • IHttpControllerSelector
    3. ServicesContainer

    从上节我们知道,在消息管道中,最终在HttpControllerDispatcher的SendAsync方法中会创建IHttpController.

    HttpController

    我们先看看IHttpController

    public interface IHttpController
    {
        Task<HttpResponseMessage> ExecuteAsync(HttpControllerContext controllerContext, CancellationToken cancellationToken);
    }
    

    IHttpController设计很像HttpMessageHandler,只不过参数由HttpRequestMessage变成了HttpControllerContext

    public  public class HttpControllerContext
    {
        HttpControllerContext(HttpRequestMessage request, HttpControllerDescriptor controllerDescriptor)
    }
    

    可以看出HttpControllerContext实际就是包装了一下HttpRequestMessage和HttpControllerDescriptor

    而HttpControllerDescriptor则是真正创建IHttpController的对象

    public class HttpControllerDescriptor
    {
        public virtual IHttpController CreateController(HttpRequestMessage request)
        {
        //通过内置的轻量级容器创建
          return this.Configuration.Services.GetHttpControllerActivator().Create(request, this, this.ControllerType);
        }
    }
    

    本节重点就是介绍HttpControllerDescriptor的CreateController方法

    创建HttpController

    在谈创建HttpController前,我们需要了解HttpControllerDescriptor是如何被创建的
    整个创建过程需要经历以下步骤

    IAssembliesResolver

    首先通过IAssembliesResolver找出符合的程序集

    默认的实现是找出当前应用程序域中的程序集

    public class DefaultAssembliesResolver : IAssembliesResolver
    {
        public virtual ICollection<Assembly> GetAssemblies()
        {
            return (ICollection<Assembly>) ((IEnumerable<Assembly>) AppDomain.CurrentDomain.GetAssemblies()).ToList<Assembly>();
        }
    }
    

    而在WebHost下,在HttpConfiguration的创建过程中替换为WebHostAssembliesResolver

    internal sealed class WebHostAssembliesResolver : IAssembliesResolver
    {
        ICollection<Assembly> IAssembliesResolver.GetAssemblies()
        {
            //所有引用的程序集
            return (ICollection<Assembly>) BuildManager.GetReferencedAssemblies().OfType<Assembly>().ToList<Assembly>();
        }
    }
    

    IHttpControllerTypeResolver

    在列出可用的Assemblies后,会通过IHttpControllerTypeResolver找出所有的IHttpController
    默认实现为DefaultHttpControllerTypeResolver

    public class DefaultHttpControllerTypeResolver : IHttpControllerTypeResolver
    {
        public virtual ICollection<Type> GetControllerTypes(IAssembliesResolver assembliesResolver)
        {
            foreach (Assembly assembly in (IEnumerable<Assembly>) assembliesResolver.GetAssemblies())
            {
                typeArray = assembly.GetTypes();
                return typeArray.Where<Type>(x => this.IsControllerTypePredicate(x));
            }
        }
    
        internal static bool IsControllerType(Type t)
        {
            //IsClass IsVisible !IsAbstract IHttpController
          if (t != (Type) null && t.IsClass && (t.IsVisible && !t.IsAbstract) && typeof (IHttpController).IsAssignableFrom(t))
            return DefaultHttpControllerTypeResolver.HasValidControllerName(t);
          return false;
        }
    }
    

    IHttpControllerSelector

    当找到所有HttpController后,IHttpControllerSelector用来选择能够生成HttpControllerDescriptor(当同一个Controller名在不同的命名空间下,这时是WebAPI会抛弃这2个Controller)

    默认实现为DefaultHttpControllerSelector

    public class DefaultHttpControllerSelector : IHttpControllerSelector
    {
        //根据请求 选择对应的HttpControllerDescriptor
        public virtual HttpControllerDescriptor SelectController(HttpRequestMessage request)
        {
            string controllerName = this.GetControllerName(request);
            HttpControllerDescriptor controllerDescriptor;
            if (GetControllerDescriptor(controllerName, out controllerDescriptor))
                return controllerDescriptor;
            return null;
        }
    
        //从路由变量controller中获取ControllerName
        public virtual string GetControllerName(HttpRequestMessage request)
        {
          string str;
          request.GetRouteData().Values.TryGetValue<string>("controller", out str);
          return str;
        }
    
        public HttpControllerDescriptor GetControllerDescriptor(string controllerName,out HttpControllerDescriptor controllerDescriptor)
        {
            //去除同名Controller
            var keys = ControllerTypeCache.Cache.Where(x=>x.Value.Count == 1).Select(x=>x.Key);
            foreach(var key in keys){
                //...
                return new HttpControllerDescriptor(...);
            }
        }
    }
    

    HttpControllerTypeCache

    这里再补充一点:
    在DefaultHttpControllerSelector的代码中,我们使用ControllerTypeCache.Cache

    实际上由于频繁的反射创建Controller,WebAPI通过缓存Controller避免了不必要的损失.

    同时在DefaultHttpControllerSelector代码中也存在相应的缓存措施(文中的代码为了便于理解).

    internal sealed class HttpControllerTypeCache
    {
        public HttpControllerTypeCache(HttpConfiguration configuration)
        {
            Cache = GetCache(configuration);//该处同样为伪代码
        }
        internal Dictionary<string, ILookup<string, Type>> Cache {get;}
    }
    

    通过上面的流程,我们清楚了HttpControllerDescriptor是如何创建的,同时创建完HttpControllerDescriptor后,调用CreateController即可创建 public virtual IHttpController CreateController(HttpRequestMessage request)

    ServicesContainer

    在Web API消息管道中,定义了很多接口,对应的也有很多实现类.

    WebAPI自定义了一套DI容器ServicesContainer.而这个容器直接挂在HttpConfiguration上

    public class HttpConfiguration : IDisposable
    {
        public ServicesContainer Services { get; internal set; }
        public HttpConfiguration(HttpRouteCollection routes)
        {
            this.Services = (ServicesContainer) new DefaultServices(this);
        }
    }
    

    在默认的实现DefaultServices 则定义了WebAPI 默认对应的实现

    public class DefaultServices : ServicesContainer
    {
        private readonly Dictionary<Type, object> _defaultServicesSingle = new Dictionary<Type, object>();
    
        public DefaultServices(HttpConfiguration configuration)
        {
            //...
            this.SetSingle<IAssembliesResolver>((IAssembliesResolver) new DefaultAssembliesResolver());
            this.SetSingle<IHttpControllerActivator>((IHttpControllerActivator) new DefaultHttpControllerActivator());
            this.SetSingle<IHttpControllerSelector>((IHttpControllerSelector) new DefaultHttpControllerSelector(configuration));
            this.SetSingle<IHttpControllerTypeResolver>((IHttpControllerTypeResolver) new DefaultHttpControllerTypeResolver());
        }
        //设置接口实现
        private void SetSingle<T>(T instance) where T : class
        {
          this._defaultServicesSingle[typeof (T)] = (object) instance;
        }
        //获取接口实现
        public override object GetService(Type serviceType)
        {
            return this._defaultServicesSingle[serviceType];
        }
    }
    

    备注:

    • 文章中的代码并非完整WebAPI代码,一般是经过自己精简后的.

    • 本篇内容使用MarkDown语法编辑

    首发地址:http://neverc.cnblogs.com/p/5952821.html

  • 相关阅读:
    sql server实用要点全解
    C# EntityFramwork(Model First)使用要点
    c# linq查询语句详细使用介绍
    c# webapi2 实用详解
    create-react-app脚手架中配置sass
    redux使用教程详细介绍
    react-router4.x 实用例子(路由过渡动画、代码分割)
    react-router4.x 组件和api介绍
    leetcode-mid-backtracking -22. Generate Parentheses-NO
    leetcode-mid-backtracking-17. Letter Combinations of a Phone Number
  • 原文地址:https://www.cnblogs.com/neverc/p/5952821.html
Copyright © 2011-2022 走看看