有没有办法在Asp.Net core 3.1中手动启动BackgroundService

Jin*_*ish 6 c# asp.net-core asp.net-core-3.1 ihostedservice

我知道在Asp.Net 3.0(或3.1)之前,要手动启动BackgroundService,我们可以从中派生它IHostedService并将DI注册更改为:

services.AddSingleton<IHostedService, CustomHostedService>();
Run Code Online (Sandbox Code Playgroud)

然后通过在构造函数中注入服务并调用 来手动触发服务启动StartAsync()

但是,我似乎无法在 Asp.Net Core 3.1 中做到这一点。看一下该StartAsync()方法的代码,后台服务是在应用程序启动完成之前启动的。

public async Task StartAsync(CancellationToken cancellationToken = default)
{
    _logger.Starting();
    await _hostLifetime.WaitForStartAsync(cancellationToken);

    cancellationToken.ThrowIfCancellationRequested();
    _hostedServices = Services.GetService<IEnumerable<IHostedService>>();

    foreach (var hostedService in _hostedServices)
    {
        // Fire IHostedService.Start
        await hostedService.StartAsync(cancellationToken).ConfigureAwait(false);
    }

    // Fire IApplicationLifetime.Started
    _applicationLifetime?.NotifyStarted();

    _logger.Started();
}
Run Code Online (Sandbox Code Playgroud)

手动触发后台服务启动的最佳方法是什么?

本质上,这是我的设置:

后台服务

public MyBackgroundService(Func<string, IConsumer> consumerFactory)
{
    _consumerFactory = consumerFactory ?? throw new ArgumentNullException(nameof(consumerFactory));
}
Run Code Online (Sandbox Code Playgroud)

消费者工厂注册

services.AddSingleton<Func<string, IConsumer>>(provider => providerName => provider.ConfigureConsumer(environment, providerName));

private static IConsumer ConfigureConsumer(this IServiceProvider provider, IHostEnvironment environment, string provideName)
{
    if (string.IsNullOrEmpty(provideName))
        throw new ArgumentNullException(nameof(provideName));

    var options = provider.GetRequiredService<IOptions<ConsumerConfig>>();
    if (options?.Value == null)
        throw new ArgumentNullException(nameof(options));

    return environment.IsDevelopment() 
        ? new Consumer(options, provider.GetTopics()) 
        : new Consumer((IOptions<ConsumerConfig>)options.SetSecurityOptions(provider), provider.GetTopics());
}

private static IOptions<Config> SetSecurityOptions(this IOptions<Config> config, IServiceProvider provider)
{
    var certService = provider.GetRequiredService<IVaultCertificateService>();
    ...
    return config;
}
Run Code Online (Sandbox Code Playgroud)

本质上,这个certService属性仅在请求传入并执行中间件时设置。由于ExecuteAsync()在后台服务尝试从工厂获取消费者实例时,无论如何都会执行,我没有正确配置 IConsumer 谢谢

zek*_*iri 6

注入的托管服务随应用程序启动并随应用程序停止。框架不为您提供手动控制。类似的情况应该有根本原因。当然,您可以使用线程实现您自己的解决方案,但如果您希望继续使用 Microsoft 的内置解决方案,您可以使用排队后台任务。您将启动一个带有空任务队列的后台服务。服务将监听您要添加到队列中的第一个任务。您可以随时添加任务,然后它将在后台运行。