在asp.net core中使用託管服務實現後臺任務

在業務場景中常常須要後臺服務不停的或定時處理一些任務,這些任務是不須要及時響應請求的。
在 asp.net中會使用windows服務來處理。
在 asp.net core中,可使用託管服務來實現,託管服務是一個類,具備實現IHostService接口的後臺任務邏輯。git

導入包

使用NUGET添加Microsoft.Extensions.Hosting包到項目中
 Microsoft.Extensions.Hosting包地址github

IHostedService接口

  • 託管服務必須實現IHostedService接口,該接口爲主機管理的對象定義了兩種方法。
    StartAsync(CancellationToken) - StartAsync包含啓動後臺任務的邏輯。使用Web主機時,StartAsync在服務器啓動而且觸發IApplicationLifetime.ApplicationStarted後調用。使用Generic Host時,StartAsync會在ApplicationStarted觸發以前調用。

  • StopAsync(CancellationToken) - 在主機執行正常關閉時觸發。StopAsync包含結束後臺任務的邏輯。實現IDisposable和終結器(析構函數)來處理任何非託管資源。

取消令牌具備默認的五秒超時,以指示關閉過程再也不是正常的。在令牌上請求取消時:windows

應該停止應用正在執行的任何剩餘後臺操做。
任何調用的方法都StopAsync應該當即返回。
可是,在請求取消後,任務不會被放棄 - 調用者等待全部任務完成。服務器

若是應用程序被意外關閉(例如,應用程序的進程失敗),則StopAsync可能沒法調用。所以,StopAsync是有可能不會被調用的。asp.net

託管服務在應用啓動時激活一次,並在應用關閉時正常關閉。爲防止異常,最好繼承IDispose接口,釋放資源async

定時後臺任務用例

能夠寫一個託管服務類直接繼承IHostedService,和IDisposable接口ide

public class MyTimerHostedService : IHostedService, IDisposable
    {
        private Timer _timer;

        public Task StartAsync(CancellationToken cancellationToken)
        {
            Console.WriteLine("啓動定時任務託管服務");

            _timer = new Timer(DoWork, null, TimeSpan.Zero,
                TimeSpan.FromSeconds(0.5));

            return Task.CompletedTask;
        }

        private void DoWork(object state)
        {
            Console.WriteLine("定時任務處理中");
        }

        public Task StopAsync(CancellationToken cancellationToken)
        {
            _timer?.Change(Timeout.Infinite, 0);
            Console.WriteLine("中止定時任務");
            return Task.CompletedTask;
        }

        public void Dispose()
        {
            // 手動釋放定時器
            _timer?.Dispose();
        }
    }

該服務Startup.ConfigureServices使用AddHostedService擴展方法註冊:函數

services.AddHostedService<MyTimerHostedService>();

使用通用主機啓動 託管服務

class Program
    {
        static void Main(string[] args)
        {
            var host = new HostBuilder().ConfigureServices((hostContext, services) =>
            {
                services.AddHostedService<MyTimerHostedService>();
            }).Build();

            host.Run();

            Console.WriteLine("Hello World!");
            Console.ReadLine();
        }
    }

輸出效果

使用後臺服務BackgroundService 實現

.NET Core中實現的抽象BackgroundService基類。ui

// Copyright (c) .NET Foundation. Licensed under the Apache License, Version 2.0.
/// <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();

    protected abstract Task ExecuteAsync(CancellationToken stoppingToken);

    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;
    }

    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();
    }
}

因爲抽象類已經實現了IHostService接口定義的方法,只須要寫子類去繼承BackgroundService, 在本身的自定義託管服務類中實現ExecuteAsync()方法this

public class MyBackGroundService : BackgroundService
    {
        protected override async Task ExecuteAsync(CancellationToken stoppingToken)
        {
            while (!stoppingToken.IsCancellationRequested)
            {
                Console.WriteLine("MyBackGroundService doing");

                //延遲500毫秒執行 至關於使用了定時器
                await Task.Delay(500, stoppingToken);
            }
        }
    }

在主機中託管服務

class Program
    {
        static void Main(string[] args)
        {
            var host = new HostBuilder().ConfigureServices((hostContext, services) =>
            {
                //services.AddHostedService<MyTimerHostedService>();
                services.AddHostedService<MyBackGroundService>();
            }).Build();

            host.Run();

            Console.WriteLine("Hello World!");
            Console.ReadLine();
        }
    }

使用了HostService後極大的方便了後臺任務的管理

github源碼地址

相關文章
相關標籤/搜索