Memutuskan antara HttpClient dan WebClient

218

Aplikasi web kami berjalan di .Net Framework 4.0. UI memanggil metode pengontrol melalui panggilan ajax.

Kita perlu mengkonsumsi layanan REST dari vendor kami. Saya mengevaluasi cara terbaik untuk memanggil layanan REST di .Net 4.0. Layanan REST memerlukan Skema Otentikasi Dasar dan dapat mengembalikan data dalam XML dan JSON. Tidak ada persyaratan untuk mengunggah / mengunduh data besar dan saya tidak melihat apa pun di masa depan. Saya melihat beberapa proyek kode sumber terbuka untuk konsumsi REST dan tidak menemukan nilai pada mereka untuk membenarkan ketergantungan tambahan dalam proyek. Mulai mengevaluasi WebClientdan HttpClient. Saya mengunduh HttpClient untuk .Net 4.0 dari NuGet.

Saya mencari perbedaan antara WebClientdan HttpClientdan situs ini menyebutkan bahwa HttpClient tunggal dapat menangani panggilan bersamaan dan dapat menggunakan kembali DNS, konfigurasi cookie, dan otentikasi yang diselesaikan. Saya belum melihat nilai-nilai praktis yang dapat kita peroleh karena perbedaan.

Saya melakukan tes kinerja cepat untuk mengetahui kinerja WebClient(sinkronisasi panggilan), HttpClient(sinkronisasi dan asinkron). dan inilah hasilnya:

Menggunakan HttpClientcontoh yang sama untuk semua permintaan (minimal maks)

Sinkronisasi WebClient: 8 ms - 167 ms
HttpSinkronisasi klien: 3 ms - 7228 ms
HttpClient async: 985 - 10405 ms

Menggunakan yang baru HttpClientuntuk setiap permintaan (minimum)

Sinkronisasi WebClient: 4 ms - 297 ms
HttpSinkronisasi klien: 3 ms - 7953 ms
HttpClient async: 1027 - 10834 ms

Kode

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

Pertanyaan saya

  1. Panggilan REST kembali dalam 3-4 yang dapat diterima. Panggilan ke layanan REST dimulai dengan metode pengontrol yang dipanggil dari panggilan ajax. Untuk mulai dengan, panggilan berjalan di utas yang berbeda dan tidak memblokir UI. Jadi, bisakah saya tetap dengan panggilan sinkronisasi?
  2. Kode di atas dijalankan di kotak lokal saya. Dalam pengaturan prod, DNS dan pencarian proxy akan terlibat. Apakah ada keuntungan menggunakan HttpClientlebih WebClient?
  3. Apakah HttpClientkonkurensi lebih baik daripada WebClient? Dari hasil pengujian, saya melihat WebClientpanggilan sinkronisasi berkinerja lebih baik.
  4. Akankah HttpClientmenjadi pilihan desain yang lebih baik jika kita meningkatkan ke .Net 4.5? Kinerja adalah faktor desain utama.
pengguna3092913
sumber
5
Tes Anda tidak adil GetDataFromHttpClientAsynckarena berjalan terlebih dahulu, pemanggilan lainnya mendapatkan manfaat dari berpotensi memiliki data cahed (baik itu di mesin lokal atau proxy transparan antara Anda dan tujuan) dan akan lebih cepat. Selain itu, dalam kondisi yang tepat var response = httpClient.GetAsync("http://localhost:9000/api/values/").Result;dapat menyebabkan kebuntuan karena Anda melelahkan ulir threadpool. Anda seharusnya tidak pernah memblokir aktivitas yang bergantung pada kumpulan utas di utas ThreadPool, Anda harus memblokirnya awaitsehingga mengembalikan utas kembali ke kumpulan.
Scott Chamberlain
1
HttpClient dengan Web API Client sangat luar biasa untuk klien JSON / XML REST.
Cory Nelson
@Scott Chamberlain - Terima kasih atas balasan Anda. Karena semua panggilan tes dijalankan dalam Paralel. Namun, tidak ada jaminan yang mana yang akan dijalankan terlebih dahulu. Juga, memiliki panggilan pertama ke layanan ini dari GetDataFromHttpClientAsync, semua panggilan selanjutnya dari GetDataFromHttpClientAsync seharusnya mendapat manfaat dari cache dan berjalan lebih cepat. Saya tidak melihat hasilnya. Rgd tunggu, kami masih menggunakan 4.0. Saya setuju dengan Anda bahwa HttpClient dalam mode sinkronisasi akan menyebabkan kebuntuan dan saya memutuskan pilihan itu dari pertimbangan desain saya.
user3092913
@CoryNelson Bisakah Anda jelaskan mengapa HttpClient dengan Web API Client fantastis untuk klien JSON / XML REST?
user3092913
2
Berikut adalah beberapa kata tentang perbedaan antara HttpClient dan WebClient: blogs.msdn.com/b/henrikn/archive/2012/02/11/...
JustAndrei

Jawaban:

243

Saya tinggal di dunia F # dan Web API.

Ada banyak hal baik terjadi dengan Web API, terutama dalam bentuk penangan pesan untuk keamanan, dll.

Saya tahu pendapat saya hanya satu pendapat, tetapi saya hanya akan merekomendasikan penggunaan HttpClientuntuk setiap pekerjaan di masa depan . Mungkin ada beberapa cara untuk memanfaatkan beberapa karya lain yang keluar System.Net.Httptanpa menggunakan perakitan itu secara langsung, tetapi saya tidak bisa membayangkan bagaimana itu akan bekerja pada saat ini.

Berbicara tentang membandingkan keduanya

  • HttpClient lebih dekat ke HTTP daripada WebClient.
  • HttpClient tidak dimaksudkan sebagai pengganti lengkap Klien Web, karena ada hal-hal seperti melaporkan kemajuan, skema URI khusus, dan membuat panggilan FTP yang disediakan WebClient - tetapi HttpClient tidak.
+--------------------------------------------+--------------------------------------------+
|               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                |
+--------------------------------------------+--------------------------------------------+

Jika Anda menggunakan .NET 4.5, silakan gunakan async goodness dengan HttpClient yang disediakan Microsoft untuk pengembang. HttpClient sangat simetris dengan sisi server, saudara-saudara dari HTTP yaitu HttpRequest dan HttpResponse.

Pembaruan: 5 Alasan untuk menggunakan HttpClient API baru:

  • Tajuk yang sangat diketik.
  • Tembolok, cookie, dan kredensial yang dibagikan
  • Akses ke cookie dan cookie bersama
  • Kontrol atas caching dan cache bersama.
  • Suntikkan modul kode Anda ke dalam pipa ASP.NET. Kode bersih dan modular.

Referensi

C # 5.0 Joseph Albahari

(Channel9 - Video Build 2013)

Lima Alasan Besar untuk Menggunakan API HttpClient Baru untuk Menyambungkan ke Layanan Web

WebClient vs HttpClient vs HttpWebRequest

Anant Dabhi
sumber
4
Harus disebutkan bahwa HttpClient juga tersedia untuk .NET 4.0 .
Todd Menier
2
Ini tidak menjelaskan mengapa WebClient tampaknya lebih cepat daripada HttpClient. WebClientTampaknya juga memiliki metode async sekarang.
naksir
8
@ Crush itu karena OP membuat instance baru HttpClient untuk setiap permintaan tunggal. Alih-alih, Anda harus menggunakan satu instance HttpClient untuk masa aplikasi Anda. Lihat stackoverflow.com/a/22561368/57369
Gabriel
6
Perlu dicatat WebClienttidak tersedia di .Net Coretetapi HttpClient.
Pranav Singh
3
Sejak .Net Core 2.0 WebClient (di antara ribuan API lainnya) sudah kembali dan tersedia.
CoderBang
56

HttpClient adalah yang terbaru dari API dan memiliki manfaat

  • memiliki model pemrograman async yang baik
  • sedang dikerjakan oleh Henrik F Nielson yang pada dasarnya adalah salah satu penemu HTTP, dan dia merancang API sehingga mudah bagi Anda untuk mengikuti standar HTTP, misalnya menghasilkan tajuk yang sesuai standar.
  • ada dalam .Net framework 4.5, sehingga memiliki beberapa tingkat jaminan dukungan untuk masa depan yang dapat diduga
  • juga memiliki versi pustaka xcopyable / portable-framework perpustakaan jika Anda ingin menggunakannya pada platform lain -. Net 4.0, Windows Phone dll.

Jika Anda menulis layanan web yang membuat panggilan REST ke layanan web lain, Anda harus menggunakan model pemrograman async untuk semua panggilan REST Anda, sehingga Anda tidak mengalami kekosongan utas. Anda mungkin juga ingin menggunakan kompiler C # terbaru yang memiliki dukungan async / menunggu.

Catatan: Ini bukan AFAIK lebih banyak pemain. Ini mungkin agak berkinerja sama jika Anda membuat tes yang adil.

Tim Lovell-Smith
sumber
Jika ada cara untuk beralih proxy, itu akan menjadi gila
ed22
3

Pertama, saya bukan otoritas di WebClient vs HttpClient, khususnya. Kedua, dari komentar Anda di atas, tampaknya menyarankan bahwa WebClient adalah HANYA Sinkronisasi sedangkan HttpClient keduanya.

Saya melakukan tes kinerja cepat untuk menemukan bagaimana WebClient (Sinkronisasi panggilan), HttpClient (Sinkronisasi dan Async) melakukan. dan inilah hasilnya.

Saya melihat itu sebagai perbedaan besar ketika memikirkan masa depan, yaitu proses yang berjalan lama, GUI responsif, dll. (Menambah manfaat yang Anda sarankan oleh kerangka 4.5 - yang dalam pengalaman saya yang sebenarnya jauh lebih cepat pada IIS)

Anthony Horne
sumber
4
WebClienttampaknya memiliki kemampuan async dalam versi .NET terbaru. Saya ingin tahu mengapa tampaknya mengungguli HttpClient pada skala besar.
naksir
1
Menurut stackoverflow.com/a/4988325/1662973 , tampaknya sama, selain fakta bahwa satu adalah abstraksi yang lain. Mungkin, itu tergantung pada bagaimana objek digunakan / dimuat. Waktu minimum mendukung pernyataan bahwa webclient sebenarnya adalah abstraksi dari HttpClient, jadi ada biaya overhead milidetik. Kerangka kerja bisa menjadi "licik" dalam cara itu benar-benar mengumpulkan atau membuang klien web.
Anthony Horne
3

HttpClientFactory

Sangat penting untuk mengevaluasi berbagai cara Anda dapat membuat HttpClient, dan bagian dari itu adalah memahami HttpClientFactory.

https://docs.microsoft.com/en-us/dotnet/architecture/microservices/implement-resilient-applications/use-httpclientfactory-to-implement-resilient-http-requests

Ini bukan jawaban langsung yang saya tahu - tetapi Anda lebih baik memulai di sini daripada berakhir di new HttpClient(...)mana - mana.

Simon_Weaver
sumber
2

Saya memiliki patokan antara HttpClient, WebClient, HttpWebResponse lalu panggil Rest Web Api

dan hasil Tolak Tolok Ukur Api Web Rest

--------------------- Tahap 1 ---- 10 Permintaan

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

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

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

--------------------- Tahap 1 ---- 10 Permintaan - Ukuran Kecil

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

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

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

--------------------- Tahap 3 ---- 10 Permintaan sinkronisasi - Ukuran Kecil

{00:00: 15.3047502} ====> HttpClinet

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

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

--------------------- Tahap 4 ---- Permintaan 100 sinkronisasi - Ukuran Kecil

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

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

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

--------------------- Tahap 5 ---- 10 Permintaan sinkronisasi - Ukuran Maks

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

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

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

--------------------- Tahap 6 ---- 10 Permintaan sinkronisasi - Ukuran Maks

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

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

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

_____ WebClient Lebih cepat ()

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;

// ------------------------- Fungsi

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;
    }
pengguna3754071
sumber
1
Lihat komentar Gabriel di atas. Singkatnya, HttpClient jauh lebih cepat jika Anda membuat satu instance HttpClient dan menggunakannya kembali.
LT Dan
1

Mungkin Anda bisa memikirkan masalah dengan cara yang berbeda. WebClientdan HttpClientimplementasi pada dasarnya berbeda dari hal yang sama. Apa yang saya sarankan adalah menerapkan pola Injeksi Ketergantungan dengan Kontainer IoC di seluruh aplikasi Anda. Anda harus membangun antarmuka klien dengan tingkat abstraksi yang lebih tinggi daripada transfer HTTP tingkat rendah. Anda bisa menulis kelas konkret yang menggunakan keduanya WebClientdan HttpClient, dan kemudian menggunakan wadah IoC untuk menyuntikkan implementasi melalui konfigurasi.

Apa yang memungkinkan Anda lakukan adalah beralih di antara HttpClientdan WebClientdengan mudah sehingga Anda dapat menguji secara objektif di lingkungan produksi.

Jadi pertanyaan seperti:

Akankah HttpClient menjadi pilihan desain yang lebih baik jika kita meningkatkan ke .Net 4.5?

Sebenarnya dapat dijawab secara objektif dengan beralih di antara dua implementasi klien menggunakan wadah IoC. Berikut adalah contoh antarmuka yang mungkin Anda andalkan yang tidak menyertakan detail tentang HttpClientatau 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
}

Kode lengkap

Implementasi HttpClient

Anda dapat menggunakan Task.Rununtuk WebClientmenjalankan asinkron dalam implementasinya.

Ketergantungan Injeksi, ketika dilakukan dengan baik membantu meringankan masalah karena harus membuat keputusan tingkat rendah di muka. Pada akhirnya, satu-satunya cara untuk mengetahui jawaban yang benar adalah mencoba keduanya dalam lingkungan hidup dan melihat mana yang paling baik. Sangat WebClientmungkin untuk bekerja lebih baik untuk beberapa pelanggan, dan HttpClientmungkin bekerja lebih baik untuk orang lain. Inilah sebabnya mengapa abstraksi itu penting. Ini berarti kode dapat dengan cepat ditukar, atau diubah dengan konfigurasi tanpa mengubah desain dasar aplikasi.

Pengembang Melbourne
sumber
0

Pendapat tidak populer dari tahun 2020:

Ketika datang ke ASP.NET aplikasi saya masih lebih suka WebClientlebih HttpClientkarena:

  1. Implementasi modern dilengkapi dengan metode berbasis tugas async / awaitable
  2. Memiliki jejak memori yang lebih kecil dan 2x-5x lebih cepat (jawaban lain sudah menyebutkan itu) terutama dalam skenario ketika Anda tidak bisa " menggunakan kembali satu contoh HttpClient untuk masa aplikasi Anda " seperti yang direkomendasikan oleh komentator lain. Dan ASP.NET adalah salah satu skenario itu - tidak ada "masa aplikasi", hanya seumur hidup permintaan.
Alex
sumber