Is there a way in ASP.NET to get all singletons?
I want to implement a health check which would instantiate all the registered singletons and only after that return a healthy status.
I am trying to get all the singletons from the IServiceProvider, but it seems to have only one method, i.e. the object? GetService(Type serviceType);.
So, maybe someone knows a way in C# to get all singletons?
I am trying to do like so:
_servicesProvider
  .GetServices<object>()
  .Where(service => _servicesProvider.GetService(service.GetType()) == service)
But it seems to also give me back scoped services.
Seems like this:
_servicesProvider
  .GetServices<object>()
  .ToList();
return new HealthCheckResult(HealthStatus.Healthy);
should work. But I am still hoping for a more optimal solution.
I don't believe there is a built in way to do this.
This answer to a similar question agrees, and suggest reflection as a possible solution.
Another option is to register your ServiceCollection with itself via .AddSingleton<IServiceCollection>(serviceCollection). You can then inject this or request it from the IServiceProvider and query it to get all the service descriptions with singleton lifetime:
var serviceCollection = serviceProvider.GetRequiredService<IServiceCollection>();
var singletons = serviceCollection
    .Where(descriptor => descriptor.Lifetime == ServiceLifetime.Singleton)
    .Select(descriptor => serviceProvider.GetRequiredService(descriptor.ServiceType))
    .ToList();
foreach(object singleton in singletons)
{
    // do something with the singleton
}
Depending on your use case it may be better to make your own implemention with a reduced interface, rather than exposing all of IServiceCollection to the consumer of the DI container.
@DisplayName already gave an answer that might work as a starting point. Here is a different solution:
IEnumerable<object> singletons = (
    from service in services
    group service by service.ServiceType into g
    where g.Any(descriptor => descriptor.Lifetime == ServiceLifetime.Singleton)
    from pair in serviceProvider.GetServices(g.Key).Zip(g)
    where pair.Second.Lifetime == ServiceLifetime.Singleton
    select pair.First)
    .Distinct();
Compared to @DisplayName's answer, this solution will retrieve all registered singletons, even those that are part of a collection. This solution, however, exhibits a few unfortunate downsides that might not exist in @DisplayName's answer:
Pick the solution that works best for your situation.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With