有人知道如何在DotNetCore Worker Service中设置自定义DI提供程序(如Castle Windsor(吗?我看到了关于如何为ASP.NET应用程序执行此操作的信息,但所有的示例都谈到了修改Startup.cs,而Worker Service模板中不存在Startup.cs。
在.net core worker项目中使用自定义依赖项注入容器
Castle Windsor不支持最近的.NET Core版本,所以我将使用Autofac作为示例。
当你开始一个新的worker
项目时,你会有一个类似于的Program类
public class Program
{
public static void Main(string[] args)
{
CreateHostBuilder(args).Build().Run();
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureServices((hostContext, services) =>
{
services.AddHostedService<Worker>();
});
}
Host.CreateDefaultBuilder
为您提供了一个IHostBuilder
,它具有扩展或替换DI容器的必要方法。我们正在使用Autofac,所以让我们安装它:
dotnet add package Autofac.Extensions.DependencyInjection
然后把它介绍给我们的主人。此处ContainerBuilder
来自Autofac组件。
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
// use autofac
.UseServiceProviderFactory(new AutofacServiceProviderFactory())
// configure autofac di container
.ConfigureContainer<ContainerBuilder>((hostContext, container) =>
{
// hostcontext gives you access to config & environment
// hostContext.Configuration.GetSection("ApiKeys");
// hostContext.HostingEnvironment.IsDevelopment()
// auto register all classes in the assembly
container
.RegisterAssemblyTypes(typeof(Program).Assembly)
.AsImplementedInterfaces();
})
// configure microsoft di container
.ConfigureServices((hostContext, services) =>
{
// let autofac register this service
// services.AddHostedService<Worker>();
});
现在让我们创建一个服务。这里的IJob
接口是不必要的,它只是用来展示Autofac的功能:
internal interface IJob
{
Task ExecuteAsync(CancellationToken cancellationToken = default);
}
internal class WarmUpCaches : IJob
{
private readonly ILogger<WarmUpCaches> _logger;
public WarmUpCaches(ILogger<WarmUpCaches> logger)
{
_logger = logger;
}
public async Task ExecuteAsync(CancellationToken cancellationToken = default)
{
_logger.LogInformation("Warming up caches");
var steps = 5;
while (!cancellationToken.IsCancellationRequested && --steps > 0)
{
_logger.LogInformation("working...");
await Task.Delay(TimeSpan.FromSeconds(1), cancellationToken);
}
_logger.LogInformation("Done");
}
}
现在让我们在后台服务中使用此服务:
class Worker : BackgroundService
{
private readonly ILogger<Worker> _logger;
private readonly IJob _job;
public Worker(ILogger<Worker> logger, IJob job)
{
_logger = logger;
_job = job;
}
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
await _job.ExecuteAsync(stoppingToken);
}
}
当我们运行应用程序时,它会记录:
info: CustomDiExample.WarmUpCaches[0]
Warming up caches
info: CustomDiExample.WarmUpCaches[0]
working...
info: Microsoft.Hosting.Lifetime[0]
Application started. Press Ctrl+C to shut down.
info: Microsoft.Hosting.Lifetime[0]
Hosting environment: Development
info: Microsoft.Hosting.Lifetime[0]
Content root path: C:...CustomDiExample
info: CustomDiExample.WarmUpCaches[0]
working...
info: CustomDiExample.WarmUpCaches[0]
working...
info: CustomDiExample.WarmUpCaches[0]
working...
info: CustomDiExample.WarmUpCaches[0]
Done
在不使用后台服务的情况下使用服务
如果应用程序不需要继续工作,我们可以不使用BackgroundService
。
我们需要修改Main
方法并公开IHost
实例。我们可以使用IHost.Services
解析容器中的任何服务。
public static async Task Main(string[] args)
{
var host = CreateHostBuilder(args).Build();
// stop the application with Ctrl+C, SIGINT, SIGTERM
var lifetime = host.Services.GetRequiredService<IHostApplicationLifetime>();
var cancellationToken = lifetime.ApplicationStopping;
var job = host.Services.GetRequiredService<IJob>();
await job.ExecuteAsync(cancellationToken);
}
参考
- https://autofac.readthedocs.io/en/latest/integration/aspnetcore.html?highlight=AutofacServiceProviderFactory#asp-net-core-3-0和generic-hosting
- https://learn.microsoft.com/en-us/aspnet/core/fundamentals/host/generic-host?view=aspnetcore-5.0
- https://learn.microsoft.com/en-us/dotnet/api/microsoft.extensions.hosting.hostbuilder.useserviceproviderfactory?view=dotnet-平台-ext-5.0