在業務場景中常常須要後臺服務不停的或定時處理一些任務,這些任務是不須要及時響應請求的。
在 asp.net中會使用windows服務來處理。
在 asp.net core中,可使用託管服務來實現,託管服務是一個類,具備實現IHostService接口的後臺任務邏輯。git
使用NUGET添加Microsoft.Extensions.Hosting包到項目中
Microsoft.Extensions.Hosting包地址github
取消令牌具備默認的五秒超時,以指示關閉過程再也不是正常的。在令牌上請求取消時: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(); } }
.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後極大的方便了後臺任務的管理