我正在使用带有.net核心的mvc,我需要在启动时运行一个任务,并在应用程序停止时停止它。在Startup.cs中,我注册了应用程序启动和停止的事件。问题是,我不知道如何从启动时运行必须在特定类中运行的任务。任务看起来像这样:
public void PreventStatusChange()
{
while (forceStatusChange)
{
foreach (var ext in GetExtensions())
{
ext.Status = StatusType.Available;
}
Thread.Sleep(1000);
}
}
变量forceStatusChange在同一类中声明,所以我从Startup.cs中看不到它。最好的方法是什么?
答案 0 :(得分:5)
您需要创建一个实现IHostedService的类。该接口仅定义两个方法,StartAsync在应用程序启动时调用,StopAsync
在应用程序终止时调用。
您需要使用以下命令将其注册为托管服务:
services.AddHostedService<TimedHostedService>();
请小心使用AddHostedService
,不要 AddSingleton
。如果您使用AddSingleton
,则运行时将不会在适当的时候调用StartAsync和StopAsync。
文章Background tasks with hosted services in ASP.NET Core显示了如何使用计时器来实现服务:
internal 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.");
_timer = new Timer(DoWork, null, TimeSpan.Zero,
TimeSpan.FromSeconds(10));
return Task.CompletedTask;
}
private void DoWork(object state)
{
_logger.LogInformation("Timed Background Service is working.");
}
public Task StopAsync(CancellationToken cancellationToken)
{
_logger.LogInformation("Timed Background Service is stopping.");
_timer?.Change(Timeout.Infinite, 0);
return Task.CompletedTask;
}
public void Dispose()
{
_timer?.Dispose();
}
}
此代码中没有什么特别有趣的-只需在调用StartAsync
时启动一个计时器,然后在StopAsync
上停止它即可
取消长期运行的任务
当运行时需要回收或停止时,它将在所有托管服务上调用StopAsync
方法,稍等片刻使其正常运行,然后警告其立即取消。片刻之后,它将继续并终止应用程序或回收它。
cancellationToken
参数用于表示该服务应立即停止。通常,这意味着您必须编写自己的代码进行检查,警告自己的任务终止,等待所有任务完成等,类似于代码shown in this article
这几乎是样板,这就是为什么可以使用BackgroundService类来创建只需要实现ExecuteAsync(CancellationToken)
的类的原因。 BackgroundService
提供了启动和停止该任务的功能,例如:
public class PollingService : BackgroundService
{
private readonly ILogger _logger;
public PollingService(ILogger<PollingService> logger)
{
_logger = logger;
}
protected async override Task ExecuteAsync(
CancellationToken cancellationToken)
{
while (!cancellationToken.IsCancellationRequested)
{
try
{
await DoSomething(cancellationToken);
await Task.Delay(1000,cancellationToken);
}
catch (Exception ex)
{
_logger.LogError(ex,
$"Error occurred executing {nameof(workItem)}.");
}
}
_logger.LogInformation("Queued Hosted Service is stopping.");
}
}
在这种情况下,一旦运行时提出取消令牌,Task.Delay()
本身将被取消。 DoSomething()
本身应以检查取消令牌的方式实现,例如,将其传递给将其作为参数接受的任何异步方法,在每个循环上测试IsCancellationRequested
属性并退出引发的令牌。 / p>
例如:
protected async override Task ExecuteAsync(
CancellationToken cancellationToken)
{
while (!cancellationToken.IsCancellationRequested)
{
try
{
foreach (var ext in GetExtensions())
{
//Oops, time to cancel
if(cancellationToken.IsCancellationRequested)
{
break;
}
//Otherwise, keep working
ext.Status = StatusType.Available;
}
await Task.Delay(1000,cancellationToken);
}
catch (Exception ex)
{
...
}
}
_logger.LogInformation("Hosted Service is stopping.");
}
答案 1 :(得分:1)
您可以使用BackgroundService
ALLOWED_HOSTS = ['192.168.45.2', 'localhost', '127.0.0.1','192.168.1.2']
并注册:
public class LongRunningService : BackgroundService
{
public LongRunningService()
{
}
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
while (!stoppingToken.IsCancellationRequested && forceStatusChange)
{
foreach (var ext in GetExtensions())
{
ext.Status = StatusType.Available;
}
await Task.Delay(1000, stoppingToken);
}
}
protected override async Task StopAsync (CancellationToken stoppingToken)
{
// Run your graceful clean-up actions
}
}