Внедрение зависимостей в ASP. NET Core Worker Service - PullRequest
1 голос
/ 28 мая 2020

Я столкнулся с некоторыми проблемами внедрения зависимостей в. 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();
}

И см. Ниже код для 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 Время жизни: Тип реализации с заданной областью: MyApp.CS.Business.Services.MyAppCoreService ': Не удалось разрешить службу для типа «MyApp.CS.Data.Facade.ICommonRepository» при попытке активировать «MyApp.CS.Business.Services.MyAppCoreService».

Не могли бы вы сказать мне, где я был сделано неправильно?

РЕДАКТИРОВАТЬ: После того, как я зарегистрирую весь интерфейс с его классом. затем у меня появилась новая ошибка:

Ошибка при проверке дескриптора службы ServiceType: Microsoft.Extensions.Hosting.IHostedService Lifetime: Singleton ImplementationType: MyApp_CoreService.Worker ': невозможно использовать службу с областью действия' MyApp. CS.Business.Facade.IMyAppCoreService 'из синглтона' Microsoft.Extensions.Hosting.IHostedService '.

Ответы [ 2 ]

0 голосов
/ 02 сентября 2020

Внедрение зависимости:

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

Рабочий класс:

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

Источник 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

0 голосов
/ 28 мая 2020

Вы ввели Serivce IMyAppCoreService как Scoped. Службы с заданной областью могут быть разрешены только с помощью ScopedServiceProvider.

Мое первое предположение состоит в том, что вы не хотели - вы хотели внедрить свою службу как синглтон:

services.AddSingleton<IMyAppCoreService, MyAppCoreService>();

Однако это может не работать, так как вы используете EF Core, который внедряет свои классы, подобные контексту, как ограниченные. У вас есть два варианта:

  1. Попросите EF Core внедрить свой класс контекста как временный. Я бы не стал предлагать этого, так как вы будете нести ответственность за его утилизацию. Если вы хотите завершить работу с go, вот как это сделать (Startup.cs / Program.cs):
services.AddDbContext<YourContext>(opts => { ...config...}, ServiceLifetime.Transient);
Создайте область вручную:

Имейте свойство IServiceProvider с именем ServiceProvider, внедренное в Worker вместо вашей службы.

в ExecuteAsyn c -L oop:

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

Это аккуратно удалит каждый объект контекста EFCore-Data каждого L oop и, на мой взгляд, это самый чистый вариант.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...