110

So let's say I have a singleton class instance that I register in the DI like this:

services.AddSingleton<IFoo, Foo>();

And let's say the Foo class has a number of other dependencies (mostly repository classes that allow it to load data).

With my current understanding, the Foo instance is not created until it's first used (asked). Is there a way to initialize this class other than the constructor? Like right after ConfigureServices() completes? Or should the initialization code (loading data from db) be done in Foo's constructor?

(It would be nice if this class could load its data before the first use to speed up first time access)

2
  • 1
    You can create new Foo() and register it in ConfigureServices method. Commented Aug 17, 2016 at 20:49
  • 4
    @ademcaglin That won't work; since Foo has dependencies, it won't have a default constructor. Commented Mar 6, 2020 at 19:23

6 Answers 6

147

Do it yourself during startup.

var foo = new Foo();
services.AddSingleton<IFoo>(foo);

Or "warm it up"

public void Configure(IApplicationBuilder app) 
{
    app.ApplicationServices.GetService<IFoo>();
}

or alternatively

public void Configure(IApplicationBuilder app, IFoo foo) 
{
    ...
}

But this feels just dirty and is more a problem with your design, if you do something that you shouldn't in the constructor. Class instantiation has to be fast and if you do long-running operations within it, you break against a bunch of best practices and need to refactor your code base rather than looking for ways to hack around it

Sign up to request clarification or add additional context in comments.

13 Comments

But then I'd have to worry about all of Foo's dependencies (all the repositories and their dependencies). Definitely doable, but looking for a way that doesn't fight the system.
Yes. You usually only initialize classes that need special treatment, like starting a service bus connection etc. that you don't want happen during bootup time. We'd need more information though what exactly you try. I suspect you do some long running operation in the constructor which is an absolute no go. Class instantiation should be fast and long running operation NEVER done in constructor. Of course you can also resolve the class in Configure once, but that just feels "dirty"
for me it was public void Configure(IApplicationBuilder app) { app.ApplicationServices.GetService<IFoo>(); } (IFoo instead of Foo)
What if your singleton service needs to read data from a file or load data from a database and act as cache of that data? It doesn't seem right to do it during the first request (when the service is asked for) but to me this seems like a common situation. Moreover those operations are potentially dangerous and can throw exceptions which you would want to catch, log etc. what is the best practice for doing this if instantiating service yourself or "warming up" feels dirty?
@tseng I ended up with the following in Startup class: var rabbitMqManager = app.ApplicationServices.GetService<IRabbitMqManager>(); var rabbitMqReceiver = app.ApplicationServices.GetService<IRabbitMqReceiver>(); rabbitMqManager.Subscribe(rabbitMqReceiver);
|
9

Lately I've been creating it as an IHostedService if it needs initialization, because to me it seems more logical to let the initialization be handled by the service itself rather than outside of it.

You can even use a BackgroundService instead of IHostedService as it's pretty similar and it only needs the implementation of ExecuteAsync

Here's the documentation for them
https://learn.microsoft.com/en-us/aspnet/core/fundamentals/host/hosted-services

An example of how to add the service so you can inject it directly:

services
    .AddHostedService<MyService>()
    .AddSingleton<MyService>(x => x
        .GetServices<IHostedService>()
        .OfType<MyService>()
        .First());

Example of a simple service:

public class MyService : IHostedService
{
    // This function will be called automatically when the host `starts`
    public async Task StartAsync(CancellationToken cancellationToken)
    {
        // Do initialization logic
    }

    // This function will be called automatically when the host `stops`
    public Task StopAsync(CancellationToken cancellationToken)
    {
        // Do cleanup if needed

        return Task.CompletedTask;
    }
}

Some extension methods I created later on because i needed to use the same pattern again

public static class HostedServiceExtensions
{
    public static IServiceCollection AddHostedServiceAsService<T>(this IServiceCollection services) where T : class, IHostedService
        => services.AddHostedService<T>().AddSingleton(x => x.GetServices<IHostedService>().OfType<T>().First());

    public static IServiceCollection AddHostedServiceAsService<T>(this IServiceCollection services, Func<IServiceProvider, T> factory) where T : class, IHostedService
        => services.AddHostedService(factory).AddSingleton(x => x.GetServices<IHostedService>().OfType<T>().First());
}

Used like

services.AddHostedServiceAsService<MyService>();

// Or like this if you need a factory
services.AddHostedServiceAsService<MyService>(x => new MyService());

4 Comments

WARNING: the above will result in infinite recursion during startup. The way to do it is to register as a singleton first, then as a hosted service supplied with a factory, like: services.AddSingleton<IMyHostedService, MyHostedService>().AddHostedService(x => x.GetRequiredService<IMyHostedService>());
@Jez No it won't, it's tested and works as intended. For all I know without you providing any context is that you're the one introducing the infinite recursion, please check your code again.
I literally tried your code and got infinite recursion until I reversed the registration of the singleton and then the hosted service.
@Jez Infinite recursion don't just happen on their own, they only happen when services depend on each other, this this here is a service that depends on nothing which means this can't just create an infinite recursion.
8

This is an old discussion. But in 2024 I think this is the way to go :

https://learn.microsoft.com/en-us/dotnet/api/microsoft.extensions.dependencyinjection.autoactivationextensions?view=net-8.0

official nuget : https://www.nuget.org/packages/Microsoft.Extensions.DependencyInjection.AutoActivation

you can activate your service like this :

builder.Services.AddSingleton<x>();
builder.Services.ActivateSingleton<x>();

2 Comments

ActivateSingleton creates a fake Hosted Service and invokes ` _ = _provider.GetRequiredService(singleton);` I would double think if I want to pull a Nuget dependency just for this.
I'll leave it up to the reader to decide on whether to bring this in as a NuGet dependency or not, but for those interested in the source code for this package, it's here: github.com/dotnet/extensions/tree/main/src/Libraries/…
7

Adding detail to Jérôme FLAMEN's answer, as it provided the key I required to calling an async Initialization task to a singleton:

Create a class that implements IHostedService:

public class PostStartup : IHostedService
{
   private readonly YourSingleton yourSingleton;

   public PostStartup(YourSingleton _yourSingleton)
   {
       yourSingleton = _yourSingleton;
   }

   // you may wish to make use of the cancellationToken
   public async Task StartAsync(CancellationToken cancellationToken)
   {
      await yourSingleton.Initialize();
   }

   // implement as you see fit
   public Task StopAsync(CancellationToken cancellationToken) => Task.CompletedTask;
}

Then, in your ConfigureServices, add a HostedService reference:

services.AddHostedService<PostStartup>();

From link.

Comments

6

I got the same problem and I find Andrew Lock blog: https://andrewlock.net/running-async-tasks-on-app-startup-in-asp-net-core-3/

He explains how to do this with asp .net core 3, but he also refers to his pages on how to to this with previous version.

2 Comments

Hi Jérôme FLAMEN, welcome. Please consider adding more information because if the link becomes obsolete, then you have a very low quality answer.
Thanks for the article reference, but in my Main method, my WebHost is being initialized this way: CreateWebHostBuilder(args).Build().Run(). So, I'm calling the Run method instead of the StartAsync method. I don't think calling an async method instead of a sync one is a problem (as I can just capture the resulting Task and wait on it), but is there a difference between calling Run and Start?
0

I made some manager and I need to subscribe to events of the other services. I didn't like doing this in the

webBuilder.Configure (applicationBuilder => ...

I think it should be in the section

webBuilder.ConfigureServices ((context, services) => ...

So, here is my answer (test on net.core 3):

public static IHostBuilder CreateHostBuilder (string [] args) =>
    Host.CreateDefaultBuilder (args)
        .ConfigureWebHostDefaults (webBuilder =>
        {

        ...

        services.AddSingleton<ISomeSingletonService,SomeSingletonService>();

        var buildServiceProvider = services.BuildServiceProvider();
        var someSingletonService = buildServiceProvider.GetRequiredService <ISomeSingletonService>();

        ...
        });
  

1 Comment

And i think this is not the solution because the singleton might be instanciated multiple times. when it will also be injected to a controller-function for example.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.