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

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 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.

questionAnswers(3)

yourAnswerToTheQuestion