Register multiple .Net Core IHostedService in Dependency Injection - Background service in .net core

Viewed 1453

I have a .Net core (v2.2) API. That API uses some external service calls. We want to make them as fire and forget calls. We used .net core Background service to implement that. We have multiple background services. Now if I register all those IHostedService in Dependency Injection, The last registered background service works, and others come as null in constructor injection of project. Registering dependencies like:

services.AddHostedService<BackgroundServiceA>();
 services.AddHostedService<BackgroundServiceB>();

And also, I tried adding them as:

 services.AddSingleton<IHostedService, BackgroundServiceA>();
 services.AddSingleton<IHostedService, BackgroundServiceB>();

In both the cases, only BackgroundServiceB works, BackgroundServiceA comes as null in constructor injection.

To handle this, I was using ServiceProvider to get the object.

  var services = serviceProvider.GetServices<IHostedService>();
 _backgroundServiceA = services.First(o => o.GetType() == typeof(BackgroundServiceA)) as BackgroundServiceA;

Is it a good way to handle such an issue or I am missing something while registering dependencies.

Also, can we trigger both the background calls parallel?

3 Answers

(edit, I initially answered the wrong question....)

Dependency injection doesn't work with multiple implementations of the same interface. Since each hosted service is registered as an implementation of IHostedService, only one service can be easily injected into other types.

However you can register each service again, with a factory method to locate the background singleton instance;

services.AddHostedService<BackgroundServiceA>();
services.AddHostedService<BackgroundServiceB>();
services.AddSingleton<BackgroundServiceA>(p => p.GetServices<IHostedService>().OfType<BackgroundServiceA>().Single());
services.AddSingleton<BackgroundServiceB>(p => p.GetServices<IHostedService>().OfType<BackgroundServiceB>().Single());

Edit: It's probably better to implement this the other way around;

services.AddSingleton<BackgroundServiceA>();
services.AddSingleton<IHostedService>(p => p.GetService<BackgroundServiceA>());

Try to register them via AddHostedService call in separate ConfigureServices call outside startup, as stated in docs:

public static void Main(string[] args) { CreateHostBuilder(args).Build().Run(); }

public static IHostBuilder CreateHostBuilder(string[] args) =>
    Host.CreateDefaultBuilder(args)
        .ConfigureWebHostDefaults(webBuilder =>
        {
            webBuilder.UseStartup<Startup>();
        })
        .ConfigureServices(services =>
        {
            services.AddHostedService<BackgroundServiceA>();
            services.AddHostedService<BackgroundServiceB>();
        });

avoid direct access to hosted service as discussed here

use intermediate service instead as describe in 'Queued background tasks' example

Related