Зарегистрируйте несколько экземпляров IHostedService с различными параметрами конструктора (DI и не-DI) в .NET Core - PullRequest
1 голос
/ 30 октября 2019

У меня есть среда с 4 одинаковыми устройствами, к которым я должен подключиться и запросить некоторые параметры через соединение TCP (каждое устройство со своим IP-адресом). Я реализовал класс для одного устройства, которому нужны некоторые параметры (например, IP-адрес, порт, интервалы опроса и т. Д.)

Класс реализует интерфейс BackgroundService и имеет конструктор, подобный приведенному ниже:

public RemoteDevice(RemoteDeviceConfig config, ILogger<RemoteDevice> logger)

Внутри класса есть реализация метода ExecuteAsync с циклом while{}, который выполняет всю логику.

Я хочу создать рабочую службу, котораяобрабатывает несколько экземпляров этого класса на основе файла конфигурации (например, файла конфигурации с массивом устройств)

В Program.cs я бы сделал:

public static void Main(string[] args)
{
    CreateHostBuilder(args).Build().Run();
}

public static IHostBuilder CreateHostBuilder(string[] args) =>
    Host.CreateDefaultBuilder(args)
        .UseSystemd()
        .ConfigureServices((hostContext, services) =>
        {
            services.AddHostedService<RemoteDevice>(); //First device
            services.AddHostedService<RemoteDevice>(); //Second device
            ...
            services.AddHostedService<RemoteDevice>(); //n-th device

        });
...
//Methods to load configuration 
...

Без RemoteDeviceConfig параметр конструктора, ILogger вводится, но если я его добавлю, я не знаю, как внедрить мой RemoteDeviceConfig класс

Что я делаю не так?

I 'Я использую .NET Core 3.0 с VS2019 и проектом Worker Service Template.

ОБНОВЛЕНИЕ - ПРИНЯТ ОТВЕТ

Я принял @ gldraphael ответ , и я хотел бы добавить некоторые подробности о спецификации части регистрациив комментариях ответа.

Проблема: использовать реализацию ILogger в классах, созданных в основном классе Worker.

Решение: внедрить ILoggerFactory в класс Worker и использовать его для создания регистраторов для подклассов

DeviceMainClass и DeviceConfig - соответственно общий диспетчер устройств и его конфигурация.

Worker.cs

List<DeviceMainClass> devices;
//Pass ILoggerFactory to worker constructor for Dependency Injection
//On worker start, instantiate all subclasses and create logger for each class
public Worker(IOptions<List<DeviceConfig>> options, ILogger<Worker> logger, ILoggerFactory loggerFactory)
{
    devices = new List<DeviceMainClass>();
    foreach(var device in _config)
    {
        devices.Add(new DeviceMainClass(_loggerFactory.CreateLogger<DeviceMainClass>(),...other parameters));
    }

    _logger = logger;
    _loggerFactory = loggerFactory;
    _config = options.Value;
}

...

protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
    while (!stoppingToken.IsCancellationRequested)
    {


        //***for testing purposes only, repeats every second***
        _logger.LogInformation("Worker running at: {time}", DateTimeOffset.Now);
        await Task.Delay(1000, stoppingToken);
    }
}

DeviceMainClass

private readonly ILogger<DeviceMainClass> _logger;

//Use
public DeviceMainClass(ILogger<DeviceMainClass> logger, ...other parameters)
{
    _logger = logger;
    ...
}

1 Ответ

0 голосов
/ 30 октября 2019

Вы хотите сделать что-то вроде этого:

appsettings.json

{
  "Devices": [
    { "Name": "D1" },
    { "Name": "D2" },
    { "Name": "D3" },
    { "Name": "D4" }
  ]
}

CreateHostBuilder():

public static IHostBuilder CreateHostBuilder(string[] args) =>
    Host.CreateDefaultBuilder(args)
        .ConfigureServices((hostContext, services) =>
        {
            services.Configure<List<DeviceConfig>>(hostContext.Configuration.GetSection("Devices"));
            services.AddHostedService<Worker>();
        });

Рабочий:

public class Worker : BackgroundService
    {
        private readonly ILogger<Worker> _logger;
        private readonly List<DeviceConfig> config;

        public Worker(IOptions<List<DeviceConfig>> options, ILogger<Worker> logger)
        {
            config = options.Value;
            _logger = logger;
        }

        protected override async Task ExecuteAsync(CancellationToken stoppingToken)
        {
            while (!stoppingToken.IsCancellationRequested)
            {

                foreach(var device in config)
                {
                    // TODO: Process each device here
                    _logger.LogInformation("Processing device {name}", device.Name);
                }


                await Task.Delay(1000, stoppingToken);
            }
        }
    }

Если ваш текущий класс RemoteDevice имеет информацию о состоянии, создайте List<RemoteDevice> в работнике и инициализируйте из конфигурации.

...