在 DotNetCore 3.1 Worker Service 中使用自定义 DI 提供程序?
Use custom DI provider in DotNetCore 3.1 Worker Service?
有谁知道如何在 DotNetCore Worker Service 中设置自定义 DI 提供程序(例如 Castle Windsor)?我已经看到有关如何为 ASP.NET 应用程序执行此操作的信息,但所有示例都在谈论修改 Startup.cs,这在 Worker Service 模板中不存在。
在 .NET Core Worker 项目中使用自定义依赖注入容器
Castle Windsor 不支持最新的 .NET Core 版本,因此我将使用 Autofac 作为示例。
当您开始一个新的 worker
项目时,您将拥有一个这样的程序 class
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 assembly.
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-and-generic-hosting
- https://docs.microsoft.com/en-us/aspnet/core/fundamentals/host/generic-host?view=aspnetcore-5.0
- https://docs.microsoft.com/en-us/dotnet/api/microsoft.extensions.hosting.hostbuilder.useserviceproviderfactory?view=dotnet-plat-ext-5.0
有谁知道如何在 DotNetCore Worker Service 中设置自定义 DI 提供程序(例如 Castle Windsor)?我已经看到有关如何为 ASP.NET 应用程序执行此操作的信息,但所有示例都在谈论修改 Startup.cs,这在 Worker Service 模板中不存在。
在 .NET Core Worker 项目中使用自定义依赖注入容器
Castle Windsor 不支持最新的 .NET Core 版本,因此我将使用 Autofac 作为示例。
当您开始一个新的 worker
项目时,您将拥有一个这样的程序 class
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 assembly.
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-and-generic-hosting
- https://docs.microsoft.com/en-us/aspnet/core/fundamentals/host/generic-host?view=aspnetcore-5.0
- https://docs.microsoft.com/en-us/dotnet/api/microsoft.extensions.hosting.hostbuilder.useserviceproviderfactory?view=dotnet-plat-ext-5.0