Правильное использование Worker Service и регистрация его сервисов из Web Api (то же решение) - PullRequest
1 голос
/ 19 марта 2020

Я пытаюсь найти правильную архитектуру для решения этой проблемы: мне нужно создать API, который обслуживает контроллер REST. Этот контроллер REST просто обращается к значениям, хранящимся в словаре, и передает их пользователю. Что в структуре данных словаря? Есть данные, которые являются результатом очистки внешнего API.

Решение 1: Я не создаю рабочую службу, а только мой API. Мой API при запуске запускает другой поток асинхронно, который продолжает очищать внешний API и сохраняет данные в этом словаре.

Решение 2 - Я выбрал тот, который мне подходит лучше (поправьте меня, если я ошибаюсь) : Я создаю рабочую службу, которая вызывается при запуске моего API и выполняет роль очистки внешнего API и сохранения данных в словаре. Такие данные будут обслуживаться контроллером в моем API.

Итак, во-первых, я не знаю, правильный ли мой выбор по отношению к первому. Если это ... У меня проблемы с настройкой работника.

Program.cs моего API:

public class Program
{
    public static void Main(string[] args)
    {
        var webHost = CreateHostBuilder(args).Build();

        var configuration = new ConfigurationBuilder()
            .SetBasePath(Directory.GetCurrentDirectory())
            .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
            .AddJsonFile($"appsettings.{Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT") ?? "Production"}.json", optional: true)
            .Build();
    }

    public static IHostBuilder CreateHostBuilder(string[] args) =>
        Host.CreateDefaultBuilder(args)
            .ConfigureWebHostDefaults(webBuilder =>
            {
                webBuilder.UseStartup<Startup>();
            });
}

Startup.cs моего API:

public void ConfigureServices(IServiceCollection services)
{
    services.AddControllers();

    services.AddHostedService<Worker>(); //here I register my worker service
}

Program.cs моего работника:

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

    public static IHostBuilder CreateHostBuilder(string[] args) =>
        Host.CreateDefaultBuilder(args)
            .ConfigureServices((hostContext, services) =>
            {
                services.AddSingleton<IScraperService, ScraperService>();

                // Inject IHttpClientFactory
                services.AddHttpClient();
                services.AddHostedService<Worker>();
            });
}

Мой работник:

public class Worker : BackgroundService
{
    private readonly ILogger<Worker> _logger;
    private readonly IScraperService _scraperService;

    public Worker(ILogger<Worker> logger, IScraperService scraperService)
    {
        _logger = logger;
        _scraperService = scraperService;
    }

    protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    {
        while (!stoppingToken.IsCancellationRequested)
        {
            _scraperService.ScrapeObjects();
        }
    }
}

, поэтому, когда мой API запустит вызов рабочего (или, по крайней мере, попытка), но жалобы. Там написано, что мой работник ничего не знает о регистрации IScraperService . Конечно, нет .. потому что я зарегистрировался в ConfigureServices моего проекта Worker Service, который никогда не вызывается, потому что я не запускаю его самостоятельно.

Возможное решение: правильно ли сделать регистрацию IScraperService (services.AddSingleton ();) при запуске моего API? Пожалуйста, дайте мне знать, если все не так. Спасибо!

1 Ответ

1 голос
/ 19 марта 2020

Пусть они работают вместе

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

    public static IHostBuilder CreateHostBuilder(string[] args) =>
        Host.CreateDefaultBuilder(args)
            .ConfigureServices((hostContext, services) => {
                services.AddSingleton<IScraperService, ScraperService>();

                // Inject IHttpClientFactory
                services.AddHttpClient();
                services.AddHostedService<Worker>();
            })
            .ConfigureWebHostDefaults(webBuilder => {
                webBuilder.UseStartup<Startup>();
            });
}

Запуск

public void ConfigureServices(IServiceCollection services) {
    services.AddControllers();    
    //services.AddHostedService<Worker>(); //worker already registered in Main

    //...
}

Теперь все сервисы должны быть известны в контейнере сервисов.

Когда хост запущен , API будет прослушивать запросы и рабочий будет запущен.

public class Worker : BackgroundService {
    private readonly ILogger<Worker> _logger;
    private readonly IScraperService _scraperService;

    public Worker(ILogger<Worker> logger, IScraperService scraperService) {
        _logger = logger;
        _scraperService = scraperService;
    }

    protected override async Task ExecuteAsync(CancellationToken stoppingToken) {
        while (!stoppingToken.IsCancellationRequested) {
            await Task.Run(() => _scraperService.ScrapeObjects());
        }
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...