Комментарии 17
Все мы что-нибудь да пулируем.))
Странно, что в статье про использование HttpClient в современном .NET нет ни слова про Socket Exhaustion, в свете чего совет "В современном .NET: использовать статический HttpClient экземпляр (или синглтон).." выглядит максимально неоднозначно.
@KoscheyScrag, если вдруг не знаком с проблемой - это важный момент, вот ссылки на источники на случай, если решишь изучить вопрос дополнить статью:
https://www.c-sharpcorner.com/article/httpclientfactory-vs-httpclient-to-implement-api-calls/
https://medium.com/c-sharp-progarmming/socket-exhaustion-problem-in-net-and-how-to-solve-it-92a186ddc628#:~:text=This is known as socket,major disruption to your service.
В статье целый параграф под это выделен. И в современном .NET можно пользоваться синглтоном безопасно: https://learn.microsoft.com/en-us/dotnet/fundamentals/networking/http/httpclient-guidelines#recommended-use
про вызов Dispose у HttpClient'а в самом начале статьи рассказывается после предыстории, а также далее есть ссылка на другую статью, из которой приводится выдержка в том числе и про утечку соединений. эта проблема подсвечена первой, просто без подробных примеров с кодом.
что касается использования статического экземпляра то субъективно предпочтительнее использовать IHttpClientFactory, но тем не менее это рабочий вариант, который в том числе рекомендует Майкрософт. Только надо помнить про DNS TTL и добавить в конструкторе SocketsHttpHandler с настройкой PooledConnectionLifetime.
Вечно теряюсь - сокет же открыт только с конкретным сайтом\сервером?
Т.е. рекомендация держать один httpClient - она про конкретное соединение с конкретным сервером и всё?
Условно, если речь о приложении, которое обращается к разным сайтам и с разными настройками (разные логины+пароли или прокси например), то для каждого сайта лучше всё таки иметь отдельный httpClient?
Да, иногда проще зарегистрировать сразу именованного http-клиента со всеми настройками, а потом просто инжектить куда надо.
builder.Services.AddHttpClient<FakeAPISender>((provider, client) => {
client.BaseAddress = new Uri("http://fake");
var auth = $"fake:fake";
var enc = Convert.ToBase64String(Encoding.UTF8.GetBytes(auth));
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", enc);
}).SetHandlerLifetime(TimeSpan.FromMinutes(5));
public class FakeAPISender
{
private readonly HttpClient _httpClient;
public FakeAPISender(HttpClient httpClient)
{
_httpClient = httpClient ?? throw new ArgumentNullException(nameof(httpClient));
}
public async Task<DataResponse> GetData()
{
var result = await _httpClient.GetAsync(_httpClient.BaseAddress?.ToString());
.....
}
}
если приложение обращается к разным сервисам с разными настройками, то лучше зарегистрировать под каждый такой сервис свой типизированный или сгенерированный клиент со своими настройками и через фабрику получать их. то есть ответ на ваш вопрос - да, будут отдельные клиенты. держать один httpCLient не означает что он во всем приложении должен быть одним единственным на всё и сразу, тут про то, что его стоит переиспользовать а не пересоздавать
Насколько я знаю, в современной реализации HttpClient
код типа:
using(var client = new HttpClient())
{
....
}
вполне нормален и ничего плохого не сделает. Другое дело, что использовать new
вместо DI это само по себе моветон.
Но вот за такое:
var res = client.SendAsync(req).Result;
действительно надо руки отрывать.
Ваши знания устарели, как раз такой код и приведёт к исчерпани лимита сокетов при высокой нагрузке
Хм... Поковырялся в исходниках и доках - вы действительно правы, а я ошибался. Они опять там поменяли. Этот несчастный HttpClient
каждую версию переделывают. С другой стороны, лично мне все равно никогда бы не пришло в голову использовать HttpClient
без DI, так что впросак с этим я бы все равно не попал.
конструкция using это же синтаксический сахар, так что в любой реализации (до сегодняшнего дня) код типа using(var client = new HttpClient()) не "нормален" для HttpClient'а =)
"В мире .NET есть два популярных nuget-пакета для работы с HTTP. Это RestSharp и Flurl.Http."
а как же Refit?
Так это тоже обёртка над HttpClient.
да, Refit отличная библиотека. как раз удобно для создания API клиентов для сервисов использовать:
https://learn.microsoft.com/ru-ru/aspnet/core/fundamentals/http-requests?view=aspnetcore-8.0#generated-clients
RestSharp как минималистичная альтернатива использованию HttpClient'а (но под капотом используется HttpClient все равно)
А почему бы вместо HttpClient не использовать библиотеку Refit, которая берет формирование, выполнение запросов, сериализацию и десериализацию данных на себя? Конфигурируешь httpclient как тебе надо через фабрику и дергаешь нужные методы
Как стоит и как не стоит использовать HttpClient в .NET