Quyết định giữa HttpClient và WebClient


218

Ứng dụng web của chúng tôi đang chạy trong .Net Framework 4.0. UI gọi các phương thức điều khiển thông qua các cuộc gọi ajax.

Chúng tôi cần tiêu thụ dịch vụ REST từ nhà cung cấp của chúng tôi. Tôi đang đánh giá cách tốt nhất để gọi dịch vụ REST trong .Net 4.0. Dịch vụ REST yêu cầu Lược đồ xác thực cơ bản và nó có thể trả về dữ liệu trong cả XML và JSON. Không có yêu cầu tải lên / tải xuống dữ liệu lớn và tôi không thấy gì trong tương lai. Tôi đã xem xét một vài dự án mã nguồn mở cho việc tiêu thụ REST và không tìm thấy bất kỳ giá trị nào trong các dự án đó để biện minh cho sự phụ thuộc bổ sung trong dự án. Bắt đầu đánh giá WebClientHttpClient. Tôi đã tải xuống httpClient cho .Net 4.0 từ NuGet.

Tôi đã tìm kiếm sự khác biệt giữa WebClientHttpClienttrang web này đã đề cập rằng một httpClient có thể xử lý các cuộc gọi đồng thời và nó có thể sử dụng lại DNS, cấu hình cookie và xác thực đã giải quyết. Tôi vẫn chưa thấy các giá trị thực tế mà chúng ta có thể đạt được do sự khác biệt.

Tôi đã thực hiện một bài kiểm tra hiệu suất nhanh để tìm cách WebClient(đồng bộ hóa cuộc gọi), HttpClient(đồng bộ hóa và không đồng bộ) thực hiện. và đây là kết quả:

Sử dụng cùng một HttpClientví dụ cho tất cả các yêu cầu (tối thiểu - tối đa)

Đồng bộ hóa WebClient: 8 ms - 167 ms
Đồng bộ hóa httpClient: 3 ms - 7228 ms Đồng bộ hóa
httpClient: 985 - 10405 ms

Sử dụng một cái mới HttpClientcho mỗi yêu cầu (tối thiểu - tối đa)

Đồng bộ hóa WebClient: 4 ms - 297 ms
Đồng bộ hóa httpClient: 3 ms - 7953 ms Đồng bộ hóa httpClient
: 1027 - 10834 ms

public class AHNData
{
    public int i;
    public string str;
}

public class Program
{
    public static HttpClient httpClient = new HttpClient();
    private static readonly string _url = "http://localhost:9000/api/values/";

    public static void Main(string[] args)
    {
       #region "Trace"
       Trace.Listeners.Clear();

       TextWriterTraceListener twtl = new TextWriterTraceListener(
           "C:\\Temp\\REST_Test.txt");
       twtl.Name = "TextLogger";
       twtl.TraceOutputOptions = TraceOptions.ThreadId | TraceOptions.DateTime;

       ConsoleTraceListener ctl = new ConsoleTraceListener(false);
       ctl.TraceOutputOptions = TraceOptions.DateTime;

       Trace.Listeners.Add(twtl);
       Trace.Listeners.Add(ctl);
       Trace.AutoFlush = true;
       #endregion

       int batchSize = 1000;

       ParallelOptions parallelOptions = new ParallelOptions();
       parallelOptions.MaxDegreeOfParallelism = batchSize;

       ServicePointManager.DefaultConnectionLimit = 1000000;

       Parallel.For(0, batchSize, parallelOptions,
           j =>
           {
               Stopwatch sw1 = Stopwatch.StartNew();
               GetDataFromHttpClientAsync<List<AHNData>>(sw1);
           });
       Parallel.For(0, batchSize, parallelOptions,
            j =>
            {
                Stopwatch sw1 = Stopwatch.StartNew();
                GetDataFromHttpClientSync<List<AHNData>>(sw1);
            });
       Parallel.For(0, batchSize, parallelOptions,
            j =>
            {
                using (WebClient client = new WebClient())
                {
                   Stopwatch sw = Stopwatch.StartNew();
                   byte[] arr = client.DownloadData(_url);
                   sw.Stop();

                   Trace.WriteLine("WebClient Sync " + sw.ElapsedMilliseconds);
                }
           });

           Console.Read();
        }

        public static T GetDataFromWebClient<T>()
        {
            using (var webClient = new WebClient())
            {
                webClient.BaseAddress = _url;
                return JsonConvert.DeserializeObject<T>(
                    webClient.DownloadString(_url));
            }
        }

        public static void GetDataFromHttpClientSync<T>(Stopwatch sw)
        {
            HttpClient httpClient = new HttpClient();
            var response = httpClient.GetAsync(_url).Result;
            var obj = JsonConvert.DeserializeObject<T>(
                response.Content.ReadAsStringAsync().Result);
            sw.Stop();

            Trace.WriteLine("HttpClient Sync " + sw.ElapsedMilliseconds);
        }

        public static void GetDataFromHttpClientAsync<T>(Stopwatch sw)
        {
           HttpClient httpClient = new HttpClient();
           var response = httpClient.GetAsync(_url).ContinueWith(
              (a) => {
                 JsonConvert.DeserializeObject<T>(
                    a.Result.Content.ReadAsStringAsync().Result);
                 sw.Stop();
                 Trace.WriteLine("HttpClient Async " + sw.ElapsedMilliseconds);
              }, TaskContinuationOptions.None);
        }
    }
}

Những câu hỏi của tôi

  1. Các cuộc gọi REST trả về sau 3-4 giây là chấp nhận được. Các cuộc gọi đến dịch vụ REST được bắt đầu trong các phương thức điều khiển được gọi từ các cuộc gọi ajax. Để bắt đầu, các cuộc gọi chạy trong một luồng khác và không chặn UI. Vì vậy, tôi chỉ có thể gắn bó với các cuộc gọi đồng bộ?
  2. Đoạn mã trên đã được chạy trong localbox của tôi. Trong thiết lập prod, DNS và tra cứu proxy sẽ được tham gia. Có bất kỳ lợi thế của việc sử dụng HttpClienthơn WebClient?
  3. HttpClientđồng thời tốt hơn WebClient? Từ kết quả kiểm tra, tôi thấy WebClientcác cuộc gọi đồng bộ thực hiện tốt hơn.
  4. Sẽ HttpClientlà lựa chọn thiết kế tốt hơn nếu chúng tôi nâng cấp lên .Net 4.5? Hiệu suất là yếu tố thiết kế quan trọng.

5
Thử nghiệm của bạn không công bằng GetDataFromHttpClientAsyncvì nó chạy trước, các yêu cầu khác nhận được lợi ích của việc có khả năng có dữ liệu bị chặn (có thể trên máy cục bộ hoặc bất kỳ proxy minh bạch nào giữa bạn và đích) và sẽ nhanh hơn. Ngoài ra, trong các điều kiện phù hợp var response = httpClient.GetAsync("http://localhost:9000/api/values/").Result;có thể dẫn đến bế tắc do bạn làm cạn kiệt các luồng xử lý. Bạn không bao giờ nên chặn một hoạt động phụ thuộc vào nhóm luồng trong các luồng ThreadPool, awaitthay vào đó , bạn nên trả lại luồng vào lại nhóm.
Scott Chamberlain

1
HttpClient với Web API Client rất tuyệt vời cho máy khách JSON / XML REST.
Cory Nelson

@Scott Chamberlain - Cảm ơn bạn đã trả lời. Vì tất cả các cuộc gọi thử nghiệm đều chạy trong Parallel.Foreach, không có gì đảm bảo cuộc gọi nào sẽ chạy trước. Ngoài ra, có cuộc gọi đầu tiên đến dịch vụ là từ GetDataFromHttpClientAsync, tất cả các cuộc gọi tiếp theo từ GetDataFromHttpClientAsync sẽ được hưởng lợi từ bộ đệm và chạy nhanh hơn. Tôi đã không nhìn thấy điều đó trong kết quả. Rgd đang chờ, chúng tôi vẫn đang sử dụng 4.0. Tôi đồng ý với bạn rằng httpClient theo kiểu đồng bộ sẽ dẫn đến bế tắc và tôi loại bỏ tùy chọn đó ra khỏi sự cân nhắc thiết kế của tôi.
dùng3092913

@CoryNelson Bạn có thể giải thích rõ tại sao httpClient với Web API Client lại tuyệt vời cho máy khách JSON / XML REST không?
dùng3092913

2
Dưới đây là vài lời về sự khác biệt giữa HttpClient và WebClient: blogs.msdn.com/b/henrikn/archive/2012/02/11/...
JustAndrei

Câu trả lời:


243

Tôi sống trong cả thế giới API F # và Web.

Có rất nhiều thứ hay ho xảy ra với API Web, đặc biệt là ở dạng trình xử lý thông báo để bảo mật, v.v.

Tôi biết ý kiến ​​của tôi chỉ là một ý kiến, nhưng tôi chỉ khuyên bạn nên sử dụng HttpClientcho bất kỳ công việc nào trong tương lai . Có lẽ có một số cách để tận dụng một số phần khác ra khỏi System.Net.Httpmà không sử dụng trực tiếp lắp ráp đó, nhưng tôi không thể tưởng tượng được nó sẽ hoạt động như thế nào vào lúc này.

Nói về việc so sánh hai

  • HttpClient gần với HTTP hơn WebClient.
  • HttpClient không có nghĩa là một sự thay thế hoàn toàn của Máy khách Web, vì có những thứ như tiến trình báo cáo, lược đồ URI tùy chỉnh và thực hiện các cuộc gọi FTP mà WebClient cung cấp - nhưng HttpClient thì không.
+--------------------------------------------+--------------------------------------------+
|               WebClient                    |               HttpClient                   |
+--------------------------------------------+--------------------------------------------+
| Available in older versions of .NET        | .NET 4.5 only.  Created to support the     |
|                                            | growing need of the Web API REST calls     |
+--------------------------------------------+--------------------------------------------+
| WinRT applications cannot use WebClient    | HTTPClient can be used with WinRT          |
+--------------------------------------------+--------------------------------------------+
| Provides progress reporting for downloads  | No progress reporting for downloads        |
+--------------------------------------------+--------------------------------------------+
| Does not reuse resolved DNS,               | Can reuse resolved DNS, cookie             |
| configured cookies                         | configuration and other authentication     |
+--------------------------------------------+--------------------------------------------+
| You need to new up a WebClient to          | Single HttpClient can make concurrent      |
| make concurrent requests.                  | requests                                   |
+--------------------------------------------+--------------------------------------------+
| Thin layer over WebRequest and             | Thin layer of HttpWebRequest and           |
| WebResponse                                | HttpWebResponse                            |
+--------------------------------------------+--------------------------------------------+
| Mocking and testing WebClient is difficult | Mocking and testing HttpClient is easy     |
+--------------------------------------------+--------------------------------------------+
| Supports FTP                               | No support for FTP                         |
+--------------------------------------------+--------------------------------------------+
| Both Synchronous and Asynchronous methods  | All IO bound methods in                    |
| are available for IO bound requests        | HTTPClient are asynchronous                |
+--------------------------------------------+--------------------------------------------+

Nếu bạn đang sử dụng .NET 4.5, vui lòng sử dụng tính tốt không đồng bộ với HttpClient mà Microsoft cung cấp cho các nhà phát triển. HttpClient rất đối xứng với anh em phía máy chủ của HTTP là HTTPRequest và HttpResponse.

Cập nhật: 5 lý do nên sử dụng API HTTPClient mới:

  • Tiêu đề đánh máy mạnh mẽ.
  • Bộ nhớ cache, cookie và thông tin đăng nhập
  • Truy cập cookie và chia sẻ cookie
  • Kiểm soát bộ đệm và chia sẻ bộ đệm.
  • Tiêm mô-đun mã của bạn vào đường ống dẫn ASP.NET. Mã sạch hơn và mô-đun.

Tài liệu tham khảo

C # 5.0 Joseph Albahari

(Kênh9 - Xây dựng video 2013)

Năm lý do tuyệt vời để sử dụng API httpClient mới để kết nối với các dịch vụ web

WebClient vs HttpClient vs HttpWebRequest


4
Cần phải đề cập rằng httpClient cũng có sẵn cho .NET 4.0 .
Todd Menier

2
Điều này không giải thích được tại sao WebClient dường như có cường độ nhanh hơn so với HttpClient. Cũng WebClientdường như có các phương thức async bây giờ.
nghiền nát

8
@crush là vì OP đang tạo một phiên bản mới của httpClient cho mỗi yêu cầu. Thay vào đó, bạn nên sử dụng một ví dụ duy nhất của httpClient trong suốt vòng đời của ứng dụng. Xem stackoverflow.com/a/22561368/57369
Gabriel

6
Nó đáng chú ý WebClientlà không có sẵn trong .Net Corenhưng HttpClientlà.
Pranav Singh

3
Vì .Net Core 2.0 WebClient (trong số hàng ngàn API khác) đã hoạt động trở lại.
CoderBang

56

HttpClient là API mới hơn và nó có những lợi ích của

  • có một mô hình lập trình async tốt
  • được Henrik F Nielson làm việc về cơ bản là một trong những người phát minh ra HTTP và ông đã thiết kế API để bạn dễ dàng tuân theo tiêu chuẩn HTTP, ví dụ: tạo các tiêu đề tuân thủ tiêu chuẩn
  • nằm trong khung .Net 4.5, do đó, nó có một số mức hỗ trợ được đảm bảo cho tương lai có thể thấy được
  • cũng có phiên bản xcopyable / Portable-framework của thư viện nếu bạn muốn sử dụng nó trên các nền tảng khác - .Net 4.0, Windows Phone, v.v.

Nếu bạn đang viết một dịch vụ web đang thực hiện các cuộc gọi REST đến các dịch vụ web khác, bạn sẽ muốn sử dụng mô hình lập trình không đồng bộ cho tất cả các cuộc gọi REST của mình, để bạn không bị chết đói. Bạn cũng có thể muốn sử dụng trình biên dịch C # mới nhất có hỗ trợ async / await.

Lưu ý: Nó không hiệu quả hơn AFAIK. Nó có thể có hiệu suất tương tự nếu bạn tạo ra một thử nghiệm công bằng.


Nếu nó có cách chuyển proxy thì sẽ điên rồ
ed22

3

Thứ nhất, tôi không phải là người có thẩm quyền trên WebClient so với HttpClient. Thứ hai, từ các bình luận của bạn ở trên, dường như gợi ý rằng WebClient là CHỈ Đồng bộ hóa trong khi httpClient là cả hai.

Tôi đã thực hiện một bài kiểm tra hiệu năng nhanh để tìm cách WebClient (Cuộc gọi đồng bộ hóa), HttpClient (Đồng bộ hóa và Async) hoạt động. và đây là kết quả.

Tôi thấy đó là một sự khác biệt rất lớn khi nghĩ về tương lai, tức là các quy trình chạy dài, GUI đáp ứng, v.v. (thêm vào lợi ích mà bạn đề xuất theo khung 4.5 - mà theo kinh nghiệm thực tế của tôi là nhanh hơn trên IIS)


4
WebClientdường như không có khả năng async trong các phiên bản .NET mới nhất. Tôi muốn biết lý do tại sao nó dường như vượt trội so với HttpClient ở quy mô lớn như vậy.
nghiền nát

1
Theo stackoverflow.com/a/4988325/1662973 , nó dường như giống nhau, khác với thực tế là cái này là một sự trừu tượng của cái kia. Có lẽ, nó phụ thuộc vào cách các đối tượng được sử dụng / tải. Thời gian tối thiểu không hỗ trợ tuyên bố rằng webclient trên thực tế là một sự trừu tượng hóa của HTTPClient, do đó, có một phần trăm giá trị trên không. Khung này có thể là "lén lút" trong cách nó thực sự được tập hợp hoặc xử lý webclient.
Anthony Horne

2

Tôi có điểm chuẩn giữa HttpClient, WebClient, HttpWebResponse sau đó gọi Rest Web Api

và kết quả Call Rest Web Điểm chuẩn Api

--------------------- Giai đoạn 1 ---- 10 Yêu cầu

{00: 00: 17.2232544} ====> HttpClinet

{00: 00: 04.3108986} ====> WebRequest

{00: 00: 04.5436889} ====> WebClient

--------------------- Giai đoạn 1 ---- 10 Yêu cầu - Kích thước nhỏ

{00: 00: 17.2232544} ====> HttpClinet

{00: 00: 04.3108986} ====> WebRequest

{00: 00: 04.5436889} ====> WebClient

--------------------- Giai đoạn 3 ---- Yêu cầu đồng bộ 10 - Kích thước nhỏ

{00: 00: 15.3047502} ====> httpClinet

{00: 00: 03.5505249} ====> WebRequest

{00: 00: 04.0761359} ====> WebClient

--------------------- Giai đoạn 4 ---- Yêu cầu đồng bộ 100 - Kích thước nhỏ

{00: 03: 23.6268086} ====> HttpClinet

{00: 00: 47.1406632} ====> WebRequest

{00: 01: 01.2319499} ====> WebClient

--------------------- Giai đoạn 5 ---- Yêu cầu đồng bộ hóa 10 - Kích thước tối đa

{00: 00: 58.1804677} ====> HttpClinet

{00: 00: 58.0710444} ====> WebRequest

{00: 00: 38.4170938} ====> WebClient

--------------------- Giai đoạn 6 ---- Yêu cầu đồng bộ hóa 10 - Kích thước tối đa

{00: 01: 04.9964278} ====> HttpClinet

{00: 00: 59.1429764} ====> WebRequest

{00: 00: 32.0584836} ====> WebClient

_____ WebClient nhanh hơn ()

var stopWatch = new Stopwatch();
        stopWatch.Start();
        for (var i = 0; i < 10; ++i)
        {
            CallGetHttpClient();
            CallPostHttpClient();
        }

        stopWatch.Stop();

        var httpClientValue = stopWatch.Elapsed;

        stopWatch = new Stopwatch();

        stopWatch.Start();
        for (var i = 0; i < 10; ++i)
        {
            CallGetWebRequest();
            CallPostWebRequest();
        }

        stopWatch.Stop();

        var webRequesttValue = stopWatch.Elapsed;


        stopWatch = new Stopwatch();

        stopWatch.Start();
        for (var i = 0; i < 10; ++i)
        {

            CallGetWebClient();
            CallPostWebClient();

        }

        stopWatch.Stop();

        var webClientValue = stopWatch.Elapsed;

//-------------------------Chức năng

private void CallPostHttpClient()
    {
        var httpClient = new HttpClient();
        httpClient.BaseAddress = new Uri("https://localhost:44354/api/test/");
        var responseTask = httpClient.PostAsync("PostJson", null);
        responseTask.Wait();

        var result = responseTask.Result;
        var readTask = result.Content.ReadAsStringAsync().Result;

    }
    private void CallGetHttpClient()
    {
        var httpClient = new HttpClient();
        httpClient.BaseAddress = new Uri("https://localhost:44354/api/test/");
        var responseTask = httpClient.GetAsync("getjson");
        responseTask.Wait();

        var result = responseTask.Result;
        var readTask = result.Content.ReadAsStringAsync().Result;

    }
    private string CallGetWebRequest()
    {
        var request = (HttpWebRequest)WebRequest.Create("https://localhost:44354/api/test/getjson");

        request.Method = "GET";
        request.AutomaticDecompression = DecompressionMethods.Deflate | DecompressionMethods.GZip;

        var content = string.Empty;

        using (var response = (HttpWebResponse)request.GetResponse())
        {
            using (var stream = response.GetResponseStream())
            {
                using (var sr = new StreamReader(stream))
                {
                    content = sr.ReadToEnd();
                }
            }
        }

        return content;
    }
    private string CallPostWebRequest()
    {

        var apiUrl = "https://localhost:44354/api/test/PostJson";


        HttpWebRequest httpRequest = (HttpWebRequest)WebRequest.Create(new Uri(apiUrl));
        httpRequest.ContentType = "application/json";
        httpRequest.Method = "POST";
        httpRequest.ContentLength = 0;

        using (var httpResponse = (HttpWebResponse)httpRequest.GetResponse())
        {
            using (Stream stream = httpResponse.GetResponseStream())
            {
                var json = new StreamReader(stream).ReadToEnd();
                return json;
            }
        }

        return "";
    }

    private string CallGetWebClient()
    {
        string apiUrl = "https://localhost:44354/api/test/getjson";


        var client = new WebClient();

        client.Headers["Content-type"] = "application/json";

        client.Encoding = Encoding.UTF8;

        var json = client.DownloadString(apiUrl);


        return json;
    }

    private string CallPostWebClient()
    {
        string apiUrl = "https://localhost:44354/api/test/PostJson";


        var client = new WebClient();

        client.Headers["Content-type"] = "application/json";

        client.Encoding = Encoding.UTF8;

        var json = client.UploadString(apiUrl, "");


        return json;
    }

1
Xem bình luận của Gabriel ở trên. Nói tóm lại, HttpClient nhanh hơn nhiều nếu bạn tạo một thể hiện của HTTPClient và sử dụng lại nó.
LT Dan

2

HttpClientFactory

Điều quan trọng là phải đánh giá các cách khác nhau mà bạn có thể tạo ra một httpClient và một phần trong đó là hiểu về HTTPClientFactory.

https://docs.microsoft.com/en-us/dotnet/arch architecture / microsros /

Đây không phải là câu trả lời trực tiếp mà tôi biết - nhưng tốt hơn hết là bạn nên bắt đầu từ đây hơn là kết thúc với new HttpClient(...)mọi nơi.


1

Có lẽ bạn có thể nghĩ về vấn đề theo một cách khác. WebClientHttpClientvề cơ bản là các triển khai khác nhau của cùng một điều. Những gì tôi khuyên là nên triển khai mẫu Dependency Injection với IoC Container trong toàn bộ ứng dụng của bạn. Bạn nên xây dựng một giao diện máy khách với mức độ trừu tượng cao hơn so với chuyển HTTP mức thấp. Bạn có thể viết các lớp bê tông có sử dụng cả hai WebClientHttpClient, và sau đó sử dụng các container IoC để tiêm thực hiện qua cấu hình.

Điều này sẽ cho phép bạn làm là chuyển đổi giữa HttpClientWebClientdễ dàng để bạn có thể kiểm tra khách quan trong môi trường sản xuất.

Vì vậy, các câu hỏi như:

HttpClient sẽ là lựa chọn thiết kế tốt hơn nếu chúng tôi nâng cấp lên .Net 4.5?

Thực sự có thể được trả lời một cách khách quan bằng cách chuyển đổi giữa hai triển khai máy khách bằng cách sử dụng bộ chứa IoC. Đây là một giao diện ví dụ mà bạn có thể phụ thuộc vào đó không bao gồm bất kỳ chi tiết nào về HttpClienthoặc WebClient.

/// <summary>
/// Dependency Injection abstraction for rest clients. 
/// </summary>
public interface IClient
{
    /// <summary>
    /// Adapter for serialization/deserialization of http body data
    /// </summary>
    ISerializationAdapter SerializationAdapter { get; }

    /// <summary>
    /// Sends a strongly typed request to the server and waits for a strongly typed response
    /// </summary>
    /// <typeparam name="TResponseBody">The expected type of the response body</typeparam>
    /// <typeparam name="TRequestBody">The type of the request body if specified</typeparam>
    /// <param name="request">The request that will be translated to a http request</param>
    /// <returns></returns>
    Task<Response<TResponseBody>> SendAsync<TResponseBody, TRequestBody>(Request<TRequestBody> request);

    /// <summary>
    /// Default headers to be sent with http requests
    /// </summary>
    IHeadersCollection DefaultRequestHeaders { get; }

    /// <summary>
    /// Default timeout for http requests
    /// </summary>
    TimeSpan Timeout { get; set; }

    /// <summary>
    /// Base Uri for the client. Any resources specified on requests will be relative to this.
    /// </summary>
    Uri BaseUri { get; set; }

    /// <summary>
    /// Name of the client
    /// </summary>
    string Name { get; }
}

public class Request<TRequestBody>
{
    #region Public Properties
    public IHeadersCollection Headers { get; }
    public Uri Resource { get; set; }
    public HttpRequestMethod HttpRequestMethod { get; set; }
    public TRequestBody Body { get; set; }
    public CancellationToken CancellationToken { get; set; }
    public string CustomHttpRequestMethod { get; set; }
    #endregion

    public Request(Uri resource,
        TRequestBody body,
        IHeadersCollection headers,
        HttpRequestMethod httpRequestMethod,
        IClient client,
        CancellationToken cancellationToken)
    {
        Body = body;
        Headers = headers;
        Resource = resource;
        HttpRequestMethod = httpRequestMethod;
        CancellationToken = cancellationToken;

        if (Headers == null) Headers = new RequestHeadersCollection();

        var defaultRequestHeaders = client?.DefaultRequestHeaders;
        if (defaultRequestHeaders == null) return;

        foreach (var kvp in defaultRequestHeaders)
        {
            Headers.Add(kvp);
        }
    }
}

public abstract class Response<TResponseBody> : Response
{
    #region Public Properties
    public virtual TResponseBody Body { get; }

    #endregion

    #region Constructors
    /// <summary>
    /// Only used for mocking or other inheritance
    /// </summary>
    protected Response() : base()
    {
    }

    protected Response(
    IHeadersCollection headersCollection,
    int statusCode,
    HttpRequestMethod httpRequestMethod,
    byte[] responseData,
    TResponseBody body,
    Uri requestUri
    ) : base(
        headersCollection,
        statusCode,
        httpRequestMethod,
        responseData,
        requestUri)
    {
        Body = body;
    }

    public static implicit operator TResponseBody(Response<TResponseBody> readResult)
    {
        return readResult.Body;
    }
    #endregion
}

public abstract class Response
{
    #region Fields
    private readonly byte[] _responseData;
    #endregion

    #region Public Properties
    public virtual int StatusCode { get; }
    public virtual IHeadersCollection Headers { get; }
    public virtual HttpRequestMethod HttpRequestMethod { get; }
    public abstract bool IsSuccess { get; }
    public virtual Uri RequestUri { get; }
    #endregion

    #region Constructor
    /// <summary>
    /// Only used for mocking or other inheritance
    /// </summary>
    protected Response()
    {
    }

    protected Response
    (
    IHeadersCollection headersCollection,
    int statusCode,
    HttpRequestMethod httpRequestMethod,
    byte[] responseData,
    Uri requestUri
    )
    {
        StatusCode = statusCode;
        Headers = headersCollection;
        HttpRequestMethod = httpRequestMethod;
        RequestUri = requestUri;
        _responseData = responseData;
    }
    #endregion

    #region Public Methods
    public virtual byte[] GetResponseData()
    {
        return _responseData;
    }
    #endregion
}

Mã đầy đủ

Thực hiện httpClient

Bạn có thể sử dụng Task.Runđể thực hiện WebClientchạy không đồng bộ trong quá trình thực hiện.

Tiêm phụ thuộc, khi được thực hiện tốt giúp giảm bớt vấn đề phải đưa ra quyết định cấp thấp. Cuối cùng, cách duy nhất để biết câu trả lời thực sự là thử cả trong môi trường sống và xem cái nào hoạt động tốt nhất. Nó hoàn toàn có WebClientthể hoạt động tốt hơn đối với một số khách hàng và HttpClientcó thể hoạt động tốt hơn đối với những khách hàng khác. Đây là lý do tại sao sự trừu tượng là quan trọng. Điều đó có nghĩa là mã có thể nhanh chóng được hoán đổi hoặc thay đổi cấu hình mà không thay đổi thiết kế cơ bản của ứng dụng.


0

Ý kiến ​​không phổ biến từ năm 2020:

Khi nói đến ứng dụng ASP.NET tôi vẫn thích WebClienthơn HttpClientvì:

  1. Việc triển khai hiện đại đi kèm với các phương thức dựa trên nhiệm vụ async / awaitable
  2. Có dung lượng bộ nhớ nhỏ hơn và nhanh hơn gấp 2 lần (các câu trả lời khác đã đề cập đến điều đó), đặc biệt là trong các tình huống khi bạn không thể " sử dụng lại một phiên bản duy nhất của httpClient trong suốt thời gian sử dụng ứng dụng " như các nhà bình luận khác khuyên dùng. Và ASP.NET là một trong những kịch bản đó - không có "thời gian tồn tại của ứng dụng", chỉ có thời gian tồn tại của một yêu cầu.
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.