Когда активируется singleton в DI контейнере и можно ли сделать его предварительную инициализацию
Что проверяют
Знаете ли вы, как встроенный контейнер Microsoft.Extensions.DependencyInjection управляет временем жизни, и отличаете ли регистрацию от создания. Следом спрашивают про асинхронную инициализацию и про singleton, который зависит от scoped-сервиса.
Как отвечать
Регистрация через AddSingleton<TService, TImpl>() или фабрику AddSingleton(sp => ...) ничего не создаёт. Экземпляр появляется лениво, при первом разрешении: когда его запросили через GetRequiredService или когда контейнер собирает сервис, который от него зависит. Дальше контейнер отдаёт тот же объект до конца жизни корневого ServiceProvider и вызывает у него Dispose при остановке приложения. Потокобезопасность методов самого сервиса остаётся на вас.
Способы создать его заранее:
- разрешить после сборки:
var app = builder.Build(); app.Services.GetRequiredService<Cache>();доapp.Run(); IHostedService: сервис, который получает singleton в конструктор и прогревает его вStartAsync. Это заодно решает асинхронную инициализацию, ведь конструктор асинхронным не бывает;- готовый экземпляр:
AddSingleton(new Cache()). Объект создан вами, поэтому контейнер его не освободит,Disposeпридётся вызвать самому; - сторонние контейнеры: в Autofac есть
AutoActivate()и интерфейсIStartable.
Стоит добавить, что ValidateOnBuild проверяет граф зависимостей при старте, но экземпляры не создаёт, так что прогревом не является.
Где спотыкаются
Вызывают services.BuildServiceProvider() посреди регистрации, чтобы достать сервис пораньше. Получается второй контейнер со своими копиями singleton, и анализатор предупреждает об этом кодом ASP0000.
Внедряют scoped-зависимость, например DbContext, в singleton. Она живёт вечно и делится между запросами. В окружении Development это ловит ValidateScopes, а в проде ошибка проявится уже на данных.
Уверенно говорят, что AddSingleton(new X()) и AddSingleton<X>() одно и то же. Разница в моменте создания и в том, кто отвечает за освобождение ресурсов.