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

问题描述

我正在寻找一种使用 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 方法。我在这里做错了什么?谢谢

解决方法

您可以将 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);
                }
            }
    }