ASP.NET Core 2.2 基礎知識(九) 使用託管服務實現後臺任務

原文: ASP.NET Core 2.2 基礎知識(九) 使用託管服務實現後臺任務

在 ASP.NET Core 中,後臺任務做爲託管服務實現.託管服務是一個類,並且必須實現 IHostedService 接口,該接口定義了兩個方法:html

  • 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 結束應用.async

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

  /// <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}");

這句代碼始終不執行.不知道是哪裏沒搞對.但願大神能幫個忙..

 

 示例二:在後臺任務中使用有做用域的服務ui

要使用有做用域的服務,須要先建立一個做用域.默認狀況下,不會爲託管服務建立做用域.spa

 

    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從新開始輸出。

因此不建議在這樣的後臺任務中作一些須要固定定時執行的業務處理類的操做,但對於緩存刷新類的操做仍是能夠的,由於當應用程序池回收後再次運行的時候,後臺任務會隨着啓動。

相關文章
相關標籤/搜索