aspnet core運行后台服務任務


之前在公司的一個項目中需要用到定時程序,當時使用的是aspnet core提供的IHostedService接口來實現后台定時程序,具體的示例可去官網查看。現在的dotnet core中默認封裝了實現IHostedService接口的基類BackgroundService,該類實現如下:

復制代碼
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using System;
using System.Threading;
using System.Threading.Tasks;

namespace Microsoft.Extensions.Hosting
{
    /// <summary>
    /// Base class for implementing a long running <see cref="IHostedService"/>.
    /// </summary>
    public abstract class BackgroundService : IHostedService, IDisposable
    {
        private Task _executingTask;
        private readonly CancellationTokenSource _stoppingCts = new CancellationTokenSource();

        /// <summary>
        /// This method is called when the <see cref="IHostedService"/> starts. The implementation should return a task that represents
        /// the lifetime of the long running operation(s) being performed.
        /// </summary>
        /// <param name="stoppingToken">Triggered when <see cref="IHostedService.StopAsync(CancellationToken)"/> is called.</param>
        /// <returns>A <see cref="Task"/> that represents the long running operations.</returns>
        protected abstract Task ExecuteAsync(CancellationToken stoppingToken);

        /// <summary>
        /// Triggered when the application host is ready to start the service.
        /// </summary>
        /// <param name="cancellationToken">Indicates that the start process has been aborted.</param>
        public virtual Task StartAsync(CancellationToken cancellationToken)
        {
            // Store the task we're executing
            _executingTask = ExecuteAsync(_stoppingCts.Token);

            // If the task is completed then return it, this will bubble cancellation and failure to the caller
            if (_executingTask.IsCompleted)
            {
                return _executingTask;
            }

            // Otherwise it's running
            return Task.CompletedTask;
        }

        /// <summary>
        /// Triggered when the application host is performing a graceful shutdown.
        /// </summary>
        /// <param name="cancellationToken">Indicates that the shutdown process should no longer be graceful.</param>
        public virtual async Task StopAsync(CancellationToken cancellationToken)
        {
            // Stop called without start
            if (_executingTask == null)
            {
                return;
            }

            try
            {
                // Signal cancellation to the executing method
                _stoppingCts.Cancel();
            }
            finally
            {
                // Wait until the task completes or the stop token triggers
                await Task.WhenAny(_executingTask, Task.Delay(Timeout.Infinite, cancellationToken));
            }

        }

        public virtual void Dispose()
        {
            _stoppingCts.Cancel();
        }
    }
}
復制代碼

根據BackgroundService源碼,我們只要實現該類的抽象方法ExecuteAsync即可。
可以有兩種實現方式來做定時程序,第一種就是實現一個Timer:

復制代碼
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using System;
using System.IO;
using System.Threading;
using System.Threading.Tasks;

namespace DemoOne.Models
{
    public class TimedBackgroundService : BackgroundService
    {
        private readonly ILogger _logger;
        private Timer _timer;

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

        protected override async Task ExecuteAsync(CancellationToken stoppingToken)
        {
            _timer = new Timer(DoWork, null, TimeSpan.Zero, TimeSpan.FromSeconds(5));
            _logger.LogInformation("周六!");
            return Task.CompletedTask;

            //Console.WriteLine("MyServiceA is starting.");

            //stoppingToken.Register(() => File.Create($"E:\\dotnetCore\\Practice\\Practice\\{DateTime.Now.Millisecond}.txt"));

            //while (!stoppingToken.IsCancellationRequested)
            //{
            //    Console.WriteLine("MyServiceA 開始執行");

            //    await Task.Delay(TimeSpan.FromSeconds(5), stoppingToken);

            //    Console.WriteLine("繼續執行");
            //}

            //Console.WriteLine("MyServiceA background task is stopping.");
        }

        private void DoWork(object state)
        {
            _logger.LogInformation($"Hello World! - {DateTime.Now}");
        }

        public override void Dispose()
        {
            base.Dispose();
            _timer?.Dispose();
        }
    }
}
復制代碼

我們看看StartAsync的源碼。上面的實現方式會直接返回一個已完成的Task,這樣就會直接運行StartAsync方法的if判斷,那么如果我們不走if呢?那么就應該由StartAsync方法返回一個已完成的Task.
第二個即是:

復制代碼
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using System;
using System.IO;
using System.Threading;
using System.Threading.Tasks;

namespace DemoOne.Models
{
    public class TimedBackgroundService : BackgroundService
    {
        protected override async Task ExecuteAsync(CancellationToken stoppingToken)
        {
            Console.WriteLine("MyServiceA is starting.");

            stoppingToken.Register(() => File.Create($"E:\\dotnetCore\\Practice\\Practice\\{DateTime.Now.Millisecond}.txt"));

            while (!stoppingToken.IsCancellationRequested)
            {
                Console.WriteLine("MyServiceA 開始執行");

                await Task.Delay(TimeSpan.FromSeconds(5), stoppingToken);

                Console.WriteLine("繼續執行");
            }

            Console.WriteLine("MyServiceA background task is stopping.");
        }

        public override void Dispose()
        {
            base.Dispose();
        }
    }
}
復制代碼

最后我們將實現了BackgroundService的類注入到DI即可:
services.AddHostedService<TimedBackgroundService>();

dotnet core的Microsoft.Extensions.Hosting 組件中,充斥着類似IHostedService接口中定義的方法:StartAsync、StopAsync方法。我們注入的HostedService服務會在WebHost類中通過GetRequiredService獲取到注入的定時服務。隨后執行StartAsync方法開始執行。建議看看Hosting組件源碼,會有很多的收獲。


免責聲明!

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



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