System.Net.Http.HttpClient и System.Net.Http.HttpClientHandler в .NET Framework 4.5 реализуют IDisposable (через System.Net.Http.HttpMessageInvoker ).
В using
заявлении говорится:
Как правило, когда вы используете объект IDisposable, вы должны объявить и создать его экземпляр в операторе using.
Этот ответ использует этот шаблон:
var baseAddress = new Uri("http://example.com");
var cookieContainer = new CookieContainer();
using (var handler = new HttpClientHandler() { CookieContainer = cookieContainer })
using (var client = new HttpClient(handler) { BaseAddress = baseAddress })
{
var content = new FormUrlEncodedContent(new[]
{
new KeyValuePair<string, string>("foo", "bar"),
new KeyValuePair<string, string>("baz", "bazinga"),
});
cookieContainer.Add(baseAddress, new Cookie("CookieName", "cookie_value"));
var result = client.PostAsync("/test", content).Result;
result.EnsureSuccessStatusCode();
}
Но наиболее заметные примеры от Microsoft не вызывают Dispose()
ни явно, ни неявно. Например:
- Оригинальный блог статья объявляет о HttpClient разблокировки , .
- Актуальная документация MSDN для HttpClient.
- BingTranslateSample
- GoogleMapsSample
- WorldBankSample
В комментариях к объявлению кто-то спросил сотрудника Microsoft:
После проверки ваших образцов я увидел, что вы не выполняли действие dispose на экземпляре HttpClient. Я использовал все экземпляры HttpClient с оператором using в своем приложении, и я подумал, что это правильный путь, поскольку HttpClient реализует интерфейс IDisposable. Я на правильном пути?
Его ответ был:
В общем, это правильно, хотя вы должны быть осторожны с «использованием» и асинхронностью, поскольку они не смешиваются в .Net 4, в .Net 4.5 вы можете использовать «ожидание» внутри выражения «использование».
Кстати, вы можете повторно использовать один и тот же HttpClient столько раз, сколько вам нужно, поэтому обычно вы не будете создавать / распоряжаться ими все время.
Второй абзац лишний для этого вопроса, который касается не того, сколько раз вы можете использовать экземпляр HttpClient, а того, нужно ли его утилизировать после того, как он вам больше не нужен.
(Обновление: фактически, второй абзац является ключом к ответу, как указано ниже @DPeden.)
Итак, мои вопросы:
Необходимо ли, учитывая текущую реализацию (.NET Framework 4.5), вызывать Dispose () для экземпляров HttpClient и HttpClientHandler? Пояснение: под «необходимым» я подразумеваю, есть ли какие-либо негативные последствия для отказа от утилизации, такие как утечка ресурсов или риски повреждения данных.
Если в этом нет необходимости, будет ли это хорошей практикой, так как они реализуют IDisposable?
Если это необходимо (или рекомендуется), этот код, упомянутый выше, реализует его безопасно (для .NET Framework 4.5)?
Если эти классы не требуют вызова Dispose (), почему они были реализованы как IDisposable?
Если они требуют, или если это рекомендуемая практика, примеры Microsoft вводят в заблуждение или небезопасны?
источник
Flush
одну запись после каждой записи, и, кроме неудобств, связанных с продолжением удержания базовых ресурсов дольше, чем необходимо, что не произойдет, что требуется для «правильного поведения»?Ответы:
По общему мнению, вам не нужно (не нужно) избавляться от HttpClient.
Многие люди, которые тесно связаны с тем, как это работает, заявили об этом.
См. Сообщение в блоге Даррела Миллера и соответствующий пост SO: сканирование HttpClient приводит к утечке памяти для справки.
Я также настоятельно рекомендую прочитать главу HttpClient из раздела Разработка веб-API Evolvable с ASP.NET для контекста того, что происходит под капотом, особенно в разделе «Жизненный цикл», цитируемом здесь:
Или даже открыть DotPeek.
источник
Timeout
свойство, не топают друг друга?Текущие ответы немного сбивают с толку и вводят в заблуждение, и они пропускают некоторые важные последствия DNS. Я постараюсь подвести итог, где все четко.
IDisposable
объектов в идеале следует утилизировать, когда вы закончите с ними , особенно те, которые владеют именованными / общими ресурсами ОС .HttpClient
Не исключение, поскольку, как указывает Даррел Миллер , он выделяет токены отмены, а тела запросов / ответов могут быть неуправляемыми потоками.Connection:close
заголовок после изменения DNS. Другая возможность включает в себя повторное использованиеHttpClient
на стороне клиента, либо периодически, либо с помощью какого-либо механизма, который узнает об изменении DNS. См. Https://github.com/dotnet/corefx/issues/11224 для получения дополнительной информации (я предлагаю внимательно прочитать ее, прежде чем вслепую использовать код, предложенный в связанном сообщении в блоге).источник
В моем понимании, вызов
Dispose()
необходим только тогда, когда он блокирует ресурсы, которые вам понадобятся позже (например, конкретное соединение). Это всегда рекомендуется , чтобы освободить ресурсы , которые больше не используется, даже если вам не нужно их снова, просто потому , что вы не должны вообще быть держась за ресурсы , которые вы не используете (каламбур).Пример Microsoft не является неправильным, обязательно. Все используемые ресурсы будут освобождены при выходе из приложения. И в случае этого примера это происходит почти сразу после того,
HttpClient
как сделано, используется. В подобных случаях явный вызовDispose()
несколько избыточен.Но, как правило, когда класс реализует
IDisposable
, понимается, что вы должныDispose()
его экземпляры, как только вы полностью готовы и способны. Я бы сказал, что это особенно верно в тех случаях,HttpClient
когда явно не задокументировано, какие ресурсы или соединения удерживаются / открываются. В случае, когда соединение будет повторно использовано [скоро], вы захотите отказатьсяDipose()
от него - в этом случае вы не «полностью готовы».См. Также: Метод IDisposable.Dispose и Когда вызывать Dispose.
источник
Dispose()
преждевременно его устанавливать, и вам придется повторно подключаться через несколько секунд, если существующее соединение можно использовать повторно. Кроме того, вы не хотите излишнеDispose()
изображения или других структур, вам может понадобиться восстановить через минуту или две.Dispose () вызывает приведенный ниже код, который закрывает соединения, открытые экземпляром HttpClient. Код был создан декомпиляцией с помощью dotPeek.
HttpClientHandler.cs - избавиться
Если вы не вызываете dispose, то ServicePointManager.MaxServicePointIdleTime, запускаемый таймером, закроет http-соединения. По умолчанию это 100 секунд.
ServicePointManager.cs
Если вы не установили время простоя равным бесконечности, то кажется безопасным не вызывать утилизацию и позволить таймеру бездействующего соединения запускать и закрывать соединения для вас, хотя было бы лучше, чтобы вы вызывали dispose в операторе using, если вы знаете, что вы сделали с экземпляром HttpClient и быстрее высвободите ресурсы.
источник
Краткий ответ: Нет, утверждение в принятом в настоящее время ответе НЕ является точным : «Общее мнение заключается в том, что вам не нужно (не нужно) избавляться от HttpClient».
Длинный ответ : ОБА из следующих утверждений верны и достижимы одновременно:
IDisposable
Объект должен / рекомендуется быть утилизированы.И они НЕ ОБЯЗАТЕЛЬНО конфликтуют друг с другом. Это просто вопрос того, как вы организуете свой код для повторного использования
HttpClient
и по-прежнему правильно его используете.Еще более длинный ответ процитирован из моего другого ответа :
Это не совпадение , чтобы видеть , как человек в некоторых блогах обвиняющих как
HttpClient
«SIDisposable
интерфейс делает их , как правило , использоватьusing (var client = new HttpClient()) {...}
шаблон , а затем привести к истощенным проблемам обработчика сокета.Я полагаю, что это сводится к негласной (ошибочной?) Концепции: «ожидается, что IDisposable объект будет недолговечным» .
ОДНАКО, хотя это, конечно, выглядит недолгим, когда мы пишем код в этом стиле:
официальная документация по IDisposable никогда не упоминает
IDisposable
объекты должны быть кратковременными. По определению IDisposable - это просто механизм, позволяющий вам высвобождать неуправляемые ресурсы. Ничего более. В этом смысле вы ОЖИДАЕТЕ в конечном итоге инициировать утилизацию, но это не требует, чтобы вы делали это недолгим образом.Поэтому ваша задача - правильно выбрать, когда инициировать утилизацию, исходя из требований жизненного цикла вашего реального объекта. Ничто не мешает вам использовать IDisposable в течение длительного времени:
С этим новым пониманием, теперь, когда мы возвращаемся к этому сообщению в блоге , мы можем четко заметить, что «исправление» инициализируется
HttpClient
один раз, но никогда не удаляет его, поэтому мы можем видеть из его вывода netstat, что соединение остается в состоянии ESTABLISHED, что означает НЕ был правильно закрыт. Если бы он был закрыт, его состояние было бы в TIME_WAIT. На практике нет ничего страшного в том, чтобы пропустить только одно открытое соединение после завершения всей вашей программы, и постер блога все еще видит увеличение производительности после исправления; но все же, концептуально некорректно обвинять IDisposable и выбирать НЕ распоряжаться им.источник
HttpClient.Dispose
?.HttpClient client
переменной, что является программированием-101, что вы, по-видимому, уже делаете в любом случае. Вы могли бы даже быть в состоянии использоватьusing (...) {...}
тоже. Например, посмотрите образец Hello World внутри моего ответа.Поскольку, похоже, никто еще не упомянул об этом здесь, новый лучший способ управления HttpClient и HttpClientHandler в .Net Core 2.1 использует HttpClientFactory .
Он решает большинство вышеупомянутых проблем и ошибок простым и удобным способом. Из великого сообщения в блоге Стива Гордона :
Добавьте следующие пакеты в ваш проект .Net Core (2.1.1 или новее):
Добавьте это в Startup.cs:
Внедрить и использовать:
Изучите серию публикаций в блоге Стива, чтобы узнать о многих других возможностях.
источник
В моем случае я создавал HttpClient внутри метода, который фактически выполнял вызов службы. Что-то вроде:
В рабочей роли Azure после повторного вызова этого метода (без удаления HttpClient) он в конечном итоге завершится с ошибкой
SocketException
(попытка подключения не удалась).Я сделал HttpClient переменной экземпляра (расположив ее на уровне класса), и проблема исчезла. Поэтому я бы сказал, что да, утилизируйте HttpClient, предполагая, что это безопасно (у вас нет выдающихся асинхронных вызовов).
источник
При обычном использовании (ответы <2 ГБ) нет необходимости утилизировать сообщения HttpResponseMessages.
Возвращаемые типы методов HttpClient должны быть удалены, если их потоковое содержимое не полностью прочитано. В противном случае CLR не сможет узнать, что эти потоки могут быть закрыты до тех пор, пока они не будут собраны.
Если для HttpCompletionOption задано значение ResponseHeadersRead или размер ответа превышает 2 ГБ, следует выполнить очистку. Это можно сделать, вызвав Dispose для HttpResponseMessage или вызвав Dispose / Close для потока, полученного из содержимого HttpResonseMessage, или полностью прочитав его.
Вызываете ли вы Dispose на HttpClient, зависит от того, хотите ли вы отменить ожидающие запросы или нет.
источник
Если вы хотите избавиться от HttpClient, вы можете, если вы настроите его как пул ресурсов. И в конце вашего приложения вы распределяете свой пул ресурсов.
Код:
var handler = HttpClientHander.GetHttpClientHandle (новый Uri («базовый URL»)).
источник
Dispose
метод, который вы регистрируете в GC. Это должно быть оценено выше на вершине.Использование внедрения зависимостей в вашем конструкторе упрощает управление временем жизни вашего приложения
HttpClient
- вынимает управляющий ресурс жизни за пределами кода, который в этом нуждается, и делает его легко изменяемым на более позднем этапе.В настоящее время я предпочитаю создать отдельный клиентский класс http, который наследует
HttpClient
один раз для целевого домена конечной точки, а затем сделать его одиночным с помощью внедрения зависимостей.public class ExampleHttpClient : HttpClient { ... }
Затем я беру зависимость конструктора от пользовательского http-клиента в классах обслуживания, где мне нужен доступ к этому API. Это решает проблему срока службы и имеет преимущества, когда речь идет о пуле соединений.
Вы можете увидеть обработанный пример в соответствующем ответе на https://stackoverflow.com/a/50238944/3140853
источник
Пожалуйста, прочитайте мой ответ на очень похожий вопрос, размещенный ниже. Должно быть ясно, что вы должны рассматривать
HttpClient
экземпляры как одиночные и повторно использовать в запросах.Каковы затраты на создание нового HttpClient для каждого вызова в клиенте WebAPI?
источник
Я думаю, что следует использовать шаблон синглтона, чтобы избежать необходимости создавать экземпляры HttpClient и постоянно его закрывать. Если вы используете .Net 4.0, вы можете использовать пример кода, как показано ниже. Для получения дополнительной информации о шаблоне синглтон, проверьте здесь .
Используйте код, как показано ниже.
источник