ASP.NET Core Worker Service 中的依赖注入

Dil*_*mar 2 c# windows-services backgroundworker .net-core asp.net-core

我在 .NET Core Worker Service 中遇到了一些依赖注入问题。请参阅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();
}
Run Code Online (Sandbox Code Playgroud)

请参阅下面的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);
    }
}
Run Code Online (Sandbox Code Playgroud)

当我运行上面的查询时,我得到了下面的查询。

验证服务描述符时出错

ServiceType:MyApp.CS.Business.Facade.IMyAppCoreService Lifetime:Scoped ImplementationType:MyApp.CS.Business.Services.MyAppCoreService”:尝试激活“MyApp”时无法解析“MyApp.CS.Data.Facade.ICommonRepository”类型的服务.CS.Business.Services.MyAppCoreService'。

你能告诉我我哪里做错了吗?

编辑:在我用它的类注册所有接口之后。然后我得到如下新错误。

验证服务描述符“ServiceType: Microsoft.Extensions.Hosting.IHostedService Lifetime: Singleton ImplementationType: MyApp_CoreService.Worker”时出错:无法使用来自单例“Microsoft.Extensions.Hosting”的范围服务“MyApp.CS.Business.Facade.IMyAppCoreService”。 IHostedService'。

mon*_*omo 8

您将 SerivceIMyAppCoreService作为 Scoped注入。范围服务只能由ScopedServiceProvider.

我的第一个猜测是,您不是故意的 - 您打算将您的服务注入为单例:

services.AddSingleton<IMyAppCoreService, MyAppCoreService>();
Run Code Online (Sandbox Code Playgroud)

但是,这可能不起作用,因为您使用的是 EF Core,它将其 Context-like 类注入为作用域。您有两个选择:

  1. 让 EF Core 将其上下文类注入为瞬态。我不建议这样做,因为您将负责处理它。如果你想通过它,这是如何做到的(Startup.cs / Program.cs):
services.AddDbContext<YourContext>(opts => { ...config...}, ServiceLifetime.Transient);
Run Code Online (Sandbox Code Playgroud)
  1. 手动创建范围:

IServiceProvider名为 ServiceProvider的属性注入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);
Run Code Online (Sandbox Code Playgroud)

这将巧妙地处理每个循环的 EFCore-Data 上下文对象,在我看来是最干净的选择。

  • 当我写“using (varscope = ServiceProvider.CreateScope())”时,“CreateScope”丢失了。我正在使用.net Core 3.1。我使用过“using Microsoft.Extensions.DependencyInjection”。我们是否需要导入一些其他库。? (2认同)

小智 6

依赖注入:

 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);
Run Code Online (Sandbox Code Playgroud)

工人阶级:

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);
    }
}
Run Code Online (Sandbox Code Playgroud)

来源https://learn.microsoft.com/en-us/aspnet/core/fundamentals/host/hosted-services?view=aspnetcore-3.0&tabs=visual-studio#consuming-a-scoped-service-in-a-后台任务