Daily Knowledge Drop
Application OnStarted
, OnStopping
and OnStopped
event handlers can be registered using the IHostApplicationLifetime
interface (and implementation), to run logic when the application starts, is stopping and has stopped respectively.
Zero or many event handlers can dynamically be registered to handle the required logic at the correct application lifetime event.
Registering handlers
The
OnStopping
andOnStopped
events are NOT called when debugging the application using Visual Studio. The application has to be run usingdotnet run
from the command line to have these events successfully invoked whilst developing. More on this below under the Graceful shutdown section.
Api
Registering callback handlers for the events is done by injecting IHostApplicationLifetime
, and calling the Register method on the relevent CancellationToken property:
// Define an endpoint, which when called will register a callback
// method for each of the events
app.MapGet("/registerevents", (
IHostApplicationLifetime hostApplicationLifetime) =>
{
// register each of the events
hostApplicationLifetime.ApplicationStarted.Register(OnStarted);
hostApplicationLifetime.ApplicationStopping.Register(OnStopping);
hostApplicationLifetime.ApplicationStopped.Register(OnStopped);
});
app.Run();
void OnStarted()
{
Console.WriteLine("Application OnStarted - api");
}
void OnStopping()
{
Console.WriteLine("Application OnStopping - api");
}
void OnStopped()
{
Console.WriteLine("Application OnStopped - api");
}
Executing the application (using dotnet run) and then closing the application (using Ctrl-C
) without calling the endpoint, will result in no callback events being called - as none have been registered.
However executing the application, and invoking the /registerevents
endpoint, will result in the OnStarted callback event being called immediately, and the other two OnClosing and OnClosed events called when the application is shutdown. The output of the application (other logging output removed):
Application OnStarted - api
Application OnStopping - api
Application OnStopped - api
Worker
Callback events can also be registered with background/worker
services when they are instantiated. Updating the default .NET Worker template:
public class Worker : BackgroundService
{
private readonly ILogger<Worker> _logger;
private readonly IHostApplicationLifetime _hostApplicationLifetime;
// inject IHostApplicationLifetime
public Worker(ILogger<Worker> logger, IHostApplicationLifetime hostApplicationLifetime)
{
_logger = logger;
_hostApplicationLifetime = hostApplicationLifetime;
// register the callback methods
_hostApplicationLifetime.ApplicationStarted.Register(OnStarted);
_hostApplicationLifetime.ApplicationStopping.Register(OnStopping);
_hostApplicationLifetime.ApplicationStopped.Register(OnStopped);
}
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
while (!stoppingToken.IsCancellationRequested)
{
_logger.LogInformation("Worker running at: {time}", DateTimeOffset.Now);
await Task.Delay(1000, stoppingToken);
}
}
private void OnStarted()
{
Console.WriteLine("Application OnStarted - worker");
}
private void OnStopping()
{
Console.WriteLine("Application OnStopping - worker");
}
private void OnStopped()
{
Console.WriteLine("Application OnStopped - worker");
}
}
This background service can be registered in the same api application used in the previous minimal api example, using:
builder.Services.AddHostedService<Worker>();
Now executing the application, invoking the endpoint and then closing the application will result in the following output:
Application OnStarted - worker
Application OnStarted - api
Application OnStopping - api
Application OnStopping - worker
Application OnStopped - api
Application OnStopped - worker
Graceful shutdown
While the OnStopping
and OnStopped
events are useful for performing logic when the application is stopping and stopped - these events are only called in the case of a graceful shutdown
. For example, in the case when debugging using Visual Studio - when the debugging session is stopped, a graceful shutdown is not performed, and as such the stopping/stopped events are not invoked. Application functionality should not assume that the 'OnStopping' and 'OnStopped' events will always be called.
Notes
The two closing events OnStopping
and OnStopped
are especially useful, and can be leveraged to perform application cleanup tasks on closing (while not depending on them always being executing). For example, clearing any lingering cache files, or persisting any in memory logs to disk can be executing when the application is stopping/stopped.
References
Daily Drop 162: 16-09-2022
At the start of 2022 I set myself the goal of learning one new coding related piece of knowledge a day.
It could be anything - some.NET / C# functionality I wasn't aware of, a design practice, a cool new coding technique, or just something I find interesting. It could be something I knew at one point but had forgotten, or something completely new, which I may or may never actually use.
The Daily Drop is a record of these pieces of knowledge - writing about and summarizing them helps re-enforce the information for myself, as well as potentially helps others learn something new as well.