Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ASP.NET core call async init on singleton service

I have a service that asynchronously reads some content from a file in a method called InitAsync

public class MyService : IService {
    private readonly IDependency injectedDependency;

    public MyService(IDependency injectedDependency) {
        this.injectedDependency = injectedDependency;
    }

    public async Task InitAsync() {
        // async loading from file.
    }
}

Now this service is injected into my controller.

public class MyController : Controller {
    private readonly IService service;

    public MyController(IService service) {
        this.service = service;
    }
}

Now I want a singleton instance of MyService. And I want to call InitAsync in startup.

public class Startup {
    public void ConfigureServices(IServiceCollection services) {
        ......
        services.AddSingleton<IService, MyService>();
        var serviceProvider = services.BuildServiceProvider();
        // perform async init.
        serviceProvider.GetRequiredService<IService>().InitAsync();
    }
}

What is happening is at the time of startup, an instance of MyService is created and InitAsync() is called on it. Then when I called the controller class, another instance of MyService is created which is then reused for consequent calls.

What I need is to initialize only 1 instance, called InitAsync() on it in startup and have it be reused by controllers as well.

like image 321
user3740951 Avatar asked May 10 '19 12:05

user3740951


People also ask

Can Singleton be initialized asynchronously?

Another advantage of a Singleton class is that it can be initialized lazily or asynchronously.

What is IoC container in. NET Core?

ASP.NET Core contains a built-in dependency injection mechanism. In the Startup. cs file, there is a method called ConfigureServices which registers all application services in the IServiceCollection parameter. The collection is managed by the Microsoft.

What is IServiceProvider .NET Core?

The IServiceProvider is responsible for resolving instances of types at runtime, as required by the application. These instances can be injected into other services resolved from the same dependency injection container. The ServiceProvider ensures that resolved services live for the expected lifetime.

What is singleton service in .NET Core?

Singleton is a design pattern, It means that there will be a single copy of your object inside server memory, which will be shared among all the requests (http/client). So, when you register any dependency in your application as a Singleton, then you will get a single copy of an object per server/node/instance.


1 Answers

What is happening is at the time of startup, an instance of MyService is created and InitAsync() is called on it. Then when I called the controller class, another instance of MyService is created which is then reused for consequent calls.

When you call BuildServiceProvider(), you create a separate instance of IServiceProvider, which creates its own singleton instance of IService. The IServiceProvider that gets used when resolving the IService that's provided for MyController is different to the one you created yourself and so the IService itself is also different (and uninitialised).

What I need is to initialize only 1 instance, called InitAsync() on it in startup and have it be reused by controllers as well.

Rather than attempting to resolve and initialise IService inside of Startup.ConfigureServices, you can do so in Program.Main. This allows for two things:

  1. Using the same instance of IService for initialisation and later use.
  2. awaiting the call to InitAsync, which is currently fire-and-forget in the approach you've shown.

Here's an example of how Program.Main might look:

public static async Task Main(string[] args)
{
    var webHost = CreateWebHostBuilder(args).Build();

    await webHost.Services.GetRequiredService<IService>().InitAsync();

    webHost.Run();
    // await webHost.RunAsync();
}

This uses async Main to enable use of await, builds the IWebHost and uses its IServiceProvider to resolve and initialise IService. The code also shows how you can use await with RunAsync if you prefer, now that the method is async.

like image 109
Kirk Larkin Avatar answered Oct 09 '22 17:10

Kirk Larkin