I'm using the .NET Core 3.1 worker service template to build a Windows Service.
I gather that the basic flow should be handled within ExecuteAsync
, roughly like so:
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
while (!stoppingToken.IsCancellationRequested)
{
try
{
_Logger.LogInformation("Worker running at: {time}", DateTimeOffset.Now);
await SomeMethodThatDoesTheWork(stoppingToken);
}
catch (Exception ex)
{
_Logger.LogError(ex, "Global exception occurred. Will resume in a moment.");
}
await Task.Delay(TimeSpan.FromSeconds(10), stoppingToken);
}
}
I'm trying to properly signal from within the process that I want the app to shut down.
When stopping the service, I assume StopAsync()
gets called. This seems to work fine. So I thought await StopAsync()
would do the trick, but afterwards, ExecuteAsync
still keeps running (so I'm guessing StopAsync
won't request cancellation, and you're not supposed to call it yourself).
So I amended my loop with another bool:
while (!stoppingToken.IsCancellationRequested && !_ShuttingDown)
This does exit the loop, and never enters ExecuteAsync
again. However, the app just keeps on running. According to the debugger, it just stays on host.Run()
.
How do I signal to the application host that I want to shut down?
In ASP.NET Core, background services are independent from the application. It's possible, e.g., for services to finish and yet the application continues executing. If you want your application to exit when your background service finishes, then you'll need to wire that up yourself.
You can inject IHostApplicationLifetime
into your service and then call IHostApplicationLifetime.StopApplication
. Something like this:
public sealed class MyService : BackgroundService
{
private readonly IHostApplicationLifetime _hostApplicationLifetime;
private readonly ILogger<MyService> _logger;
public MyService(IHostApplicationLifetime hostApplicationLifetime, ILogger<MyService> logger)
{
_hostApplicationLifetime = hostApplicationLifetime;
_logger = logger;
}
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
try
{
while (!stoppingToken.IsCancellationRequested)
{
try
{
_logger.LogInformation("Worker running at: {time}", DateTimeOffset.Now);
await SomeMethodThatDoesTheWork(stoppingToken);
}
catch (Exception ex)
{
_logger.LogError(ex, "Global exception occurred. Will resume in a moment.");
}
await Task.Delay(TimeSpan.FromSeconds(10), stoppingToken);
}
}
finally
{
_logger.LogCritical("Exiting application...");
_hostApplicationLifetime.StopApplication();
}
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With