Reputation: 21
We have an API project in.net core and one library project in the .net core where we define the background process (Background services using IHosted Service).
In the API project, we register the dependencies of our background services as:
services.AddHostedService<MyBackgroundProcess>();
and we have some other scope, transient, and singleton dependencies, as:
services.AddScoped<IHttpClientService , HttpClientService>();
services.AddScoped<IUserService, UserService>();
services.AddTransient<IMyTransientService, MyTransientService>();
services.AddScoped<IMyScopeService, MyScopeService>();
In our background service project, in the constructor, we inject some of the scoped and transient dependencies as (for example):
public MyBackgroundProcess(IHttpClientService iHttpClientService, IUserService iUserService, IMyTransientService iMyTransientServcie, IMyScopeService iMyScopeService)
{
_iHttpClientService = iHttpClientService;
_iUserService = iUserService;
_iMyTransientServcie = iMyTransientServcie;
_iMyScopeService = iMyScopeService;
}
I was able to resolve these scoped dependencies in .net core 2.2. I am getting all those values from my API project. The background process constructor is being called when I call my background service from the API project. So I was getting all the updated dependencies.
The problem came when I migrated the projects to .net core 3.1. Now my dependencies are coming as null. These are not synced with my API project from where I invoke these background services. We are using .net core inbuild DI. The constructor of IHostedService/Background services is being called while deploying the application to service fabric, it does not get called on calling background process from API.
My API Business Logic constructor is like:
public MyAPIManager(IMyTransientService myTransientService, IMyScopeService myScopedService, IHostedService myBackGroundProcess1,
IHostedService myBackgroundProcess2, IServiceProvider serviceProvider)
{
_myTransientService = myTransientService;
_myScopedService = myScopedService;
_myBackGroundService1 = myBackGroundService1 as MyBackgroundServiceA;
_myBackGroundService2 = myBackGroundService2 as MyBackgroundServiceB;
if (_myBackGroundService2 == null)
{
var services = serviceProvider.GetServices<IHostedService>();
_myBackGroundService2 = services.First(o => o.GetType() == typeof(MyBackgroundServiceB)) as MyBackgroundServiceB;
}
}
Here I am injecting, scoped, and transient dependencies and 2 background services. Whenever I get the instances of IHostedService from "serviceProvider.GetServices()", in .net core 2.2, it calls the constructor of all the IHosted services registered in my DI, but in .net core 3.1 it does not call the constructor of background services.
UPDATE--
I tried register my background services, as Transient instead of AddHostedService as below:
services.AddTransient<IHostedService, MyBackgroundService1>();
services.AddTransient<IHostedService, MyBackgroundService2>();
Seems it is working now, it calls the constructor every time I tried to resolve the type:
var services = serviceProvider.GetServices<IHostedService>();
_myBackgroundProcess1 = services.First(o => o.GetType() == typeof(MyBackgroundProcessA)) as MyBackgroundProcessA;
Is it advisable to register IHostedService like this? Will there be any impact?
Upvotes: 2
Views: 4158
Reputation: 27874
Schoooo Wheeeeee.
Looks like you ran into a small-holy-war.
Here is link and discussion:
https://github.com/dotnet/extensions/issues/553
"AddHostedService should not be a singleton. Please don't make this breaking change,"
"This thread is extremely strange. HostedServices should be singletons not transient."
This seems to be the key comment in your case:
"Because it's a helper for what we expect is the most common scenario. If that doesn't suit you then use the DI methods directly."
PREVIOUS RESPONSE:
As per this example:
services.AddHostedService<ConsumeScopedServiceHostedService>();
services.AddScoped<IScopedProcessingService, ScopedProcessingService>();
(code above from the example)
You have to register your dependencies
services.AddHostedService<MyBackgroundProcess>();
services.AddScoped<IHttpClientService , MyConcreteHttpClientService>();
services.AddScoped<IUserService, MyConcreteUserService>();
services.AddScoped<IMyTransientService, MyConcreteMyTransientService>();
services.AddScoped<IMyScopeService, MyConcreteScopeService>();
This (the above) is .. of course... if you are not using some kind of "autoscan" solution. (Did you have kind of autoscan solution in your 2.2 code maybe??)
something like
NetCore.AutoRegisterDi
https://www.thereformedprogrammer.net/asp-net-core-fast-and-automatic-dependency-injection-setup/
public static class NetCoreDiSetupExtensions
{
public static void RegisterServiceLayerDi
(this IServiceCollection services)
{
services.RegisterAssemblyPublicNonGenericClasses()
.AsPublicImplementedInterfaces();
//put any non-standard DI registration, e.g. generic types, here
}
}
Another link:
Ultimately, I think this is the issue:
Upvotes: 0