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 WebClient
und HttpClient
. Ich habe HttpClient für .Net 4.0 von NuGet heruntergeladen.
Ich habe nach Unterschieden zwischen WebClient
und gesucht HttpClient
und 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 HttpClient
Instanz 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 HttpClient
fü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
- 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?
- 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
HttpClient
overWebClient
? - Ist
HttpClient
Parallelität besser alsWebClient
? Aus den Testergebnissen geht hervor, dassWebClient
Synchronisierungsaufrufe eine bessere Leistung erbringen. - Wird
HttpClient
eine bessere Design-Wahl sein, wenn wir auf .Net 4.5 aktualisieren? Leistung ist der entscheidende Designfaktor.
GetDataFromHttpClientAsync
da 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 Bedingungenvar 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 solltenawait
Sie den Thread wieder in den Pool zurückgeben.Antworten:
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
HttpClient
für zukünftige Arbeiten zu verwenden . Vielleicht gibt es eine Möglichkeit, einige der anderen TeileSystem.Net.Http
zu 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
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:
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
quelle
WebClient
scheint jetzt async Methoden zu haben.WebClient
es nicht verfügbar ist,.Net Core
aber esHttpClient
ist.HttpClient ist die neuere API und bietet die Vorteile von
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.
quelle
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 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).
quelle
WebClient
scheint 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.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 ()
// ------------------------- Funktionen
quelle
HttpClientFactory
Es ist wichtig, die verschiedenen Möglichkeiten zum Erstellen eines HttpClient zu bewerten. Ein Teil davon ist das Verständnis von HttpClientFactory.
https://docs.microsoft.com/en-us/dotnet/architecture/microservices/implement-resilient-applications/use-httpclientfactory-to-implement-resilient-http-requests
Dies ist keine direkte Antwort, die ich kenne - aber Sie sollten besser hier anfangen, als
new HttpClient(...)
überall zu landen .quelle
Vielleicht könnten Sie das Problem anders betrachten.
WebClient
undHttpClient
sind 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 sowohlWebClient
als als auch verwendenHttpClient
, und dann den IoC-Container verwenden, um die Implementierung über config zu injizieren.Dies würde es Ihnen ermöglichen, zwischen
HttpClient
undWebClient
einfach zu wechseln, damit Sie objektiv in der Produktionsumgebung testen können.Also Fragen wie:
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
HttpClient
oder enthältWebClient
.Vollständiger Code
HttpClient-Implementierung
Sie können verwenden
Task.Run
, um dieWebClient
Ausfü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
WebClient
für einige KundenHttpClient
besser 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.quelle
Unpopuläre Meinung von 2020:
Wenn es darum geht zu ASP.NET apps ich immer noch lieber
WebClient
über ,HttpClient
weil:quelle