Использование IHttpClientFactory для управления жизненным циклом HttpClientHandler¶
Начнём с того, что класс HttpClient отвечает за оркестровку запросов, но не за само соединение. Вместо этого он вызывает конвейер HttpMessageHandler, в конце которого находится HttpClientHandler, который устанавливает фактическое соединение и отправляет HTTP-запрос, как показано на картинке.

Эта конфигурация напоминает конвейер промежуточного ПО, хоть это и исходящий конвейер. Каждый обработчик может изменить запрос до того, как последний HttpClientHandler выполнит настоящий запрос, а также получает возможность посмотреть ответ после получения.
Проблемы исчерпания сокетов и ротации DNS связаны с удалением HttpClientHandler в конце конвейера. По умолчанию удаление HttpClient удаляет и весь конвейер обработчиков; IHttpClientFactory отделяет жизенный цикл HttpClient от базового HttpClientHandler.
Такое разделение жизненного цикла позволяет решать проблемы сокетов и DNS двумя способами:
- путём создания пула доступных обработчиков —
IHttpClientFactoryподдерживает активный обработчик, который используется при создании всехHttpClientв течении двух минут, при этом при удаленииHttpClientбазовый обработчик не удаляется, тем самым соединение не закрывается; - периодически удаляя обработчики — каждые две минуты
IHttpClientFactoryсоздаёт новый активный обработчик, который используется для создания новыхHttpClient.
Также IHttpClientFactory периодически удаляет обработчики с “истекшим сроком действия”, если они больще не используются HttpClient, обеспечивая использование ограниченного количества подключений1.
IHttpClientFactory по умолчанию включён в сервисы ASP.NET Core; нужно добавить его в сервисы приложения:
Теперь мы можем получить объект IHttpClientFactory через внедрение зависимостей:
[ApiController]
public class ValuesController : ControllerBase
{
private readonly IHttpClientFactory _factory;
public ValuesController(IHttpClientFactory factory)
{
_factory = factory;
}
[HttpGet("values")]
public async Task<string> GetRates()
{
HttpClient client = _factory.CreateClient();
client.BaseAddress = new Uri("https://api.exchangeratesapi.io");
client.DefaultRequestHeaders
.Add(HeaderNames.UserAgent, "ExchangeRateViewer");
var response = await client.GetAsync("latest");
response.EnsureSuccessStatusCode();
return await response.Content.ReadAsStringAsync();
}
}
SocketsHttpHandler и IHttpClientFactory
Ограничения HttpClient, описанные в предыдущем разделе, применяются именно к HttpClientHandler. IHttpClientFactory управляет жизненным циклом и повторным использованием HttpClientHandler.
В .NET Core 2.1 была представлена замена HttpClientHandler — SocketsHttpHandler, в первую очередь нацеленная на повышение производительности и согласованности между платформами. Также SocketsHttpHandler можно настроить для использования пула соединений и повторного использования.
Несмотря на то, что использование IHttpClientFactory по прежнему предпочтительно, в сценарии, где нет внедрения зависимостей и где нельзя использовать IHttpClientFactory, можно активировать пул соединений SocketsHttpHandler, как описано здесь
-
Подробнее об этом в блоге автора ↩
Дата создания : 30 октября 2022 г.