Выбор между HttpClient и WebClient

Наше веб-приложение работает в .NET Framework 4.0. Пользовательский интерфейс обрабатывает методы контроллера через вызовы ajax.

Нам нужно использовать REST-сервис у нашего поставщика. Я оцениваю лучший способ вызова службы REST в .NET 4.0. Служба REST требует базовой схемы аутентификации, и она может возвращать данные как в XML, так и в JSON. Нет необходимости загружать/загружать огромные данные, и я ничего не вижу в будущем. Я взглянул на несколько проектов с открытым исходным кодом для потребления REST и не нашел в них никакой ценности, чтобы оправдать дополнительную зависимость в проекте. Начали оценивать WebClient и HttpClient. Я загрузил HttpClient для .Net 4.0 из NuGet.

Я искал различия между WebClient и HttpClient и на этом сайте, что один HttpClient может обрабатывать одновременные вызовы и может повторно использовать разрешенные DNS, конфигурацию cookie и аутентификацию. Мне еще предстоит увидеть практические ценности, которые мы можем получить из-за различий.

Я сделал быстрый тест производительности, чтобы узнать, как выполнить WebClient (вызовы синхронизации), HttpClient (синхронизация и асинхронный). и вот результаты:

Используя тот же экземпляр HttpClient для всех запросов (min-max)

Синхронизация WebClient: 8 мс - 167 мс
Синхронизация HttpClient: 3 мс - 7228 мс
HttpClient async: 985 - 10405 мс

Используя новый HttpClient для каждого запроса (min - max)

Синхронизация WebClient: 4 мс - 297 мс
Синхронизация HttpClient: 3 мс - 7953 мс
HttpClient async: 1027 - 10834 мс

код

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

Мои вопросы

  • REST вызывает возврат в 3-4 секунды, что является приемлемым. Звонки в REST службы инициируются в методах контроллера, которые вызываются из ajax звонки. Начнем с того, что вызовы выполняются в другом потоке и не блокирует пользовательский интерфейс. Итак, могу ли я просто придерживаться вызовов синхронизации?
  • Вышеупомянутый код был запущен в моем локальном блоке. В настройке prod DNS и прокси-сервер поиск будет задействован. Есть ли преимущество использования HttpClient над WebClient?
  • Является ли HttpClient concurrency лучше, чем WebClient? Из результатов теста я вижу, что WebClient вызовы синхронизации выполняются лучше.
  • Будет ли HttpClient лучшим выбором дизайна, если мы перейдем на .Net 4.5? Производительность является ключевым фактором проектирования.

Ответы

Ответ 1

Я живу в мире F # и Web API.

С Web API происходит много хорошего, особенно в виде обработчиков сообщений для безопасности и т.д.

Я знаю, что мое мнение только одно, но я бы рекомендовал использовать HttpClient для любой будущей работы. Возможно, есть какой-то способ использовать некоторые другие части, выходящие из System.Net.Http, без непосредственного использования этой сборки, но я не могу представить, как это будет работать в настоящее время.

Говоря о сравнении этих двух

  • HttpClient ближе к HTTP, чем WebClient.
  • HttpClient не предназначался для полной замены веб-клиента, поскольку существуют такие вещи, как ход выполнения отчета, настраиваемая схема URI и выполнение FTP-вызовов, которые предоставляет WebClient, но HttpClient этого не делает.
+--------------------------------------------+--------------------------------------------+
|               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                |
+--------------------------------------------+--------------------------------------------+

Если вы используете .NET 4.5, пожалуйста, используйте асинхронные свойства HttpClient, которые Microsoft предоставляет разработчикам. HttpClient очень симметричен по отношению к собратьям на стороне сервера HTTP, а именно HttpRequest и HttpResponse.

Обновление: 5 причин использования нового API HttpClient:

  • Сильно типизированные заголовки.
  • Общие кэши, файлы cookie и учетные данные
  • Доступ к файлам cookie и общим файлам cookie
  • Контроль над кэшированием и общим кэшем.
  • Вставьте свой модуль кода в конвейер ASP.NET. Более чистый и модульный код.

Ссылка

С# 5.0 Джозеф Албахари

(Channel9 - Video Build 2013)

Пять веских причин использовать новый API HttpClient для подключения к веб-сервисам

WebClient против HttpClient против HttpWebRequest

Ответ 2

HttpClient является новее API и имеет преимущества

  • имеет хорошую асинхронную модель программирования
  • над которым работал Henrik F Nielson, который в основном является одним из изобретателей HTTP, и он разработал API, поэтому вам легко следовать стандарт HTTP, например. создание стандартных совместимых заголовков.
  • находится в .Net framework 4.5, поэтому он имеет некоторый гарантированный уровень поддержки для будущего будущего
  • также имеет версию xcopyable/portable-framework библиотеки, если вы хотите использовать ее на других платформах -.Net 4.0, Windows Phone и т.д.

Если вы пишете веб-службу, которая делает REST-вызовы другим веб-службам, вам следует использовать модель программирования асинхронного программирования для всех ваших вызовов REST, чтобы вы не ударили по голосу. Возможно, вы также захотите использовать новейший компилятор С# с поддержкой async/wait.

Примечание. Это не более эффективный AFAIK. Это, вероятно, несколько аналогично, если вы создадите честный тест.

Ответ 3

Во-первых, я не авторитет в WebClient и HttpClient, в частности. Во-вторых, из ваших комментариев выше, похоже, что WebClient синхронизирован ТОЛЬКО, тогда как HttpClient - оба.

Я сделал быстрый тест производительности, чтобы узнать, как работают WebClient (вызовы Sync), HttpClient (Sync и Async). и вот результаты.

Я вижу, что это огромная разница, когда вы думаете о будущем, то есть о длительных процессах, гибком графическом интерфейсе и т.д. (добавьте в пользу, которую вы предлагаете в рамках версии 4.5), которая в моем фактическом опыте значительно быстрее в IIS)