I am now using .NET 6 Worker Service to develop an backend service, and I have multi background services need to be registered by AddHostedService<> like:
var host = Host.CreateDefaultBuilder(args)
.ConfigureServices(services =>
{
services.AddHostedService<WorkerA>();
services.AddHostedService<WorkerB>();
services.AddHostedService<WorkerC>();
})
.Build();
await host.RunAsync();
I want to find a better way to register background services dynamically, for example:
var workers = Assembly.GetExecutingAssembly().GetTypes()
.Where(worker =>
worker is {IsClass: true, IsAbstract: false} &&
!string.IsNullOrWhiteSpace(worker.Namespace) &&
worker.Namespace.Equals(typeof(BaseWorker).Namespace))
.ToArray();
foreach (var worker in workers)
{
// Incorrect here
services.AddHostedService<worker>();
}
However I failed since the worker is a Type not a class name. Could someone give me some instructions, thank you.
It is possible. You need to make a generic method for each type and call it. First get the open generic method:
var method =
// for the static extensions class where AddHostedService is defined
typeof(ServiceCollectionHostedServiceExtensions)
// get the AddHostedService<>() method
.GetMethod(
"AddHostedService",
// that has one generic argument
1,
// that is static and public
BindingFlags.Static | BindingFlags.Public,
// using the default binder
null,
// that takes one IServiceCollection as a parameter
new Type[] { typeof(IServiceCollection },
null));
Then change your foreach
such that it creates a closed generic version of the method with MakeGenericMethod, and invokes it.
foreach (var worker in workers)
{
// if worker is a MyWorker, then the below code is
// equivalent to services.AddHostedService<MyWorker>()
method
.MakeGenericMethod(new Type[] { worker })
.Invoke(null, new object?[] { services });
}
This allows you to call the ServiceCollectionHostedServiceExtensions.AddHostedService method via reflection.