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

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

目录

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

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> <>9__26_0;

            public static Func> <>9__28_0;

            public static Func> <>9__30_0;

            internal Task b__26_0(HttpContent content)
            {
                return content.ReadAsStringAsync();
            }

            internal Task b__28_0(HttpContent content)
            {
                return content.ReadAsByteArrayAsync();
            }

            internal Task 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 GetStringAsync(string requestUri)
        {
            return this.GetStringAsync(this.CreateUri(requestUri));
        }

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

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

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

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

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

        private Task GetContentAsync(Uri requestUri, HttpCompletionOption completionOption, T defaultValue, Func> readAs)
        {
            TaskCompletionSource tcs = new TaskCompletionSource();
            Action> <>9__1;
            this.GetAsync(requestUri, completionOption).ContinueWithStandard(delegate(Task requestTask)
            {
                if (HttpClient.HandleRequestFaultsAndCancelation(requestTask, tcs))
                {
                    return;
                }
                HttpResponseMessage result = requestTask.Result;
                if (result.Content == null)
                {
                    tcs.TrySetResult(defaultValue);
                    return;
                }
                try
                {
                    Task arg_62_0 = readAs(result.Content);
                    Action> arg_62_1;
                    if ((arg_62_1 = <>9__1) == null)
                    {
                        arg_62_1 = (<>9__1 = delegate(Task contentTask)
                        {
                            if (!HttpUtilities.HandleFaultsAndCancelation(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 GetAsync(string requestUri)
        {
            return this.GetAsync(this.CreateUri(requestUri));
        }

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

        [__DynamicallyInvokable]
        public Task 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 tcs = new TaskCompletionSource();
            base.SendAsync(request, linkedCts.Token).ContinueWithStandard(delegate(Task 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(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 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 tcs, Exception e)
        {
            this.LogSendError(request, cancellationTokenSource, "SendAsync", e);
            tcs.TrySetException(e);
            cancellationTokenSource.Dispose();
        }

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

        private void SetTaskCompleted(HttpRequestMessage request, CancellationTokenSource cancellationTokenSource, TaskCompletionSource 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(Task task, TaskCompletionSource tcs)
        {
            if (HttpUtilities.HandleFaultsAndCancelation(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的“盖头”来(一)_第1张图片
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 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 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方法来实现。(关于这点我们来看截图,有图有真相!)
揭开HttpClient的“盖头”来(一)_第2张图片
HttpMessageInvoker调用SendAsync

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

HttpMessageInvoker利用HttpMessageHandler完成请求发送和响应接收原理图
揭开HttpClient的“盖头”来(一)_第3张图片
请求发送和响应接收原理图
  • HttpMessageInvoker类型实现了IDisposable接口,它通过实现的Dispose方法来释放被封装的HttpMessageHandler对象。但是当一个HttpMessageInvoker被释放的时候,并不一定要求释放被其封装的HttpMessageHandler对象,是否需要对其实施释放操作取决于构建HTTP MessageInvoker时传入的disposeHandler参数。
参考文献
  • 《ASP.NET WebAPI 2 框架揭秘》
  • MSDN
  • 博客园

你可能感兴趣的:(揭开HttpClient的“盖头”来(一))