在DotNetCore 3.1 Worker Service中使用自定义DI提供程序



有人知道如何在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

最新更新