ASP.NET 核心工作者服务中的依赖注入
Dependency Injection in ASP.NET Core Worker Service
我在 .NET Core 辅助角色服务中遇到了一些依赖注入问题。
请参阅 Program.cs
文件中的以下代码。
public static void Main(string[] args)
{
Log.Logger = new LoggerConfiguration()
.MinimumLevel.Debug()
.MinimumLevel.Override("Microsof)t", LogEventLevel.Warning)
.Enrich.FromLogContext()
.WriteTo.File(@"C:\MyApp_Log\Log.txt")
.CreateLogger();
try
{
Log.Information("Starting up the service.");
CreateHostBuilder(args).Build().Run();
return;
}
catch (Exception ex)
{
Log.Fatal(ex, "There was a problem starting the service");
return;
}
finally
{
Log.CloseAndFlush();
}
}
public static IHostBuilder CreateHostBuilder(string[] args)
{
return Host.CreateDefaultBuilder(args)
.UseWindowsService()
.ConfigureServices((hostContext, services) =>
{
services.AddScoped<IMyAppCoreService, MyAppCoreService>();
services.AddDbContext<MyAppCSContext>(options => options.UseSqlServer("Data Source=xx.xxx.xx.xxx;Database=Mydb;User ID = sa;Password=mypassword"));
services.AddHostedService<Worker>();
})
.UseSerilog();
}
请参阅下面的 Worker.cs
文件代码
private readonly ILogger<Worker> _logger;
private readonly IMyAppCoreService _CoreService;
public Worker(ILogger<Worker> logger, IMyAppCoreService CoreService)
{
_logger = logger;
_CoreService = CoreService;
}
public override Task StartAsync(CancellationToken cancellationToken)
{
_logger.LogInformation("The MyApp_CoreService has been Started...");
return base.StartAsync(cancellationToken);
}
public override Task StopAsync(CancellationToken cancellationToken)
{
_logger.LogInformation("The MyApp_CoreService has been stopped...");
return base.StopAsync(cancellationToken);
}
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
while (!stoppingToken.IsCancellationRequested)
{
_logger.LogInformation("Worker running at: {time}", DateTimeOffset.Now);
_CoreService.CheckAndProcessResult();
await Task.Delay(1000, stoppingToken);
}
}
当我运行上面的查询时,我得到了下面的查询。
验证服务描述符时出错
ServiceType: MyApp.CS.Business.Facade.IMyAppCoreService Lifetime: Scoped ImplementationType: MyApp.CS.Business.Services.MyAppCoreService': Unable to resolve service for type 'MyApp.CS.Data.Facade.ICommonRepository' while attempting to activate 'MyApp.CS.Business.Services.MyAppCoreService'.
你能告诉我哪里做错了吗?
编辑: 在我用 class 注册所有接口之后。然后我得到如下新错误。
Error while validating the service descriptor 'ServiceType: Microsoft.Extensions.Hosting.IHostedService Lifetime: Singleton ImplementationType: MyApp_CoreService.Worker': Cannot consume scoped service 'MyApp.CS.Business.Facade.IMyAppCoreService' from singleton 'Microsoft.Extensions.Hosting.IHostedService'.
您将 Serivce IMyAppCoreService
作为 Scoped 注入。范围服务只能由 ScopedServiceProvider
.
解决
我的第一个猜测是你不是故意的 - 你打算将你的服务作为单例注入:
services.AddSingleton<IMyAppCoreService, MyAppCoreService>();
然而,这可能不起作用,因为您使用的是 EF Core,它将其类似上下文的 classes 作为作用域注入。您有两个选择:
- 让 EF Core 将其上下文 class 作为瞬态注入。我不建议这样做,因为您将负责处理它。如果你想完成它,这是怎么做的 (Startup.cs / Program.cs):
services.AddDbContext<YourContext>(opts => { ...config...}, ServiceLifetime.Transient);
- 手动创建范围:
将名为 ServiceProvider 的 IServiceProvider
属性 注入 Worker
而不是 您的服务。
在 ExecuteAsync 循环中:
_logger.LogInformation("Worker running at: {time}", DateTimeOffset.Now);
using (var scope = ServiceProvider.CreateScope())
{
scope.ServiceProvider.GetRequiredService<IMyAppCoreService>().CheckAndProcessResult();
}
await Task.Delay(1000, stoppingToken);
这将巧妙地处理每个 Loop 的 EFCore-Data 上下文对象,在我看来是最干净的选择。
依赖注入:
services.AddScoped<IMyAppCoreService, MyAppCoreService>();
services.AddDbContext<MyAppCSContext>(options => options.UseSqlServer("Data Source=xx.xxx.xx.xxx;Database=Mydb;User ID = sa;Password=mypassword"), ServiceLifetime.Scoped);
工人class:
public class Worker : BackgroundService
{
IServiceProvider _serviceProvider;
public Worker(IServiceProvider serviceProvider)
{
_serviceProvider = serviceProvider;
}
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
using (var scope = _serviceProvider.CreateScope())
{
scope.ServiceProvider.GetRequiredService<IMyAppCoreService>().CheckAndProcessResult();
}
await Task.Delay(1000, stoppingToken);
}
}
我在 .NET Core 辅助角色服务中遇到了一些依赖注入问题。
请参阅 Program.cs
文件中的以下代码。
public static void Main(string[] args)
{
Log.Logger = new LoggerConfiguration()
.MinimumLevel.Debug()
.MinimumLevel.Override("Microsof)t", LogEventLevel.Warning)
.Enrich.FromLogContext()
.WriteTo.File(@"C:\MyApp_Log\Log.txt")
.CreateLogger();
try
{
Log.Information("Starting up the service.");
CreateHostBuilder(args).Build().Run();
return;
}
catch (Exception ex)
{
Log.Fatal(ex, "There was a problem starting the service");
return;
}
finally
{
Log.CloseAndFlush();
}
}
public static IHostBuilder CreateHostBuilder(string[] args)
{
return Host.CreateDefaultBuilder(args)
.UseWindowsService()
.ConfigureServices((hostContext, services) =>
{
services.AddScoped<IMyAppCoreService, MyAppCoreService>();
services.AddDbContext<MyAppCSContext>(options => options.UseSqlServer("Data Source=xx.xxx.xx.xxx;Database=Mydb;User ID = sa;Password=mypassword"));
services.AddHostedService<Worker>();
})
.UseSerilog();
}
请参阅下面的 Worker.cs
文件代码
private readonly ILogger<Worker> _logger;
private readonly IMyAppCoreService _CoreService;
public Worker(ILogger<Worker> logger, IMyAppCoreService CoreService)
{
_logger = logger;
_CoreService = CoreService;
}
public override Task StartAsync(CancellationToken cancellationToken)
{
_logger.LogInformation("The MyApp_CoreService has been Started...");
return base.StartAsync(cancellationToken);
}
public override Task StopAsync(CancellationToken cancellationToken)
{
_logger.LogInformation("The MyApp_CoreService has been stopped...");
return base.StopAsync(cancellationToken);
}
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
while (!stoppingToken.IsCancellationRequested)
{
_logger.LogInformation("Worker running at: {time}", DateTimeOffset.Now);
_CoreService.CheckAndProcessResult();
await Task.Delay(1000, stoppingToken);
}
}
当我运行上面的查询时,我得到了下面的查询。
验证服务描述符时出错
ServiceType: MyApp.CS.Business.Facade.IMyAppCoreService Lifetime: Scoped ImplementationType: MyApp.CS.Business.Services.MyAppCoreService': Unable to resolve service for type 'MyApp.CS.Data.Facade.ICommonRepository' while attempting to activate 'MyApp.CS.Business.Services.MyAppCoreService'.
你能告诉我哪里做错了吗?
编辑: 在我用 class 注册所有接口之后。然后我得到如下新错误。
Error while validating the service descriptor 'ServiceType: Microsoft.Extensions.Hosting.IHostedService Lifetime: Singleton ImplementationType: MyApp_CoreService.Worker': Cannot consume scoped service 'MyApp.CS.Business.Facade.IMyAppCoreService' from singleton 'Microsoft.Extensions.Hosting.IHostedService'.
您将 Serivce IMyAppCoreService
作为 Scoped 注入。范围服务只能由 ScopedServiceProvider
.
我的第一个猜测是你不是故意的 - 你打算将你的服务作为单例注入:
services.AddSingleton<IMyAppCoreService, MyAppCoreService>();
然而,这可能不起作用,因为您使用的是 EF Core,它将其类似上下文的 classes 作为作用域注入。您有两个选择:
- 让 EF Core 将其上下文 class 作为瞬态注入。我不建议这样做,因为您将负责处理它。如果你想完成它,这是怎么做的 (Startup.cs / Program.cs):
services.AddDbContext<YourContext>(opts => { ...config...}, ServiceLifetime.Transient);
- 手动创建范围:
将名为 ServiceProvider 的 IServiceProvider
属性 注入 Worker
而不是 您的服务。
在 ExecuteAsync 循环中:
_logger.LogInformation("Worker running at: {time}", DateTimeOffset.Now);
using (var scope = ServiceProvider.CreateScope())
{
scope.ServiceProvider.GetRequiredService<IMyAppCoreService>().CheckAndProcessResult();
}
await Task.Delay(1000, stoppingToken);
这将巧妙地处理每个 Loop 的 EFCore-Data 上下文对象,在我看来是最干净的选择。
依赖注入:
services.AddScoped<IMyAppCoreService, MyAppCoreService>();
services.AddDbContext<MyAppCSContext>(options => options.UseSqlServer("Data Source=xx.xxx.xx.xxx;Database=Mydb;User ID = sa;Password=mypassword"), ServiceLifetime.Scoped);
工人class:
public class Worker : BackgroundService
{
IServiceProvider _serviceProvider;
public Worker(IServiceProvider serviceProvider)
{
_serviceProvider = serviceProvider;
}
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
using (var scope = _serviceProvider.CreateScope())
{
scope.ServiceProvider.GetRequiredService<IMyAppCoreService>().CheckAndProcessResult();
}
await Task.Delay(1000, stoppingToken);
}
}