zoukankan      html  css  js  c++  java
  • [Web API] Web API 2 深入系列(2) 消息管道

    目录

    1. HttpMessageHandler

    2. Web Host模式处理过程

    3. Self Host模式处理过程

    HttpMessageHandler

    Web API处理管道由一系列HttpMessageHandler组成

    public abstract class HttpMessageHandler : IDisposable
    {
        protected internal abstract Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken);
        
        protected virtual void Dispose(bool disposing)
    
        public void Dispose()
    }
    

    而一般在管道中,我们使用DelegatingHandler

    public abstract class DelegatingHandler : HttpMessageHandler
    {
        public HttpMessageHandler InnerHandler { get; set; }
        protected internal override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
        {
            return this.innerHandler.SendAsync(request, cancellationToken);
        }
    }
    

    头部是HttpServer

    public class HttpServer : DelegatingHandler
    {
        public HttpMessageHandler Dispatcher { get; }
        public HttpConfiguration Configuration { get; }
        protected virtual void Initialize()
        {
            this.InnerHandler = HttpClientFactory.CreatePipeline(this._dispatcher, (IEnumerable<DelegatingHandler>) this._configuration.MessageHandlers);
        }
        protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
        {
            this.EnsureInitialized();
            return await base.SendAsync(request, cancellationToken);
        }
    }
    

    其中Dispatcher就是管道的尾部
    默认为HttpRoutingDispatcher

    public class HttpRoutingDispatcher : HttpMessageHandler
    {
        public HttpConfiguration Configuration { get; }
        private readonly HttpMessageInvoker _defaultInvoker = new HttpControllerDispatcher(configuration);
    
        public HttpRoutingDispatcher(HttpConfiguration configuration, HttpMessageHandler defaultHandler)
    
        protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
        {
            //1. Routing
            IHttpRouteData routeData = request.GetRouteData();
            if (routeData == null)
            {
            routeData = this._configuration.Routes.GetRouteData(request);
            if (routeData != null)
                request.SetRouteData(routeData);
            }
            //2. Dispatcher
            this._defaultInvoker.SendAsync(request, cancellationToken);
        }
    }
    

    实现Dispatcher(选择IHttpController)的对象默认为HttpControllerDispatcher

    public class HttpControllerDispatcher : HttpMessageHandler
    {
        protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
        {
            HttpControllerDescriptor controllerDescriptor = this.ControllerSelector.SelectController(request);
            IHttpController controller = controllerDescriptor.CreateController(request);
            return await controller.ExecuteAsync(controllerContext, cancellationToken);
        }
    }
    

    验证管道

    public class DemoController : ApiController
    {
        public IEnumerable<string> Get()
        {
            var cfg = new HttpConfiguration();
            cfg.MessageHandlers.Add(new Handler1());
            cfg.MessageHandlers.Add(new Handler1());
            cfg.MessageHandlers.Add(new Handler1());
            var server = new MyServer(cfg);
            server.Initialize();//生成HttpMessageHandler链
            return GetHandlers(server);
        }
    
        private IEnumerable<string> GetHandlers(MyServer server)
        {
            DelegatingHandler next = server;
            yield return next.ToString();
            while (next.InnerHandler != null)
            {
                yield return next.InnerHandler.ToString();
                next = next.InnerHandler as DelegatingHandler;
                if (next == null)
                    break;
            }
        }
    }
    class MyServer : HttpServer
    {
        public MyServer(HttpConfiguration cfg) : base(cfg) { }
    
        public new void Initialize()//暴露Initialize方法
        {
            base.Initialize();
        }
    }
    class Handler1 : DelegatingHandler
    {
        protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
        {
            throw new NotImplementedException();
        }
    }
    

    浏览器中请求:

    Web Host模式处理过程

    上节我们说到HttpControllerHandler为Web Host下的处理程序.

    public class HttpControllerHandler : HttpTaskAsyncHandler
    {
        private readonly HttpMessageInvoker _server = GlobalConfiguration.DefaultServer;
    
        public override Task ProcessRequestAsync(HttpContext context)
        {
            response = await this._server.SendAsync(request, cancellationToken);
            await response.Content.CopyToAsync(context.Response.OutputStream);
        }
    }
    

    从上面的代码中我们看到

    1. HttpControllerHandler实现的是异步HttpControllerHandler接口

    2. 在ProcessRequestAsync方法中 通过GlobalConfiguration.DefaultServer 启动了WebAPI管道

    Self Host模式处理过程

    Self Host目前可以说分为2种

    1. OWIN
    2. HttpBinding

    本节重点说明一下传统方式的HttpBinding,WebAPI使用的Message为HttpMessage
    通过Nuget可以非常方便的操作

    Install-Package Microsoft.AspNet.WebApi.SelfHost

    using (var server = new HttpSelfHostServer(new HttpSelfHostConfiguration("http://localhost:10000")))
    {
        server.Configuration.Routes.MapHttpRoute("default", "{controller}");
        server.OpenAsync();
        Console.Read();
    }
    

    接下来我们将定义一个HttpSelfHostServer来实现SelfHost

    API是不是相比SelfHost更方便?

    using (var server = new MyHttpSelfHostServer("http://localhost:10000"))
    {
        server.Configuration.Routes.MapHttpRoute("default", "{controller}");
        server.OpenAsync();
        Console.Read();
    }
    

    再看看我们具体的MyHttpSelfHostServer如何实现

    public class MyHttpSelfHostServer : HttpServer
    {
        private string _url;
        public MyHttpSelfHostServer(string url)
        {
            _url = url;
        }
    
        public async void OpenAsync()
        {
            var binding = new HttpBinding();
            var listener = binding.BuildChannelListener<IReplyChannel>(new Uri(_url));
            listener.Open();//开启监听
            var reply = listener.AcceptChannel();
            reply.Open();//开启通信通道
            while (true)
            {
                var request = reply.ReceiveRequest();//接受到请求
                //获取HttpRequestMessage
                var method = request.RequestMessage.GetType().GetMethod("GetHttpRequestMessage");
                var requestMessage = method.Invoke(request.RequestMessage, new object[] { true }) as HttpRequestMessage;
                var response = await base.SendAsync(requestMessage, new CancellationTokenSource().Token);
                request.Reply(CreateMessage(response));//回复消息
            }
        }
    
        Message CreateMessage(HttpResponseMessage response)
        {
            var type = Type.GetType("System.Web.Http.SelfHost.Channels.HttpMessage,System.Web.Http.SelfHost");
            return (Message)Activator.CreateInstance(type, response);
        }
    }
    

    最后我们来请求一下地址:http://localhost:10000/Demo

    备注:

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

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

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

  • 相关阅读:
    maven使用杂记
    Gradle中的SourceSet理解
    CyclicBarrier正确的使用方法和错误的使用方法
    jstack 结果查看
    java1.8中ConcurrentHashMap
    grub2配置关键(三个核心变量prefix、root、cmdpath)和几点疑问
    关于docker的理解随记
    docker中的命令参数(小白常用)
    tmux快捷键汇总(常用)
    archlinux安装gnome的一些坑随记
  • 原文地址:https://www.cnblogs.com/neverc/p/5949974.html
Copyright © 2011-2022 走看看