揭開(kāi)HttpClient的“蓋頭”來(lái)(一)

之前的文章我已經(jīng)大概介紹了httpclient的使用方法晴叨。那么作為想進(jìn)步(zhuang bi)仰泻、追求真理(you jie cao)的一個(gè)碼農(nóng)瓶埋,我們更想知道這個(gè)東東內(nèi)部到底是怎么實(shí)現(xiàn)的呢捞挥?于是就有了該系列文章浮创。
說(shuō)明:由于源碼分析本來(lái)就是枯燥乏味,有時(shí)候會(huì)很難懂砌函。所以
作者將它按照系列分開(kāi)來(lái)寫斩披。作者水平有限,寫作過(guò)程中可能會(huì)錯(cuò)誤或者不足讹俊,還請(qǐng)大家及時(shí)評(píng)論或者建議垦沉。我會(huì)針對(duì)您的反饋積極做出修改。在這里提前謝謝大家H耘2薇丁!

目錄

HttpClient

話不多說(shuō)先來(lái)一段源碼贩疙。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;
        }
    }
}

眼尖的同學(xué)估計(jì)看出來(lái)了,這不是真正的源碼罢饨ΑU⒂ぁ!芍躏!當(dāng)然這個(gè)代碼反編譯工具是給搞出來(lái)的源碼這哦。這里重點(diǎn)推薦下ILSpy工具降狠。建議大家都來(lái)安裝下对竣。

看分??析

  • HttpClient繼承自HttpMessageInvoker
  • HttpMessageInvoker具有一個(gè)SendAsync方法庇楞,其實(shí)就是這個(gè)方法用戶向目標(biāo)服務(wù)器發(fā)送HttpRequsetMessage對(duì)象承載的HTTP請(qǐng)求接,并通過(guò)HttpResponseMessage對(duì)象來(lái)接收服務(wù)器返回?cái)?shù)據(jù)否纬。吕晌。(關(guān)于這點(diǎn)我們來(lái)看截圖,有圖有真相A偃肌)
HttpClient調(diào)用SendAsync
  • 注意看HttpClient這個(gè)的空參構(gòu)造函數(shù)睛驳,后面會(huì)講到哦。
    HttpClient空參構(gòu)造函數(shù)

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

看分??析

  • 從構(gòu)造函數(shù)中不難看出膜廊,HttpMessageInvoker是對(duì)一個(gè)HttpMessageHandler對(duì)象封裝乏沸。實(shí)際在SendAsync方法中,“發(fā)送請(qǐng)求爪瓜、接收響應(yīng)”的任務(wù)最終都是通過(guò)調(diào)用HttpMessageHandler中的同名SendAsync方法來(lái)實(shí)現(xiàn)蹬跃。(關(guān)于這點(diǎn)我們來(lái)看截圖,有圖有真相C)
HttpMessageInvoker調(diào)用SendAsync

看了這個(gè)圖是不是已經(jīng)明白了,這里的this就是構(gòu)造函數(shù)中初始化的HttpMessageHandler對(duì)象啊蝶缀。

HttpMessageInvoker利用HttpMessageHandler完成請(qǐng)求發(fā)送和響應(yīng)接收原理圖
請(qǐng)求發(fā)送和響應(yīng)接收原理圖
  • HttpMessageInvoker類型實(shí)現(xiàn)了IDisposable接口,它通過(guò)實(shí)現(xiàn)的Dispose方法來(lái)釋放被封裝的HttpMessageHandler對(duì)象薄货。但是當(dāng)一個(gè)HttpMessageInvoker被釋放的時(shí)候翁都,并不一定要求釋放被其封裝的HttpMessageHandler對(duì)象,是否需要對(duì)其實(shí)施釋放操作取決于構(gòu)建HTTP MessageInvoker時(shí)傳入的disposeHandler參數(shù)谅猾。
參考文獻(xiàn)
  • 《ASP.NET WebAPI 2 框架揭秘》
  • MSDN
  • 博客園
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末柄慰,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子赊瞬,更是在濱河造成了極大的恐慌先煎,老刑警劉巖,帶你破解...
    沈念sama閱讀 207,248評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件巧涧,死亡現(xiàn)場(chǎng)離奇詭異薯蝎,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)谤绳,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,681評(píng)論 2 381
  • 文/潘曉璐 我一進(jìn)店門占锯,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人缩筛,你說(shuō)我怎么就攤上這事消略。” “怎么了瞎抛?”我有些...
    開(kāi)封第一講書人閱讀 153,443評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵艺演,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我,道長(zhǎng)胎撤,這世上最難降的妖魔是什么晓殊? 我笑而不...
    開(kāi)封第一講書人閱讀 55,475評(píng)論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮伤提,結(jié)果婚禮上巫俺,老公的妹妹穿的比我還像新娘。我一直安慰自己肿男,他們只是感情好介汹,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,458評(píng)論 5 374
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著舶沛,像睡著了一般嘹承。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上冠王,一...
    開(kāi)封第一講書人閱讀 49,185評(píng)論 1 284
  • 那天赶撰,我揣著相機(jī)與錄音,去河邊找鬼柱彻。 笑死豪娜,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的哟楷。 我是一名探鬼主播瘤载,決...
    沈念sama閱讀 38,451評(píng)論 3 401
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼卖擅!你這毒婦竟也來(lái)了鸣奔?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書人閱讀 37,112評(píng)論 0 261
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤惩阶,失蹤者是張志新(化名)和其女友劉穎挎狸,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體断楷,經(jīng)...
    沈念sama閱讀 43,609評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡锨匆,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,083評(píng)論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了冬筒。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片恐锣。...
    茶點(diǎn)故事閱讀 38,163評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖舞痰,靈堂內(nèi)的尸體忽然破棺而出土榴,到底是詐尸還是另有隱情,我是刑警寧澤响牛,帶...
    沈念sama閱讀 33,803評(píng)論 4 323
  • 正文 年R本政府宣布玷禽,位于F島的核電站赫段,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏矢赁。R本人自食惡果不足惜瑞佩,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,357評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望坯台。 院中可真熱鬧,春花似錦瘫寝、人聲如沸蜒蕾。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 30,357評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)咪啡。三九已至,卻和暖如春暮屡,著一層夾襖步出監(jiān)牢的瞬間撤摸,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 31,590評(píng)論 1 261
  • 我被黑心中介騙來(lái)泰國(guó)打工褒纲, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留准夷,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,636評(píng)論 2 355
  • 正文 我出身青樓莺掠,卻偏偏與公主長(zhǎng)得像衫嵌,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子彻秆,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,925評(píng)論 2 344

推薦閱讀更多精彩內(nèi)容

  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 171,528評(píng)論 25 707
  • 1. Java基礎(chǔ)部分 基礎(chǔ)部分的順序:基本語(yǔ)法楔绞,類相關(guān)的語(yǔ)法,內(nèi)部類的語(yǔ)法唇兑,繼承相關(guān)的語(yǔ)法酒朵,異常的語(yǔ)法,線程的語(yǔ)...
    子非魚_t_閱讀 31,587評(píng)論 18 399
  • 第一章 Nginx簡(jiǎn)介 Nginx是什么 沒(méi)有聽(tīng)過(guò)Nginx扎附?那么一定聽(tīng)過(guò)它的“同行”Apache吧蔫耽!Ngi...
    JokerW閱讀 32,642評(píng)論 24 1,002
  • 廿四月度彈指間 倥傯歲月白發(fā)添 唯嘆韶華未傾負(fù) 半失半得半心酸
    家有嘉翼閱讀 141評(píng)論 0 0
  • 上班的路上在我前面走著一個(gè)大嬸 紅色上衣 綠色褲子 她每往前邁一步頭就往左一下,反反復(fù)復(fù) 我在后面看的有趣帕棉,目不轉(zhuǎn)...
    一只自力更生的小貓咪閱讀 191評(píng)論 0 0