Ctrl+C and CancellationToken#
TLDR, How to enable#
Enable the feature with appRunner.UseCancellationHandlers() or appRunner.UseDefaultMiddleware().
The problem space#
Console applications should stop gracefully when the user enters Ctrl+C or Ctrl+Break.
If your app is consuming the main thread the app will not exit right away.
Traditionally, this is solved with a following steps:
- Create a
CancellationTokenSourceand make thecancellationTokenSource.Tokenavailable for the rest of the app to reference. - Subscribe to
Console.CancelKeyPressand callcancellationTokenSource.Cancel()when triggered.cancellationToken.IsCancellationRequestedwill then return true. - Check
cancellationToken.IsCancellationRequestedin any looping code and pass the token to any libraries that check it. Instead ofThread.Sleep(...), usecancellationToken.WaitHandle.WaitOne(...)orTask.Delay(..., cancellationToken)
Cancellation middleware#
When enabled, the framework will:
- set the
CommandContext.CancellationTokenwith a new token. - register a parameter resolver for
CancellationToken - cancel the token on
Console.CancelKepPressAppDomain.CurrentDomain.ProcessExitAppDomain.CurrentDomain.UnhandledExceptionwhenUnhandledExceptionEventArgs.IsTerminating== true
The framework checks the cancellation token before every step in the pipeline.
Using the CancellationToken#
The CancellationToken is easy to access in your commands thanks to parameter resolvers. Simply add a parameter to your command or interceptor method.
public void MigrateRecords(CancellationToken cancellationToken, List<int> ids)
{
foreach(int id in ids.TakeWhile(!cancellationToken.IsCancellationRequested))
{
MigrateRecord(id);
}
}
Tip
Remember to pass the CancellationToken to all database, web and service requests that take one.
Interactive sessions#
If you code a command to use an AppRunner to run another command, Console.CancelKepPress will cancel the token for the newest CommandContext.
This enables cancelling long-running commands within an interactive session without cancelling the token for the command hosting the interactive session.
See the examples app with InteractiveSession.cs) and InteractiveMiddleware.cs) for an example of how to create an interactive session.
In the future, we hope to have a CommandDotNet.ReadLine package offering an interactive session with all the goodness that comes with ReadLine like autocomplete and history.