Какие типы, реализующие IDisposable, рекомендуется создавать один раз на весь жизненный цикл приложения?
Что проверяют
Знаете ли вы, что IDisposable не всегда значит «создай, используй, выброси через using»: часть типов дорого создавать, и держать их правильно одним экземпляром. Следом спрашивают, почему именно HttpClient и что происходит у синглтона при смене DNS.
Как отвечать
Сначала критерий: объект долго инициализируется, держит пул соединений и потокобезопасен. Такие типы создают один раз и регистрируют в DI как singleton:
HttpClient: создание на каждый запрос сusingоставляет сокеты вTIME_WAITи под нагрузкой исчерпывает порты. Правильно либо один экземпляр сSocketsHttpHandlerи заданнымPooledConnectionLifetime, чтобы соединения пересоздавались и подхватывали новые DNS-записи, либоIHttpClientFactoryчерезAddHttpClient, который сам управляет временем жизни обработчиков;- клиенты баз и брокеров:
CosmosClient,ConnectionMultiplexerиз StackExchange.Redis, продюсер Kafka. Их документация прямо рекомендует один экземпляр на приложение; MemoryCache: один кеш на процесс, обычно черезAddMemoryCache;- телеметрия:
ActivitySourceиMeterобычно живут в статическом поле.
Важная деталь: синглтоны, созданные контейнером, контейнер сам освободит через Dispose при остановке приложения. Вручную их не освобождают, иначе остальной код получит ObjectDisposedException.
Назовите и обратный список. SqlConnection открывают и закрывают на каждую операцию, а физические соединения переиспользует пул ADO.NET. DbContext не потокобезопасен и живёт в scope запроса.
Где спотыкаются
Советуют держать одно SqlConnection на всё приложение, «чтобы не пересоздавать». Эту задачу уже решает пул, а общее соединение ломается на параллельных запросах и после первого обрыва сети.
Считают ILogger одноразовым ресурсом. Он не реализует IDisposable, освобождается ILoggerFactory вместе с провайдерами, и этим тоже занимается контейнер.
Внедряют scoped-сервис вроде DbContext в синглтон. Получается пленённая зависимость: один контекст на всё время работы, с гонками и устаревшими данными. В режиме разработки контейнер ловит такое проверкой ValidateScopes.