Entscheidung zwischen HttpClient und WebClient

218

Unsere Web-App läuft in .Net Framework 4.0. Die Benutzeroberfläche ruft Controller-Methoden über Ajax-Aufrufe auf.

Wir müssen den REST-Service unseres Anbieters in Anspruch nehmen. Ich prüfe, wie der REST-Service in .Net 4.0 am besten aufgerufen werden kann. Der REST-Service erfordert ein Standardauthentifizierungsschema und kann Daten sowohl in XML als auch in JSON zurückgeben. Das Hochladen / Herunterladen großer Datenmengen ist nicht erforderlich, und ich sehe in Zukunft nichts mehr. Ich habe mir einige Open-Source-Code-Projekte für den REST-Verbrauch angesehen und in diesen keinen Wert gefunden, um eine zusätzliche Abhängigkeit im Projekt zu rechtfertigen. Begann zu bewerten WebClientund HttpClient. Ich habe HttpClient für .Net 4.0 von NuGet heruntergeladen.

Ich habe nach Unterschieden zwischen WebClientund gesucht HttpClientund auf dieser Site wurde erwähnt, dass ein einzelner HttpClient gleichzeitige Anrufe verarbeiten und aufgelöstes DNS, Cookie-Konfiguration und Authentifizierung wiederverwenden kann. Ich sehe noch keine praktischen Werte, die wir aufgrund der Unterschiede gewinnen können.

Ich habe einen kurzen Leistungstest durchgeführt, um herauszufinden, wie WebClient(Synchronisierungsaufrufe), HttpClient(Synchronisierung und Asynchronisierung) funktionieren . und hier sind die Ergebnisse:

Verwenden derselben HttpClientInstanz für alle Anforderungen (min - max)

WebClient-Synchronisierung: 8 ms - 167 ms
HttpClient-Synchronisierung: 3 ms - 7228 ms
HttpClient- Synchronisierung : 985 - 10405 ms

Verwenden eines neuen HttpClientfür jede Anforderung (min - max)

WebClient-Synchronisierung: 4 ms - 297 ms
HttpClient-Synchronisierung: 3 ms - 7953 ms
HttpClient-Asynchronisierung: 1027 - 10834 ms

Code

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

Meine Fragen

  1. Die REST-Aufrufe kehren in 3-4 Sekunden zurück, was akzeptabel ist. Aufrufe des REST-Dienstes werden in Controller-Methoden initiiert, die von Ajax-Aufrufen aufgerufen werden. Zunächst werden die Aufrufe in einem anderen Thread ausgeführt und blockieren die Benutzeroberfläche nicht. Kann ich mich also einfach an Synchronisierungsanrufe halten?
  2. Der obige Code wurde in meiner Localbox ausgeführt. Bei der Prod-Einrichtung werden DNS- und Proxy-Lookup beteiligt sein. Gibt es einen Vorteil der Verwendung von HttpClientover WebClient?
  3. Ist HttpClientParallelität besser als WebClient? Aus den Testergebnissen geht hervor, dass WebClientSynchronisierungsaufrufe eine bessere Leistung erbringen.
  4. Wird HttpClienteine bessere Design-Wahl sein, wenn wir auf .Net 4.5 aktualisieren? Leistung ist der entscheidende Designfaktor.
user3092913
quelle
5
Ihr Test ist unfair, GetDataFromHttpClientAsyncda er zuerst ausgeführt wird. Die anderen Aufrufe profitieren davon, dass möglicherweise Daten gespeichert sind (sei es auf dem lokalen Computer oder einem transparenten Proxy zwischen Ihnen und dem Ziel), und sind schneller. Unter den richtigen Bedingungen var response = httpClient.GetAsync("http://localhost:9000/api/values/").Result;kann es auch zu einem Deadlock kommen, da Sie Threadpool-Threads erschöpfen. Sie sollten niemals eine Aktivität blockieren, die vom Thread-Pool in ThreadPool-Threads abhängt. Stattdessen sollten awaitSie den Thread wieder in den Pool zurückgeben.
Scott Chamberlain
1
HttpClient mit Web-API-Client ist fantastisch für einen JSON / XML-REST-Client.
Cory Nelson
@ Scott Chamberlain - Danke für deine Antwort. Da alle Testaufrufe parallel ausgeführt werden, gibt es keine Garantie dafür, welcher zuerst ausgeführt wurde. Wenn der erste Aufruf des Dienstes von GetDataFromHttpClientAsync erfolgte, sollten alle nachfolgenden Aufrufe von GetDataFromHttpClientAsync vom Cache profitiert haben und schneller ausgeführt werden. Das habe ich im Ergebnis nicht gesehen. Rgd warten, wir verwenden immer noch 4.0. Ich stimme Ihnen zu, dass HttpClient auf synchrone Weise zu einem Deadlock führen würde, und ich schließe diese Option aus meiner Entwurfsüberlegung aus.
user3092913
@CoryNelson Können Sie bitte erläutern, warum HttpClient mit Web-API-Client für einen JSON / XML-REST-Client fantastisch ist?
user3092913
2
Hier sind einige Worte zum Unterschied zwischen HttpClient und WebClient: blogs.msdn.com/b/henrikn/archive/2012/02/11/…
JustAndrei

Antworten:

243

Ich lebe sowohl in der F # - als auch in der Web-API-Welt.

Mit der Web-API passieren viele gute Dinge, insbesondere in Form von Nachrichtenhandlern für die Sicherheit usw.

Ich weiß, dass meine Meinung nur eine ist, aber ich würde nur empfehlen, sie HttpClientfür zukünftige Arbeiten zu verwenden . Vielleicht gibt es eine Möglichkeit, einige der anderen Teile System.Net.Httpzu nutzen, ohne diese Baugruppe direkt zu verwenden, aber ich kann mir nicht vorstellen, wie das zu diesem Zeitpunkt funktionieren würde.

Apropos Vergleich dieser beiden

  • HttpClient ist HTTP näher als WebClient.
  • HttpClient war nicht als vollständiger Ersatz für Web Client gedacht, da WebClient beispielsweise den Fortschritt von Berichten, ein benutzerdefiniertes URI-Schema und FTP-Aufrufe bereitstellt, HttpClient jedoch nicht.
+--------------------------------------------+--------------------------------------------+
|               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                |
+--------------------------------------------+--------------------------------------------+

Wenn Sie .NET 4.5 verwenden, verwenden Sie bitte die asynchrone Güte mit HttpClient, die Microsoft den Entwicklern zur Verfügung stellt. HttpClient ist sehr symmetrisch zu den serverseitigen Brüdern des HTTP, nämlich HttpRequest und HttpResponse.

Update: 5 Gründe für die Verwendung der neuen HttpClient-API:

  • Stark getippte Header.
  • Freigegebene Caches, Cookies und Anmeldeinformationen
  • Zugriff auf Cookies und freigegebene Cookies
  • Kontrolle über Caching und gemeinsam genutzten Cache.
  • Fügen Sie Ihr Codemodul in die ASP.NET-Pipeline ein. Sauberer und modularer Code.

Referenz

C # 5.0 Joseph Albahari

(Channel9 - Video Build 2013)

Fünf gute Gründe, die neue HttpClient-API für die Verbindung mit Webdiensten zu verwenden

WebClient vs HttpClient vs HttpWebRequest

Anant Dabhi
quelle
4
Es sollte erwähnt werden, dass HttpClient auch für .NET 4.0 verfügbar ist .
Todd Menier
2
Dies erklärt nicht, warum WebClient um Größenordnungen schneller zu sein scheint als HttpClient. Auch WebClientscheint jetzt async Methoden zu haben.
Crush
8
@crush, weil das OP für jede einzelne Anforderung eine neue Instanz von HttpClient erstellt. Stattdessen sollten Sie eine einzelne Instanz von HttpClient für die Lebensdauer Ihrer Anwendung verwenden. Siehe stackoverflow.com/a/22561368/57369
Gabriel
6
Es ist erwähnenswert, dass WebClientes nicht verfügbar ist, .Net Coreaber es HttpClientist.
Pranav Singh
3
Seit .Net Core 2.0 ist WebClient (neben Tausenden anderer APIs) wieder verfügbar.
CoderBang
56

HttpClient ist die neuere API und bietet die Vorteile von

  • hat ein gutes asynchrones Programmiermodell
  • Henrik F. Nielson, der im Grunde einer der Erfinder von HTTP ist, hat an der API gearbeitet, sodass Sie den HTTP-Standard problemlos befolgen können, z. B. standardkonforme Header erstellen können
  • befindet sich im .Net-Framework 4.5, sodass auf absehbare Zeit ein gewisses Maß an Unterstützung garantiert ist
  • hat auch die xcopyable / portable-Framework-Version der Bibliothek, wenn Sie sie auf anderen Plattformen verwenden möchten - .Net 4.0, Windows Phone usw.

Wenn Sie einen Webdienst schreiben, der REST-Aufrufe an andere Webdienste ausführt, sollten Sie für alle Ihre REST-Aufrufe ein asynchrones Programmiermodell verwenden, damit Sie nicht auf Thread-Hunger stoßen. Sie möchten wahrscheinlich auch den neuesten C # -Compiler verwenden, der asynchrone / warte-Unterstützung bietet.

Hinweis: Es ist nicht leistungsfähiger AFAIK. Es ist wahrscheinlich etwas ähnlich performant, wenn Sie einen fairen Test erstellen.

Tim Lovell-Smith
quelle
Wenn es eine Möglichkeit gäbe, den Proxy zu wechseln, wäre es verrückt
22.
3

Erstens bin ich keine Autorität für WebClient vs. HttpClient. Zweitens scheint es aus Ihren obigen Kommentaren darauf hinzudeuten, dass WebClient NUR synchronisiert ist, während HttpClient beides ist.

Ich habe einen kurzen Leistungstest durchgeführt, um herauszufinden, wie WebClient (Synchronisierungsaufrufe), HttpClient (Synchronisierung und Asynchronisierung) funktionieren. und hier sind die Ergebnisse.

Ich sehe dies als einen großen Unterschied, wenn ich an die Zukunft denke, dh an Prozesse mit langer Laufzeit, reaktionsschnelle Benutzeroberfläche usw. (zusätzlich zu dem Nutzen, den Sie durch Framework 4.5 vorschlagen - was meiner Erfahrung nach unter IIS erheblich schneller ist).

Anthony Horne
quelle
4
WebClientscheint in den neuesten .NET-Versionen über asynchrone Funktionen zu verfügen. Ich würde gerne wissen, warum es HttpClient in so großem Umfang zu übertreffen scheint.
Crush
1
Laut stackoverflow.com/a/4988325/1662973 scheint es dasselbe zu sein, abgesehen von der Tatsache, dass das eine eine Abstraktion des anderen ist. Möglicherweise hängt es davon ab, wie die Objekte verwendet / geladen werden. Die Mindestzeit unterstützt die Aussage, dass der Webclient tatsächlich eine Abstraktion von HttpClient ist, sodass ein Overhead von Millisekunden anfällt. Das Framework könnte "hinterhältig" sein, wie es Webclient wirklich bündelt oder entsorgt.
Anthony Horne
2

Ich habe einen Benchmark zwischen HttpClient, WebClient, HttpWebResponse und rufe dann Rest Web Api auf

und Ergebnis Call Rest Web Api Benchmark

--------------------- Stufe 1 ---- 10 Anfrage

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

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

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

--------------------- Stufe 1 ---- 10 Anfrage - Klein

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

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

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

--------------------- Stufe 3 ---- 10 Synchronisierungsanforderung - Kleine Größe

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

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

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

--------------------- Stufe 4 ---- 100 Synchronisierungsanforderung - Kleine Größe

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

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

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

--------------------- Stufe 5 ---- 10 Synchronisierungsanforderung - Maximale Größe

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

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

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

--------------------- Stufe 6 ---- 10 Synchronisierungsanforderung - Maximale Größe

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

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

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

_____ WebClient ist schneller ()

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;

// ------------------------- Funktionen

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;
    }
user3754071
quelle
1
Siehe Gabriels Kommentar oben. Kurz gesagt, HttpClient ist viel schneller, wenn Sie eine Instanz von HttpClient erstellen und wiederverwenden.
LT Dan
1

Vielleicht könnten Sie das Problem anders betrachten. WebClientund HttpClientsind im Wesentlichen unterschiedliche Implementierungen derselben Sache. Ich empfehle, das Abhängigkeitsinjektionsmuster mit einem IoC-Container in Ihrer gesamten Anwendung zu implementieren . Sie sollten eine Client-Schnittstelle mit einer höheren Abstraktionsebene als der HTTP-Übertragung auf niedriger Ebene erstellen. Sie können konkrete Klassen schreiben, die sowohl WebClientals als auch verwendenHttpClient , und dann den IoC-Container verwenden, um die Implementierung über config zu injizieren.

Dies würde es Ihnen ermöglichen, zwischen HttpClientund WebClienteinfach zu wechseln, damit Sie objektiv in der Produktionsumgebung testen können.

Also Fragen wie:

Wird HttpClient eine bessere Wahl für das Design sein, wenn wir auf .Net 4.5 aktualisieren?

Kann tatsächlich objektiv beantwortet werden, indem zwischen den beiden Client-Implementierungen mithilfe des IoC-Containers gewechselt wird. Hier ist eine Beispielschnittstelle, auf die Sie möglicherweise angewiesen sind und die keine Details zu HttpClientoder enthält 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
}

Vollständiger Code

HttpClient-Implementierung

Sie können verwenden Task.Run, um die WebClientAusführung in der Implementierung asynchron durchzuführen.

Abhängigkeitsinjektion hilft, wenn sie gut durchgeführt wird, das Problem zu lösen, Entscheidungen auf niedriger Ebene im Voraus treffen zu müssen. Letztendlich ist die einzige Möglichkeit, die wahre Antwort zu finden, beide in einer Live-Umgebung zu versuchen und herauszufinden, welche am besten funktioniert. Es ist durchaus möglich, dass dies WebClientfür einige Kunden HttpClientbesser und für andere besser funktioniert. Deshalb ist Abstraktion wichtig. Dies bedeutet, dass Code schnell ausgetauscht oder mit der Konfiguration geändert werden kann, ohne das grundlegende Design der App zu ändern.

Melbourne Entwickler
quelle
0

Unpopuläre Meinung von 2020:

Wenn es darum geht zu ASP.NET apps ich immer noch lieber WebClientüber , HttpClientweil:

  1. Die moderne Implementierung verfügt über asynchrone / erwartete aufgabenbasierte Methoden
  2. Hat einen geringeren Speicherbedarf und ist 2x-5x schneller (andere Antworten erwähnen dies bereits), insbesondere in Szenarien, in denen Sie nicht " eine einzelne Instanz von HttpClient für die Lebensdauer Ihrer Anwendung wiederverwenden können ", wie andere Kommentatoren empfehlen. Und ASP.NET ist eines dieser Szenarien - es gibt keine "Lebensdauer der Anwendung", nur die Lebensdauer einer Anforderung.
Alex
quelle