net core-调用接口方式实现IHostedService的停止和启动
一 基本代码实现:
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Authorization;
[Route("home")]
[AllowAnonymous]
public class HomeController : ControllerBase {
private readonly IEnumerable<IHostedService> _hostedServices;
private readonly RecureHostedService _recureHostedService;
public HomeController(IEnumerable<IHostedService> hostedServices)
{
//_recureHostedService = hostedService;// as RecureHostedService;
// var hosteds = services.BuildServiceProvider().GetServices<IHostedService>();
_hostedServices = hostedServices;
_recureHostedService = _hostedServices.First(t => t is RecureHostedService) as RecureHostedService;
}
[Route("About")]
public IActionResult About()
{
//ViewData["Message"] = "Your application description page.";
_recureHostedService.StopAsync(new System.Threading.CancellationToken());
return Ok("Hello from Recure.");
}
[Route("Contact")]
public IActionResult Contact()
{
// ViewData["Message"] = "Your contact page.";
_recureHostedService.StartAsync(new System.Threading.CancellationToken());
return Ok("Your contact page.");
} }
public class RecureHostedService : IHostedService, IDisposable { private readonly ILogger _log; private Timer _timer; public RecureHostedService(ILogger<RecureHostedService> log) { _log = log; } public void Dispose() { _timer.Dispose(); } public Task StartAsync(CancellationToken cancellationToken) { _log.LogInformation("RecureHostedService is Starting"); _timer = new Timer(DoWork,null,TimeSpan.Zero, TimeSpan.FromSeconds(5)); return Task.CompletedTask; } public Task StopAsync(CancellationToken cancellationToken) { _log.LogInformation("RecureHostedService is Stopping"); _timer?.Change(Timeout.Infinite, 0); return Task.CompletedTask; } private void DoWork(object state) { _log.LogInformation("Timed Background Service is working."); } }
在program.cs中:
builder.Services.AddSingleton<IHostedService, RecureHostedService>();
二 使用.Net6新定时器PeriodicTimer优化:
1 新建backgroundSerices
public class MyHostedService : BackgroundService
{
private readonly ILogger<MyHostedService> _logger;
private PeriodicTimer _timer;
public MyHostedService(ILogger<MyHostedService> logger)
{
_logger = logger;
}
private readonly TimeSpan timeSpan = TimeSpan.FromSeconds(30); // 1 second.
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
_timer = new PeriodicTimer(timeSpan);
try
{
while (!stoppingToken.IsCancellationRequested &&
await _timer.WaitForNextTickAsync(stoppingToken))
{
_logger.LogInformation("Executing PeriodicBackgroundTask");
System.Console.WriteLine("Executing PeriodicBackgroundTask");
}
}
catch
{
_timer.Dispose();
}
}
public override Task StartAsync(CancellationToken cancellationToken)
{
return base.StartAsync(cancellationToken);
}
public override Task StopAsync(CancellationToken cancellationToken)
{
_timer.Dispose();
return base.StopAsync(cancellationToken);
}
}
2 添加注入到Promgram.cs中
3 控制器
using Microsoft.AspNetCore.Mvc; [ApiController] [Route("[controller]/[action]")] public class HostServiceContoller : ControllerBase { private readonly MyHostedService _myHostedService; public HostServiceContoller(IEnumerable<IHostedService> hostedServices) { _myHostedService = hostedServices.First(t => t is MyHostedService) as MyHostedService; } [HttpGet] public async Task<IActionResult> StopMyService() { _myHostedService.StopAsync(new System.Threading.CancellationToken()); return NoContent(); } [HttpGet] public async Task<IActionResult> StartMyService() { _myHostedService.StartAsync(new System.Threading.CancellationToken()); return NoContent(); } }
--
PeriodicTimer相比之前的Timer来说,有下面几个特点:
没有callback来绑定事件;
不会发生重入,只允许有一个消费者,不允许同一个PeriodicTimer在不同的地方同时WaitForNextTickAsync,不需要自己做排他锁来实现不能重入;
异步化。之前的timer的callback都是同步的,使用新timer可以使用异步方法,避免了编写Sync over Async代码;
Dispose之后,实例就无法使用,并且WaitForNextTickAsync始终返回false。