简体   繁体   English

ASP.NET Core Worker 服务中的依赖注入

[英]Dependency Injection in ASP.NET Core Worker Service

I'm facing some dependency injection issues in .NET Core Worker Service.我在 .NET Core Worker Service 中遇到了一些依赖注入问题。 Please see the below code in Program.cs file.请参阅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();
}

And please see below code for Worker.cs file请参阅下面的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);
    }
}

When I run the above query, I got the below query.当我运行上面的查询时,我得到了下面的查询。

Error while validating the service descriptor验证服务描述符时出错

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

Can you please tell me where I was done wrong?你能告诉我我哪里做错了吗?

EDIT: After i register all the interface with its class.编辑:在我用它的 class 注册所有接口之后。 then i got new error as follows.然后我得到如下新错误。

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'.验证服务描述符“ServiceType:Microsoft.Extensions.Hosting.IHostedService Lifetime:Singleton ImplementationType:MyApp_CoreService.Worker”时出错:无法使用 Z2ED500A3529637175E675A8791B7C56.E 中的范围服务“MyApp.CS.Business.Facade.IMyAppCoreService”托管服务”。

You injected the Serivce IMyAppCoreService as Scoped.您将IMyAppCoreService作为 Scoped 注入。 Scoped Services can only be resolved by a ScopedServiceProvider . Scoped Services 只能由ScopedServiceProvider

My first guess is that you didn't mean to - you meant to inject your service as Singleton:我的第一个猜测是您不是故意的-您打算将服务注入为 Singleton:

services.AddSingleton<IMyAppCoreService, MyAppCoreService>();

This however might not work since you are using EF Core which injects its Context-like classes as scoped.但是,这可能不起作用,因为您使用的是 EF Core,它将其 Context-like 类作为作用域注入。 You have two options:你有两个选择:

  1. Have EF Core inject its context class as transient.让 EF Core 将其上下文 class 作为瞬态注入。 I would not suggest this as you will be responsible for disposing it.我不建议这样做,因为您将负责处理它。 If you want to go through with it, this is how to do it (Startup.cs / Program.cs):如果你想 go 通过它,这是如何做到的(Startup.cs / Program.cs):
services.AddDbContext<YourContext>(opts => { ...config...}, ServiceLifetime.Transient);
  1. Create a scope manually:手动创建 scope:

Have an IServiceProvider property called ServiceProvider injected into Worker instead of your service.将一个名为 ServiceProvider 的IServiceProvider属性注入Worker而不是您的服务。

in ExecuteAsync-Loop:在 ExecuteAsync 循环中:

_logger.LogInformation("Worker running at: {time}", DateTimeOffset.Now);
using (var scope = ServiceProvider.CreateScope())
{
  scope.ServiceProvider.GetRequiredService<IMyAppCoreService>().CheckAndProcessResult();
}
await Task.Delay(1000, stoppingToken);

This will neatly dispose every Loop's EFCore-Data Context Object and in my opinion is the cleanest option.这将巧妙地处理每个 Loop 的 EFCore-Data Context Object,在我看来是最干净的选择。

Dependency injection:依赖注入:

 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);

Worker class:工人 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);
    }
}

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM