Nasza aplikacja internetowa działa w .Net Framework 4.0. Interfejs użytkownika wywołuje metody kontrolera za pośrednictwem wywołań ajax.
Musimy skorzystać z usługi REST od naszego dostawcy. Oceniam najlepszy sposób na wywołanie usługi REST w .Net 4.0. Usługa REST wymaga podstawowego schematu uwierzytelniania i może zwracać dane zarówno w formacie XML, jak i JSON. Nie ma wymogu przesyłania / pobierania dużych danych i nie widzę niczego w przyszłości. Przyjrzałem się kilku projektom z otwartym kodem źródłowym dla zużycia REST i nie znalazłem w nich żadnej wartości uzasadniającej dodatkową zależność w projekcie. Zaczął oceniać WebClient
i HttpClient
. Pobrałem HttpClient dla .Net 4.0 z NuGet.
Szukałem różnic między WebClient
a HttpClient
i ta strona wspomniano, że pojedyncze HttpClient mogą obsługiwać połączeń równoczesnych i może ponownego wykorzystania rozwiązany DNS, cookie config i uwierzytelniania. Mam jeszcze do czynienia z praktycznymi wartościami, które możemy zyskać z powodu różnic.
Zrobiłem szybki test wydajności, aby dowiedzieć się, jak działają WebClient
(synchronizacja połączeń), HttpClient
(synchronizacja i asynchronizacja). a oto wyniki:
Korzystanie z tej samej HttpClient
instancji dla wszystkich żądań (min. - maks.)
Synchronizacja WebClient: 8 ms - 167 ms
HttpClient synchronizacja: 3 ms - 7228 ms
HttpClient asynchronizacja: 985 - 10405 ms
Używanie nowego HttpClient
dla każdego żądania (min. - maks.)
Synchronizacja WebClient: 4 ms - 297 ms
HttpClient synchronizacja: 3 ms - 7953 ms
HttpClient asynchroniczna: 1027 - 10834 ms
Kod
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);
}
}
}
Moje pytania
- Połączenia REST zwracają w ciągu 3-4 sekund, co jest dopuszczalne. Wywołania usługi REST są inicjowane metodami kontrolera, które są wywoływane z wywołań ajax. Na początek wywołania działają w innym wątku i nie blokują interfejsu użytkownika. Czy mogę po prostu trzymać się synchronizacji połączeń?
- Powyższy kod został uruchomiony w mojej lokalnej skrzynce. W konfiguracji prod będą zaangażowane wyszukiwanie DNS i proxy. Czy jest jakaś korzyść z używania
HttpClient
ponadWebClient
? - Czy
HttpClient
współbieżność jest lepsza niżWebClient
? Z wyników testu widzę, żeWebClient
połączenia synchroniczne działają lepiej. - Czy
HttpClient
będzie lepszy wybór projektu, jeśli uaktualnimy do .Net 4.5? Wydajność jest kluczowym czynnikiem konstrukcyjnym.
GetDataFromHttpClientAsync
ponieważ uruchamia się jako pierwszy, inne wywołania mogą skorzystać z potencjalnego przetwarzania danych (na komputerze lokalnym lub dowolnym przezroczystym serwerze proxy między tobą a miejscem docelowym) i będą szybsze. Również w odpowiednich warunkachvar response = httpClient.GetAsync("http://localhost:9000/api/values/").Result;
może dojść do impasu z powodu wyczerpania wątków puli wątków. Nigdy nie powinieneś blokować działania zależnego od puli wątków w wątkach ThreadPool, powinieneśawait
zamiast tego zwrócić wątek z powrotem do puli.Odpowiedzi:
Mieszkam w światach F # i Web API.
Z interfejsem API sieci Web dzieje się wiele dobrych rzeczy, szczególnie w postaci programów obsługi komunikatów dla bezpieczeństwa itp.
Wiem, że moja jest tylko jedną opinią, ale poleciłabym ją tylko
HttpClient
do przyszłych prac . Być może istnieje jakiś sposób na wykorzystanie niektórych innych elementów, które powstająSystem.Net.Http
bez bezpośredniego użycia tego zestawu, ale nie mogę sobie wyobrazić, jak to by działało w tym momencie.Mówiąc o porównaniu tych dwóch
Jeśli używasz .NET 4.5, skorzystaj z asynchronicznej dobroci z HttpClient, którą Microsoft zapewnia programistom. HttpClient jest bardzo symetryczny dla braci HTTP po stronie serwera, są to HttpRequest i HttpResponse.
Aktualizacja: 5 powodów, dla których warto użyć nowego interfejsu API HttpClient:
Odniesienie
C # 5.0 Joseph Albahari
(Channel9 - Video Build 2013)
Pięć wspaniałych powodów, aby używać nowego interfejsu API HttpClient do łączenia się z usługami sieci Web
WebClient vs HttpClient vs HttpWebRequest
źródło
WebClient
Wydaje się również, że teraz ma metody asynchroniczne.WebClient
nie jest dostępny,.Net Core
aleHttpClient
jest.HttpClient jest nowszym interfejsem API i ma zalety
Jeśli piszesz usługę internetową, która wykonuje wywołania REST do innych usług internetowych, powinieneś chcieć używać modelu programowania asynchronicznego dla wszystkich swoich wywołań REST, aby nie uderzyć w głód wątku. Prawdopodobnie chcesz również użyć najnowszego kompilatora C #, który obsługuje async / oczekuje.
Uwaga: AFAIK nie jest bardziej wydajny. Prawdopodobnie działa podobnie podobnie, jeśli stworzysz uczciwy test.
źródło
Po pierwsze, nie jestem autorytetem w stosunku do WebClient vs. HttpClient. Po drugie, z powyższych komentarzy wydaje się sugerować, że WebClient jest TYLKO synchronizowany, podczas gdy HttpClient to oba.
Widzę to jako ogromną różnicę w myśleniu o przyszłości, tj. O długich procesach, responsywnym GUI itp. (Dodaj do korzyści, którą sugerujesz w frameworku 4.5 - który moim zdaniem jest znacznie szybszy w IIS)
źródło
WebClient
wydaje się mieć funkcje asynchroniczne w najnowszych wersjach .NET. Chciałbym wiedzieć, dlaczego wydaje się być lepszym od HttpClient na tak ogromną skalę.HttpClientFactory
Ważne jest, aby ocenić różne sposoby tworzenia HttpClient, a częścią tego jest zrozumienie HttpClientFactory.
https://docs.microsoft.com/en-us/dotnet/architecture/microservices/implement-resilient-applications/use-httpclientfactory-to-implement-resilient-http-requests
Wiem, że nie jest to bezpośrednia odpowiedź - ale lepiej zacząć od tego, niż skończyć
new HttpClient(...)
wszędzie.źródło
Mam test porównawczy między HttpClient, WebClient, HttpWebResponse, a następnie wywołaj Rest Web Api
i wynik Benchmark Call Rest Web Api
--------------------- Etap 1 ---- 10 Wniosek
{00: 00: 17.2232544} ====> HttpClinet
{00: 00: 04.3108986} ====> WebRequest
{00: 00: 04.5436889} ====> WebClient
--------------------- Etap 1 ---- 10 Wniosek - Mały rozmiar
{00: 00: 17.2232544} ====> HttpClinet
{00: 00: 04.3108986} ====> WebRequest
{00: 00: 04.5436889} ====> WebClient
--------------------- Etap 3 ---- Żądanie synchronizacji 10 - Mały rozmiar
{00: 00: 15.3047502} ====> HttpClinet
{00: 00: 03.5505249} ====> WebRequest
{00: 00: 04.0761359} ====> WebClient
--------------------- Etap 4 ---- Żądanie synchronizacji 100 - Mały rozmiar
{00: 03: 23.6268086} ====> HttpClinet
{00: 00: 47.1406632} ====> WebRequest
{00: 01: 01.2319499} ====> WebClient
--------------------- Etap 5 ---- 10 żądanie synchronizacji - maksymalny rozmiar
{00: 00: 58.1804677} ====> HttpClinet
{00: 00: 58.0710444} ====> WebRequest
{00: 00: 38.4170938} ====> WebClient
--------------------- Etap 6 ---- 10 żądanie synchronizacji - maksymalny rozmiar
{00: 01: 04.9964278} ====> HttpClinet
{00: 00: 59.1429764} ====> WebRequest
{00: 00: 32.0584836} ====> WebClient
_____ WebClient jest szybszy ()
//-------------------------Funkcje
źródło
Być może mógłbyś pomyśleć o problemie w inny sposób.
WebClient
iHttpClient
są zasadniczo różnymi implementacjami tej samej rzeczy. To, co zalecam, to wdrożenie wzorca Dependency Injection z kontenerem IoC w całej aplikacji. Powinieneś zbudować interfejs klienta z wyższym poziomem abstrakcji niż niskopoziomowy transfer HTTP. Możesz pisać konkretne klasy, które używają zarównoWebClient
iHttpClient
, a następnie użyć kontenera IoC wstrzyknąć realizację poprzez config.Pozwoliłoby to na przełączanie się między nimi
HttpClient
iWebClient
łatwość testowania w środowisku produkcyjnym.Więc pytania takie jak:
Można faktycznie odpowiedzieć obiektywnie, przełączając się między dwiema implementacjami klienta za pomocą kontenera IoC. Oto przykładowy interfejs, na którym możesz polegać, który nie zawiera żadnych szczegółów na temat
HttpClient
lubWebClient
.Pełny kod
Implementacja HttpClient
Możesz użyć,
Task.Run
abyWebClient
uruchomić asynchronicznie w jego implementacji.Wstrzykiwanie zależności, gdy jest dobrze wykonane, pomaga złagodzić problem związany z koniecznością podejmowania wcześniejszych decyzji na niskim poziomie. Ostatecznie jedynym sposobem na poznanie prawdziwej odpowiedzi jest wypróbowanie zarówno w środowisku na żywo, jak i sprawdzenie, który z nich działa najlepiej. Jest całkiem możliwe, że
WebClient
może działać lepiej dla niektórych klientów iHttpClient
może działać lepiej dla innych. Dlatego abstrakcja jest ważna. Oznacza to, że kod można szybko zamienić lub zmienić w konfiguracji bez zmiany podstawowego projektu aplikacji.źródło
Niepopularna opinia z 2020 roku:
Kiedy przychodzi do ASP.NET apps I wciąż wolą
WebClient
sięHttpClient
, ponieważ:źródło