揭开HttpClient的“盖头”来(一)

之前的文章我已经大概介绍了httpclient的使用方法。那么作为想进步(zhuang bi)、追求真理(you jie cao)的一个码农,我们更想知道这个东东内部到底是怎么实现的呢?于是就有了该系列文章。
说明:由于源码分析本来就是枯燥乏味,有时候会很难懂。所以
作者将它按照系列分开来写。作者水平有限,写作过程中可能会错误或者不足,还请大家及时评论或者建议。我会针对您的反馈积极做出修改。在这里提前谢谢大家!!!

目录

HttpClient

话不多说先来一段源码。HttpClient位于System.Net.Http.dll命名空间中。

using System;
using System.Globalization;
using System.IO;
using System.Net.Http.Headers;
using System.Runtime.CompilerServices;
using System.Threading;
using System.Threading.Tasks;

namespace System.Net.Http
{
    [__DynamicallyInvokable]
    public class HttpClient : HttpMessageInvoker
    {
        [CompilerGenerated]
        [Serializable]
        private sealed class <>c
        {
            public static readonly HttpClient.<>c <>9 = new HttpClient.<>c();

            public static Func<HttpContent, Task<string>> <>9__26_0;

            public static Func<HttpContent, Task<byte[]>> <>9__28_0;

            public static Func<HttpContent, Task<Stream>> <>9__30_0;

            internal Task<string> <GetStringAsync>b__26_0(HttpContent content)
            {
                return content.ReadAsStringAsync();
            }

            internal Task<byte[]> <GetByteArrayAsync>b__28_0(HttpContent content)
            {
                return content.ReadAsByteArrayAsync();
            }

            internal Task<Stream> <GetStreamAsync>b__30_0(HttpContent content)
            {
                return content.ReadAsStreamAsync();
            }
        }

        private static readonly TimeSpan defaultTimeout = TimeSpan.FromSeconds(100.0);

        private static readonly TimeSpan maxTimeout = TimeSpan.FromMilliseconds(2147483647.0);

        private static readonly TimeSpan infiniteTimeout = TimeSpan.FromMilliseconds(-1.0);

        private const HttpCompletionOption defaultCompletionOption = HttpCompletionOption.ResponseContentRead;

        private volatile bool operationStarted;

        private volatile bool disposed;

        private CancellationTokenSource pendingRequestsCts;

        private HttpRequestHeaders defaultRequestHeaders;

        private Uri baseAddress;

        private TimeSpan timeout;

        private long maxResponseContentBufferSize;

        [__DynamicallyInvokable]
        public HttpRequestHeaders DefaultRequestHeaders
        {
            [__DynamicallyInvokable]
            get
            {
                if (this.defaultRequestHeaders == null)
                {
                    this.defaultRequestHeaders = new HttpRequestHeaders();
                }
                return this.defaultRequestHeaders;
            }
        }

        [__DynamicallyInvokable]
        public Uri BaseAddress
        {
            [__DynamicallyInvokable]
            get
            {
                return this.baseAddress;
            }
            [__DynamicallyInvokable]
            set
            {
                HttpClient.CheckBaseAddress(value, "value");
                this.CheckDisposedOrStarted();
                if (Logging.On)
                {
                    Logging.PrintInfo(Logging.Http, this, "BaseAddress: '" + this.baseAddress + "'");
                }
                this.baseAddress = value;
            }
        }

        [__DynamicallyInvokable]
        public TimeSpan Timeout
        {
            [__DynamicallyInvokable]
            get
            {
                return this.timeout;
            }
            [__DynamicallyInvokable]
            set
            {
                if (value != HttpClient.infiniteTimeout && (value <= TimeSpan.Zero || value > HttpClient.maxTimeout))
                {
                    throw new ArgumentOutOfRangeException("value");
                }
                this.CheckDisposedOrStarted();
                this.timeout = value;
            }
        }

        [__DynamicallyInvokable]
        public long MaxResponseContentBufferSize
        {
            [__DynamicallyInvokable]
            get
            {
                return this.maxResponseContentBufferSize;
            }
            [__DynamicallyInvokable]
            set
            {
                if (value <= 0L)
                {
                    throw new ArgumentOutOfRangeException("value");
                }
                if (value > 2147483647L)
                {
                    throw new ArgumentOutOfRangeException("value", value, string.Format(CultureInfo.InvariantCulture, SR.net_http_content_buffersize_limit, new object[]
                    {
                        2147483647L
                    }));
                }
                this.CheckDisposedOrStarted();
                this.maxResponseContentBufferSize = value;
            }
        }

        [__DynamicallyInvokable]
        public HttpClient() : this(new HttpClientHandler())
        {
        }

        [__DynamicallyInvokable]
        public HttpClient(HttpMessageHandler handler) : this(handler, true)
        {
        }

        [__DynamicallyInvokable]
        public HttpClient(HttpMessageHandler handler, bool disposeHandler) : base(handler, disposeHandler)
        {
            if (Logging.On)
            {
                Logging.Enter(Logging.Http, this, ".ctor", handler);
            }
            this.timeout = HttpClient.defaultTimeout;
            this.maxResponseContentBufferSize = 2147483647L;
            this.pendingRequestsCts = new CancellationTokenSource();
            if (Logging.On)
            {
                Logging.Exit(Logging.Http, this, ".ctor", null);
            }
        }

        [__DynamicallyInvokable]
        public Task<string> GetStringAsync(string requestUri)
        {
            return this.GetStringAsync(this.CreateUri(requestUri));
        }

        [__DynamicallyInvokable]
        public Task<string> GetStringAsync(Uri requestUri)
        {
            HttpCompletionOption arg_27_2 = HttpCompletionOption.ResponseContentRead;
            string arg_27_3 = string.Empty;
            Func<HttpContent, Task<string>> arg_27_4;
            if ((arg_27_4 = HttpClient.<>c.<>9__26_0) == null)
            {
                arg_27_4 = (HttpClient.<>c.<>9__26_0 = new Func<HttpContent, Task<string>>(HttpClient.<>c.<>9.<GetStringAsync>b__26_0));
            }
            return this.GetContentAsync<string>(requestUri, arg_27_2, arg_27_3, arg_27_4);
        }

        [__DynamicallyInvokable]
        public Task<byte[]> GetByteArrayAsync(string requestUri)
        {
            return this.GetByteArrayAsync(this.CreateUri(requestUri));
        }

        [__DynamicallyInvokable]
        public Task<byte[]> GetByteArrayAsync(Uri requestUri)
        {
            HttpCompletionOption arg_27_2 = HttpCompletionOption.ResponseContentRead;
            byte[] arg_27_3 = HttpUtilities.EmptyByteArray;
            Func<HttpContent, Task<byte[]>> arg_27_4;
            if ((arg_27_4 = HttpClient.<>c.<>9__28_0) == null)
            {
                arg_27_4 = (HttpClient.<>c.<>9__28_0 = new Func<HttpContent, Task<byte[]>>(HttpClient.<>c.<>9.<GetByteArrayAsync>b__28_0));
            }
            return this.GetContentAsync<byte[]>(requestUri, arg_27_2, arg_27_3, arg_27_4);
        }

        [__DynamicallyInvokable]
        public Task<Stream> GetStreamAsync(string requestUri)
        {
            return this.GetStreamAsync(this.CreateUri(requestUri));
        }

        [__DynamicallyInvokable]
        public Task<Stream> GetStreamAsync(Uri requestUri)
        {
            HttpCompletionOption arg_27_2 = HttpCompletionOption.ResponseHeadersRead;
            Stream arg_27_3 = Stream.Null;
            Func<HttpContent, Task<Stream>> arg_27_4;
            if ((arg_27_4 = HttpClient.<>c.<>9__30_0) == null)
            {
                arg_27_4 = (HttpClient.<>c.<>9__30_0 = new Func<HttpContent, Task<Stream>>(HttpClient.<>c.<>9.<GetStreamAsync>b__30_0));
            }
            return this.GetContentAsync<Stream>(requestUri, arg_27_2, arg_27_3, arg_27_4);
        }

        private Task<T> GetContentAsync<T>(Uri requestUri, HttpCompletionOption completionOption, T defaultValue, Func<HttpContent, Task<T>> readAs)
        {
            TaskCompletionSource<T> tcs = new TaskCompletionSource<T>();
            Action<Task<T>> <>9__1;
            this.GetAsync(requestUri, completionOption).ContinueWithStandard(delegate(Task<HttpResponseMessage> requestTask)
            {
                if (HttpClient.HandleRequestFaultsAndCancelation<T>(requestTask, tcs))
                {
                    return;
                }
                HttpResponseMessage result = requestTask.Result;
                if (result.Content == null)
                {
                    tcs.TrySetResult(defaultValue);
                    return;
                }
                try
                {
                    Task<T> arg_62_0 = readAs(result.Content);
                    Action<Task<T>> arg_62_1;
                    if ((arg_62_1 = <>9__1) == null)
                    {
                        arg_62_1 = (<>9__1 = delegate(Task<T> contentTask)
                        {
                            if (!HttpUtilities.HandleFaultsAndCancelation<T>(contentTask, tcs))
                            {
                                tcs.TrySetResult(contentTask.Result);
                            }
                        });
                    }
                    arg_62_0.ContinueWithStandard(arg_62_1);
                }
                catch (Exception exception)
                {
                    tcs.TrySetException(exception);
                }
            });
            return tcs.Task;
        }

        [__DynamicallyInvokable]
        public Task<HttpResponseMessage> GetAsync(string requestUri)
        {
            return this.GetAsync(this.CreateUri(requestUri));
        }

        [__DynamicallyInvokable]
        public Task<HttpResponseMessage> GetAsync(Uri requestUri)
        {
            return this.GetAsync(requestUri, HttpCompletionOption.ResponseContentRead);
        }

        [__DynamicallyInvokable]
        public Task<HttpResponseMessage> GetAsync(string requestUri, HttpCompletionOption completionOption)
        {
            return this.GetAsync(this.CreateUri(requestUri), completionOption);
        }

        [__DynamicallyInvokable]
        public Task<HttpResponseMessage> GetAsync(Uri requestUri, HttpCompletionOption completionOption)
        {
            return this.GetAsync(requestUri, completionOption, CancellationToken.None);
        }

        [__DynamicallyInvokable]
        public Task<HttpResponseMessage> GetAsync(string requestUri, CancellationToken cancellationToken)
        {
            return this.GetAsync(this.CreateUri(requestUri), cancellationToken);
        }

        [__DynamicallyInvokable]
        public Task<HttpResponseMessage> GetAsync(Uri requestUri, CancellationToken cancellationToken)
        {
            return this.GetAsync(requestUri, HttpCompletionOption.ResponseContentRead, cancellationToken);
        }

        [__DynamicallyInvokable]
        public Task<HttpResponseMessage> GetAsync(string requestUri, HttpCompletionOption completionOption, CancellationToken cancellationToken)
        {
            return this.GetAsync(this.CreateUri(requestUri), completionOption, cancellationToken);
        }

        [__DynamicallyInvokable]
        public Task<HttpResponseMessage> GetAsync(Uri requestUri, HttpCompletionOption completionOption, CancellationToken cancellationToken)
        {
            return this.SendAsync(new HttpRequestMessage(HttpMethod.Get, requestUri), completionOption, cancellationToken);
        }

        [__DynamicallyInvokable]
        public Task<HttpResponseMessage> PostAsync(string requestUri, HttpContent content)
        {
            return this.PostAsync(this.CreateUri(requestUri), content);
        }

        [__DynamicallyInvokable]
        public Task<HttpResponseMessage> PostAsync(Uri requestUri, HttpContent content)
        {
            return this.PostAsync(requestUri, content, CancellationToken.None);
        }

        [__DynamicallyInvokable]
        public Task<HttpResponseMessage> PostAsync(string requestUri, HttpContent content, CancellationToken cancellationToken)
        {
            return this.PostAsync(this.CreateUri(requestUri), content, cancellationToken);
        }

        [__DynamicallyInvokable]
        public Task<HttpResponseMessage> PostAsync(Uri requestUri, HttpContent content, CancellationToken cancellationToken)
        {
            return this.SendAsync(new HttpRequestMessage(HttpMethod.Post, requestUri)
            {
                Content = content
            }, cancellationToken);
        }

        [__DynamicallyInvokable]
        public Task<HttpResponseMessage> PutAsync(string requestUri, HttpContent content)
        {
            return this.PutAsync(this.CreateUri(requestUri), content);
        }

        [__DynamicallyInvokable]
        public Task<HttpResponseMessage> PutAsync(Uri requestUri, HttpContent content)
        {
            return this.PutAsync(requestUri, content, CancellationToken.None);
        }

        [__DynamicallyInvokable]
        public Task<HttpResponseMessage> PutAsync(string requestUri, HttpContent content, CancellationToken cancellationToken)
        {
            return this.PutAsync(this.CreateUri(requestUri), content, cancellationToken);
        }

        [__DynamicallyInvokable]
        public Task<HttpResponseMessage> PutAsync(Uri requestUri, HttpContent content, CancellationToken cancellationToken)
        {
            return this.SendAsync(new HttpRequestMessage(HttpMethod.Put, requestUri)
            {
                Content = content
            }, cancellationToken);
        }

        [__DynamicallyInvokable]
        public Task<HttpResponseMessage> DeleteAsync(string requestUri)
        {
            return this.DeleteAsync(this.CreateUri(requestUri));
        }

        [__DynamicallyInvokable]
        public Task<HttpResponseMessage> DeleteAsync(Uri requestUri)
        {
            return this.DeleteAsync(requestUri, CancellationToken.None);
        }

        [__DynamicallyInvokable]
        public Task<HttpResponseMessage> DeleteAsync(string requestUri, CancellationToken cancellationToken)
        {
            return this.DeleteAsync(this.CreateUri(requestUri), cancellationToken);
        }

        [__DynamicallyInvokable]
        public Task<HttpResponseMessage> DeleteAsync(Uri requestUri, CancellationToken cancellationToken)
        {
            return this.SendAsync(new HttpRequestMessage(HttpMethod.Delete, requestUri), cancellationToken);
        }

        [__DynamicallyInvokable]
        public Task<HttpResponseMessage> SendAsync(HttpRequestMessage request)
        {
            return this.SendAsync(request, HttpCompletionOption.ResponseContentRead, CancellationToken.None);
        }

        [__DynamicallyInvokable]
        public override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
        {
            return this.SendAsync(request, HttpCompletionOption.ResponseContentRead, cancellationToken);
        }

        [__DynamicallyInvokable]
        public Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, HttpCompletionOption completionOption)
        {
            return this.SendAsync(request, completionOption, CancellationToken.None);
        }

        [__DynamicallyInvokable]
        public Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, HttpCompletionOption completionOption, CancellationToken cancellationToken)
        {
            if (request == null)
            {
                throw new ArgumentNullException("request");
            }
            this.CheckDisposed();
            HttpClient.CheckRequestMessage(request);
            this.SetOperationStarted();
            this.PrepareRequestMessage(request);
            CancellationTokenSource linkedCts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, this.pendingRequestsCts.Token);
            this.SetTimeout(linkedCts);
            TaskCompletionSource<HttpResponseMessage> tcs = new TaskCompletionSource<HttpResponseMessage>();
            base.SendAsync(request, linkedCts.Token).ContinueWithStandard(delegate(Task<HttpResponseMessage> task)
            {
                try
                {
                    this.DisposeRequestContent(request);
                    if (task.IsFaulted)
                    {
                        this.SetTaskFaulted(request, linkedCts, tcs, task.Exception.GetBaseException());
                    }
                    else if (task.IsCanceled)
                    {
                        this.SetTaskCanceled(request, linkedCts, tcs);
                    }
                    else
                    {
                        HttpResponseMessage result = task.Result;
                        if (result == null)
                        {
                            this.SetTaskFaulted(request, linkedCts, tcs, new InvalidOperationException(SR.net_http_handler_noresponse));
                        }
                        else if (result.Content == null || completionOption == HttpCompletionOption.ResponseHeadersRead)
                        {
                            this.SetTaskCompleted(request, linkedCts, tcs, result);
                        }
                        else
                        {
                            this.StartContentBuffering(request, linkedCts, tcs, result);
                        }
                    }
                }
                catch (Exception ex)
                {
                    if (Logging.On)
                    {
                        Logging.Exception(Logging.Http, this, "SendAsync", ex);
                    }
                    tcs.TrySetException(ex);
                }
            });
            return tcs.Task;
        }

        [__DynamicallyInvokable]
        public void CancelPendingRequests()
        {
            this.CheckDisposed();
            if (Logging.On)
            {
                Logging.Enter(Logging.Http, this, "CancelPendingRequests", "");
            }
            CancellationTokenSource cancellationTokenSource = Interlocked.Exchange<CancellationTokenSource>(ref this.pendingRequestsCts, new CancellationTokenSource());
            cancellationTokenSource.Cancel();
            cancellationTokenSource.Dispose();
            if (Logging.On)
            {
                Logging.Exit(Logging.Http, this, "CancelPendingRequests", "");
            }
        }

        [__DynamicallyInvokable]
        protected override void Dispose(bool disposing)
        {
            if (disposing && !this.disposed)
            {
                this.disposed = true;
                this.pendingRequestsCts.Cancel();
                this.pendingRequestsCts.Dispose();
            }
            base.Dispose(disposing);
        }

        private void DisposeRequestContent(HttpRequestMessage request)
        {
            HttpContent content = request.Content;
            if (content != null)
            {
                content.Dispose();
            }
        }

        private void StartContentBuffering(HttpRequestMessage request, CancellationTokenSource cancellationTokenSource, TaskCompletionSource<HttpResponseMessage> tcs, HttpResponseMessage response)
        {
            response.Content.LoadIntoBufferAsync(this.maxResponseContentBufferSize).ContinueWithStandard(delegate(Task contentTask)
            {
                try
                {
                    bool isCancellationRequested = cancellationTokenSource.Token.IsCancellationRequested;
                    if (contentTask.IsFaulted)
                    {
                        response.Dispose();
                        if (isCancellationRequested && contentTask.Exception.GetBaseException() is HttpRequestException)
                        {
                            this.SetTaskCanceled(request, cancellationTokenSource, tcs);
                        }
                        else
                        {
                            this.SetTaskFaulted(request, cancellationTokenSource, tcs, contentTask.Exception.GetBaseException());
                        }
                    }
                    else if (contentTask.IsCanceled)
                    {
                        response.Dispose();
                        this.SetTaskCanceled(request, cancellationTokenSource, tcs);
                    }
                    else
                    {
                        this.SetTaskCompleted(request, cancellationTokenSource, tcs, response);
                    }
                }
                catch (Exception ex)
                {
                    response.Dispose();
                    tcs.TrySetException(ex);
                    if (Logging.On)
                    {
                        Logging.Exception(Logging.Http, this, "SendAsync", ex);
                    }
                }
            });
        }

        private void SetOperationStarted()
        {
            if (!this.operationStarted)
            {
                this.operationStarted = true;
            }
        }

        private void CheckDisposedOrStarted()
        {
            this.CheckDisposed();
            if (this.operationStarted)
            {
                throw new InvalidOperationException(SR.net_http_operation_started);
            }
        }

        private void CheckDisposed()
        {
            if (this.disposed)
            {
                throw new ObjectDisposedException(base.GetType().FullName);
            }
        }

        private static void CheckRequestMessage(HttpRequestMessage request)
        {
            if (!request.MarkAsSent())
            {
                throw new InvalidOperationException(SR.net_http_client_request_already_sent);
            }
        }

        private void PrepareRequestMessage(HttpRequestMessage request)
        {
            Uri uri = null;
            if (request.RequestUri == null && this.baseAddress == null)
            {
                throw new InvalidOperationException(SR.net_http_client_invalid_requesturi);
            }
            if (request.RequestUri == null)
            {
                uri = this.baseAddress;
            }
            else if (!request.RequestUri.IsAbsoluteUri)
            {
                if (this.baseAddress == null)
                {
                    throw new InvalidOperationException(SR.net_http_client_invalid_requesturi);
                }
                uri = new Uri(this.baseAddress, request.RequestUri);
            }
            if (uri != null)
            {
                request.RequestUri = uri;
            }
            if (this.defaultRequestHeaders != null)
            {
                request.Headers.AddHeaders(this.defaultRequestHeaders);
            }
        }

        private static void CheckBaseAddress(Uri baseAddress, string parameterName)
        {
            if (baseAddress == null)
            {
                return;
            }
            if (!baseAddress.IsAbsoluteUri)
            {
                throw new ArgumentException(SR.net_http_client_absolute_baseaddress_required, parameterName);
            }
            if (!HttpUtilities.IsHttpUri(baseAddress))
            {
                throw new ArgumentException(SR.net_http_client_http_baseaddress_required, parameterName);
            }
        }

        private void SetTaskFaulted(HttpRequestMessage request, CancellationTokenSource cancellationTokenSource, TaskCompletionSource<HttpResponseMessage> tcs, Exception e)
        {
            this.LogSendError(request, cancellationTokenSource, "SendAsync", e);
            tcs.TrySetException(e);
            cancellationTokenSource.Dispose();
        }

        private void SetTaskCanceled(HttpRequestMessage request, CancellationTokenSource cancellationTokenSource, TaskCompletionSource<HttpResponseMessage> tcs)
        {
            this.LogSendError(request, cancellationTokenSource, "SendAsync", null);
            tcs.TrySetCanceled();
            cancellationTokenSource.Dispose();
        }

        private void SetTaskCompleted(HttpRequestMessage request, CancellationTokenSource cancellationTokenSource, TaskCompletionSource<HttpResponseMessage> tcs, HttpResponseMessage response)
        {
            if (Logging.On)
            {
                Logging.PrintInfo(Logging.Http, this, string.Format(CultureInfo.InvariantCulture, SR.net_http_client_send_completed, new object[]
                {
                    Logging.GetObjectLogHash(request),
                    Logging.GetObjectLogHash(response),
                    response
                }));
            }
            tcs.TrySetResult(response);
            cancellationTokenSource.Dispose();
        }

        private void SetTimeout(CancellationTokenSource cancellationTokenSource)
        {
            if (this.timeout != HttpClient.infiniteTimeout)
            {
                cancellationTokenSource.CancelAfter(this.timeout);
            }
        }

        private void LogSendError(HttpRequestMessage request, CancellationTokenSource cancellationTokenSource, string method, Exception e)
        {
            if (cancellationTokenSource.IsCancellationRequested)
            {
                if (Logging.On)
                {
                    Logging.PrintError(Logging.Http, this, method, string.Format(CultureInfo.InvariantCulture, SR.net_http_client_send_canceled, new object[]
                    {
                        Logging.GetObjectLogHash(request)
                    }));
                    return;
                }
            }
            else if (Logging.On)
            {
                Logging.PrintError(Logging.Http, this, method, string.Format(CultureInfo.InvariantCulture, SR.net_http_client_send_error, new object[]
                {
                    Logging.GetObjectLogHash(request),
                    e
                }));
            }
        }

        private Uri CreateUri(string uri)
        {
            if (string.IsNullOrEmpty(uri))
            {
                return null;
            }
            return new Uri(uri, UriKind.RelativeOrAbsolute);
        }

        private static bool HandleRequestFaultsAndCancelation<T>(Task<HttpResponseMessage> task, TaskCompletionSource<T> tcs)
        {
            if (HttpUtilities.HandleFaultsAndCancelation<T>(task, tcs))
            {
                return true;
            }
            HttpResponseMessage result = task.Result;
            if (!result.IsSuccessStatusCode)
            {
                if (result.Content != null)
                {
                    result.Content.Dispose();
                }
                tcs.TrySetException(new HttpRequestException(string.Format(CultureInfo.InvariantCulture, SR.net_http_message_not_success_statuscode, new object[]
                {
                    (int)result.StatusCode,
                    result.ReasonPhrase
                })));
                return true;
            }
            return false;
        }
    }
}

眼尖的同学估计看出来了,这不是真正的源码啊!!!当然这个代码反编译工具是给搞出来的源码这哦。这里重点推荐下ILSpy工具。建议大家都来安装下。

看分🐴析

  • HttpClient继承自HttpMessageInvoker
  • HttpMessageInvoker具有一个SendAsync方法,其实就是这个方法用户向目标服务器发送HttpRequsetMessage对象承载的HTTP请求接,并通过HttpResponseMessage对象来接收服务器返回数据。。(关于这点我们来看截图,有图有真相!)
HttpClient调用SendAsync
  • 注意看HttpClient这个的空参构造函数,后面会讲到哦。
    HttpClient空参构造函数

HttpMessageInvoker

“撸”一段源码

using System;
using System.Threading;
using System.Threading.Tasks;

namespace System.Net.Http
{
    [__DynamicallyInvokable]
    public class HttpMessageInvoker : IDisposable
    {
        private volatile bool disposed;

        private bool disposeHandler;

        private HttpMessageHandler handler;

        [__DynamicallyInvokable]
        public HttpMessageInvoker(HttpMessageHandler handler) : this(handler, true)
        {
        }

        [__DynamicallyInvokable]
        public HttpMessageInvoker(HttpMessageHandler handler, bool disposeHandler)
        {
            if (Logging.On)
            {
                Logging.Enter(Logging.Http, this, ".ctor", handler);
            }
            if (handler == null)
            {
                throw new ArgumentNullException("handler");
            }
            if (Logging.On)
            {
                Logging.Associate(Logging.Http, this, handler);
            }
            this.handler = handler;
            this.disposeHandler = disposeHandler;
            if (Logging.On)
            {
                Logging.Exit(Logging.Http, this, ".ctor", null);
            }
        }

        [__DynamicallyInvokable]
        public virtual Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
        {
            if (request == null)
            {
                throw new ArgumentNullException("request");
            }
            this.CheckDisposed();
            if (Logging.On)
            {
                Logging.Enter(Logging.Http, this, "SendAsync", Logging.GetObjectLogHash(request) + ": " + request);
            }
            Task<HttpResponseMessage> task = this.handler.SendAsync(request, cancellationToken);
            if (Logging.On)
            {
                Logging.Exit(Logging.Http, this, "SendAsync", task);
            }
            return task;
        }

        [__DynamicallyInvokable]
        public void Dispose()
        {
            this.Dispose(true);
            GC.SuppressFinalize(this);
        }

        [__DynamicallyInvokable]
        protected virtual void Dispose(bool disposing)
        {
            if (disposing && !this.disposed)
            {
                this.disposed = true;
                if (this.disposeHandler)
                {
                    this.handler.Dispose();
                }
            }
        }

        private void CheckDisposed()
        {
            if (this.disposed)
            {
                throw new ObjectDisposedException(base.GetType().FullName);
            }
        }
    }
}

看分🐴析

  • 从构造函数中不难看出,HttpMessageInvoker是对一个HttpMessageHandler对象封装。实际在SendAsync方法中,“发送请求、接收响应”的任务最终都是通过调用HttpMessageHandler中的同名SendAsync方法来实现。(关于这点我们来看截图,有图有真相!)
HttpMessageInvoker调用SendAsync

看了这个图是不是已经明白了,这里的this就是构造函数中初始化的HttpMessageHandler对象啊。

HttpMessageInvoker利用HttpMessageHandler完成请求发送和响应接收原理图
请求发送和响应接收原理图
  • HttpMessageInvoker类型实现了IDisposable接口,它通过实现的Dispose方法来释放被封装的HttpMessageHandler对象。但是当一个HttpMessageInvoker被释放的时候,并不一定要求释放被其封装的HttpMessageHandler对象,是否需要对其实施释放操作取决于构建HTTP MessageInvoker时传入的disposeHandler参数。
参考文献
  • 《ASP.NET WebAPI 2 框架揭秘》
  • MSDN
  • 博客园
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,491评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,856评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,745评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,196评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,073评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,112评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,531评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,215评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,485评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,578评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,356评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,215评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,583评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,898评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,174评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,497评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,697评论 2 335

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,054评论 25 707
  • 1. Java基础部分 基础部分的顺序:基本语法,类相关的语法,内部类的语法,继承相关的语法,异常的语法,线程的语...
    子非鱼_t_阅读 31,497评论 18 399
  • 第一章 Nginx简介 Nginx是什么 没有听过Nginx?那么一定听过它的“同行”Apache吧!Ngi...
    JokerW阅读 32,605评论 24 1,002
  • 廿四月度弹指间 倥偬岁月白发添 唯叹韶华未倾负 半失半得半心酸
    家有嘉翼阅读 138评论 0 0
  • 上班的路上在我前面走着一个大婶 红色上衣 绿色裤子 她每往前迈一步头就往左一下,反反复复 我在后面看的有趣,目不转...
    一只自力更生的小猫咪阅读 188评论 0 0