ASP.NET Core 2.2 基礎知識(九) 使用托管服務實現后台任務


在 ASP.NET Core 中,后台任務作為托管服務實現.托管服務是一個類,而且必須實現 IHostedService 接口,該接口定義了兩個方法:

  • StartAsync(CancellationToken cancellationToken)  該方法包含啟動后台任務的邏輯,當啟動服務器並觸發 IApplicationLifetime.ApplicationStarted 后調用該方法.
  • StopAsync(CancellationToken cancellationToken)主機正常關閉時觸發,包含結束后台任務和處理任何非托管資源的邏輯.如果應用意外關閉,則可能不會調用.

托管服務在應用啟動時激活一次,在應用關閉時正常關閉.實現 IDisposable 時,可在處置服務容器時處理資源.如果在執行后台任務期間引發錯誤,即使未調用 StopAsync ,也應調用 Dispose.

示例一:計時的后台任務

    public class TimedHostedService : IHostedService, IDisposable
    {

        private readonly ILogger _logger;
        private Timer _timer;
        public TimedHostedService(ILogger<TimedHostedService> logger)
        {
            _logger = logger;
        }

        public Task StartAsync(CancellationToken cancellationToken)
        {
            _logger.LogInformation("Timed Background Service is starting." + DateTime.Now);
            _timer = new Timer(DoWork, null, TimeSpan.Zero, TimeSpan.FromSeconds(5));//立即執行一次,每5秒執行一次
            return Task.CompletedTask;
        }


        private void DoWork(object state)
        {
            _logger.LogInformation("Timed Background Service is working." + DateTime.Now);
        }

        public Task StopAsync(CancellationToken cancellationToken)
        {
            _logger.LogInformation("Timed Background Service is stopping." + DateTime.Now);
            _timer?.Change(Timeout.Infinite, 0);//不再執行
            return Task.CompletedTask;
        }


        public void Dispose()
        {
            _timer?.Dispose();
        }
    }

 

注冊該后台任務:

        public void ConfigureServices(IServiceCollection services)
        {
            services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
            services.AddHostedService<TimedHostedService>();
        }

 

在控制台啟動該項目,期間用 ctrl+C 結束應用.

其實官方幫我們封裝了一個類來簡化上述代碼:

  /// <summary>
  /// Base class for implementing a long running <see cref="T:Microsoft.Extensions.Hosting.IHostedService" />.
  /// </summary>
  public abstract class BackgroundService : IHostedService, IDisposable

 

因此上述代碼可以修改成:

    public class MyBackGroundTask : BackgroundService
    {
        private readonly ILogger _logger;

        private Timer _timer;

        public MyBackGroundTask(ILogger<MyBackGroundTask> logger)
        {
            _logger = logger;
        }
        
        protected override async Task ExecuteAsync(CancellationToken stoppingToken)
        {
            _logger.LogInformation($" MyBackGroundTask is starting. {DateTime.Now}");
            while (!stoppingToken.IsCancellationRequested)
            {
                _logger.LogInformation($" MyBackGroundTask is working. {DateTime.Now}");
                await Task.Delay(5000, stoppingToken);
            }
            _logger.LogInformation($" MyBackGroundTask is stopping. {DateTime.Now}");
        }
    }

 

但是,我發現 

_logger.LogInformation($" MyBackGroundTask is stopping. {DateTime.Now}");

這句代碼始終不執行.不知道是哪里沒搞對.希望大神能幫個忙..

 

 示例二:在后台任務中使用有作用域的服務

要使用有作用域的服務,需要先創建一個作用域.默認情況下,不會為托管服務創建作用域.

 

    public interface IScopedProcessingService
    {
        void DoWork();
    }

    public class ScopedProcessingService : IScopedProcessingService
    {
        private readonly ILogger _logger;
        public ScopedProcessingService(ILogger<ScopedProcessingService> logger)
        {
            _logger = logger;
        }
        public void DoWork()
        {
            _logger.LogInformation($"Scoped Processing Service is working. {DateTime.Now}");
        }
    }

 

    public class ConsumeScopedServiceHostedService : IHostedService
    {

        private readonly ILogger _logger;

        public IServiceProvider Services { get; }

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

        public Task StartAsync(CancellationToken cancellationToken)
        {
            _logger.LogInformation($"Consume Scoped Service Hosted Service is starting. {DateTime.Now}");
            DoWork();
            return Task.CompletedTask;
        }

        private void DoWork()
        {
            _logger.LogInformation($"Consume Scoped Service Hosted Service is working. {DateTime.Now}");
            using (IServiceScope scope = Services.CreateScope())//創建一個作用域.
            {
                IScopedProcessingService scopedProcessingService = scope.ServiceProvider.GetRequiredService<IScopedProcessingService>(); scopedProcessingService.DoWork(); }
        }

        public Task StopAsync(CancellationToken cancellationToken)
        {
            _logger.LogInformation($"Consume Scoped Service Hosted Service is stopping. {DateTime.Now}");
            return Task.CompletedTask;
        }
    }

 

但是我真的沒搞懂官方這個例子的作用.因為托管服務只會激活一次,有作用域又有什么價值呢?希望哪位大哥能解答一下.

 

 

下面的在摘自網絡:https://www.cnblogs.com/FlyLolo/p/ASPNETCore2_11.html

經測試:

  1. 當IIS上部署的項目啟動后,后台任務隨之啟動,任務執行相應的log正常輸出。

  2. 手動回收對應的應用程序池,任務執行相應的log輸出停止。

  3. 重新請求該網站,后台任務隨之啟動,任務執行相應的log重新開始輸出。

所以不建議在這樣的后台任務中做一些需要固定定時執行的業務處理類的操作,但對於緩存刷新類的操作還是可以的,因為當應用程序池回收后再次運行的時候,后台任務會隨着啟動。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM