如何使用取消令牌停止范围服务?

时间:2021-02-10 08:16:12

标签: c# visual-studio asp.net-core asp.net-core-2.0

我正在寻找一种使用 Scoped background service 停止 Cancellation Token 的方法。我按照以下步骤操作:

ScopedAlertingService.cs

namespace BackgroundTasksSample.Services
{
    internal interface IScopedAlertingService
    {
        Task DoWork(System.Threading.CancellationToken stoppingToken);
    }
    public class ScopedAlertingService : IScopedAlertingService
    {
        private int executionCount = 0;
        private readonly ILogger _logger;

        public ScopedAlertingService(ILogger<ScopedAlertingService> logger)
        {
            _logger = logger;
        }

        public async Task DoWork(System.Threading.CancellationToken stoppingToken)
        {
            while (!stoppingToken.IsCancellationRequested)
            {
                executionCount++;
                _logger.LogInformation(
                    "Alert: Scoped Processing Service is working. Count: {Count}", executionCount);
            }
        }
    }
}

ConsumedServiceHostedService.cs

namespace BackgroundTasksSample.Services
{
    public class ConsumeScopedServiceHostedService : BackgroundService
    {
        private readonly ILogger<ConsumeScopedServiceHostedService> _logger;

        public ConsumeScopedServiceHostedService(IServiceProvider services,
            ILogger<ConsumeScopedServiceHostedService> logger)
        {
            Services = services;
            _logger = logger;
        }

        public IServiceProvider Services { get; }


        protected override async Task ExecuteAsync(CancellationToken stoppingToken)
        {
            CancellationTokenSource _stoppingCts = CancellationTokenSource.CreateLinkedTokenSource(stoppingToken);
            _stoppingCts.CancelAfter(30000);

            _logger.LogInformation(
                "Consume Scoped Service Hosted Service running.");

            while (!stoppingToken.IsCancellationRequested)
            {
                await Task.Delay(10000, stoppingToken);

                using (var scope = Services.CreateScope())
                {
                    var scopedProcessingService =
                        scope.ServiceProvider
                            .GetRequiredService<IScopedAlertingService>();

                    
                    await scopedProcessingService.DoWork(stoppingToken);
                }
            }
    }

        private async Task DoWork(CancellationToken stoppingToken)
        {
            _logger.LogInformation(
                "Consume Scoped Service Hosted Service is working.");

            using (var scope = Services.CreateScope())
            {
                var scopedProcessingService =
                    scope.ServiceProvider
                        .GetRequiredService<IScopedAlertingService>();

                await scopedProcessingService.DoWork(stoppingToken);
            }
        }

        public override async Task StopAsync(CancellationToken stoppingToken)
        {
            _logger.LogInformation(
                "Consume Scoped Service Hosted Service is stopping.");

            await Task.CompletedTask;
        }
    }
    }

我正在使用 IServiceCollection

运行此服务
#region snippet2
services.AddHostedService<ConsumeScopedServiceHostedService>();
services.AddScoped<IScopedAlertingService, ScopedAlertingService>();
#endregion

我使用以下代码在 30 秒后停止服务:

 CancellationTokenSource _stoppingCts = CancellationTokenSource.CreateLinkedTokenSource(stoppingToken);
 _stoppingCts.CancelAfter(30000); 

但是调试器不会去 stopAsyncConsumeScopedServiceHostedService 方法。我在这里做错了什么?谢谢

1 个答案:

答案 0 :(得分:1)

您可以将 IHostedService 注入为 Singleton,然后您可以在后台服务中调用 stop 方法。

更新: 在托管服务中,stopasync 仅在应用程序关闭时调用,但在您的代码中您可以使用它并且它可以工作:

 protected override async Task ExecuteAsync(CancellationToken stoppingToken)
        {
            CancellationTokenSource _stoppingCts = CancellationTokenSource.CreateLinkedTokenSource(stoppingToken);
            _stoppingCts.CancelAfter(30000);

            _logger.LogInformation(
                "Consume Scoped Service Hosted Service running.");

            while (!_stoppingCts.Token.IsCancellationRequested)
            {
                await Task.Delay(10000, _stoppingCts.Token);

                using (var scope = Services.CreateScope())
                {
                    var scopedProcessingService =
                        scope.ServiceProvider
                            .GetRequiredService<IScopedAlertingService>();

                    
                    await scopedProcessingService.DoWork(_stoppingCts.Token);
                }
            }
    }