Decydowanie między HttpClient a WebClient
Nasza aplikacja internetowa działa w .Net Framework 4.0. Interfejs użytkownika wywołuje metody kontrolera poprzez wywołania ajax.
Musimy korzystać z usługi REST od naszego dostawcy. Oceniam najlepszy sposób wywołania 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 potrzeby przesyłania / pobierania ogromnych danych i nic nie widzę w przyszłości. Przyjrzałem się kilku projektom otwartego kodu źródłowego pod kątem konsumpcji REST i nie znalazłem żadnej wartości w tych, które uzasadniałyby dodatkową zależność w projekcie. Zaczęłam oceniaćWebClient
iHttpClient
. Pobrałem HttpClient dla .Net 4.0 z NuGet.
Szukałem różnic między nimiWebClient
iHttpClient
ita strona wspomniał, że pojedynczy HttpClient może obsługiwać jednoczesne połączenia i może ponownie wykorzystywać rozwiązany DNS, konfigurację plików cookie i uwierzytelnianie. Muszę jeszcze zobaczyć praktyczne wartości, które możemy zyskać dzięki różnicom.
Zrobiłem szybki test wydajności, aby dowiedzieć się, jak to zrobićWebClient
(połączenia synchronizowane),HttpClient
(synchronizacja i asynchronizacja) działają. a oto wyniki:
Tak samoHttpClient
przykład dla wszystkich żądań (min - max)
Synchronizacja WebClient: 8 ms - 167 ms
Synchronizacja HttpClient: 3 ms - 7228 ms
HttpClient async: 985 - 10405 ms
Korzystanie z nowegoHttpClient
dla każdego żądania (min - max)
Synchronizacja WebClient: 4 ms - 297 ms
Synchronizacja HttpClient: 3 ms - 7953 ms
HttpClient async: 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);
}
}
}
Moje pytaniaPołączenia REST wracają w 3-4s, co jest dopuszczalne. Połączenia z usługą REST są inicjowane w metodach kontrolera, które są wywoływane z wywołań ajax. Po pierwsze, wywołania działają w innym wątku i nie blokują interfejsu użytkownika. Czy mogę po prostu trzymać się połączeń synchronizacyjnych?Powyższy kod został uruchomiony w moim localbox. W konfiguracji prod będą uwzględniane wyszukiwanie DNS i proxy. Czy jest jakaś korzyść z używaniaHttpClient
koniecWebClient
?JestHttpClient
współbieżność lepsza niżWebClient
? Z wyników testu widzęWebClient
połączenia synchronizacyjne działają lepiej.BędzieHttpClient
być lepszym wyborem projektu, jeśli uaktualnimy do .Net 4.5? Wydajność jest kluczowym czynnikiem projektu.