I have a process with some computations in c#. I usually run it either in console on windows or in docker container on Linux. But I am seeking for a general answer which I would like to be applicable also to other types of apps such as windows service or WPF app.
I want my process to react to the application shutdown. I want to save all the computation, leave the hard drive in a consistent state, and dispose of some resources before the process ends.
I used to do it like this:
class Program
{
// longRunningTasks can be cancelled by CancellationToken from processExitTokenSource source
static Task longRunningTasks;
static readonly CancellationTokenSource processExitTokenSource = new();
static async Task doTheMainJob(CancellationToken cancellationToken)
{
// the long running computations I am interested in
}
static void CurrentDomain_ProcessExit(object? sender, EventArgs e)
{
Console.WriteLine("I expect this line to be written to console when ctrl+c is pressed or when process is to be closed by other means.");
processExitTokenSource.Cancel();
// this waits for task to end
longRunningTasks.Wait();
// aplication should exit after this line is reached
}
static async Task Main()
{
AppDomain.CurrentDomain.ProcessExit += new EventHandler(CurrentDomain_ProcessExit);
var tasks = new List<Task>();
tasks.Add(doTheMainJob(cancellationToken))
if (Settings.AllowMonitoringThroughHttp) {
tasks.Add(WebServer.RunAsync(cancellationToken));
}
longRunningTasks = Task.WhenAll(tasks.ToArray());
await longRunningTasks;
}
}
It always worked. Now I wanted to be modern and I added simple web server Microsoft.AspNetCore.Mvc server to monitor the process.
class WebServer
{
public static async Task RunAsync(CancellationToken cancellationToken)
{
var builder = WebApplication.CreateBuilder(new string[0]);
builder.Services.AddControllers();
builder.Services.AddEndpointsApiExplorer();
var app = builder.Build();
app.MapControllers();
await app.RunAsync(cancellationToken);
}
}
The server listens to some port and replies to http request flawlessly. However it seems to somehow override the ctrl+c behavior and CurrentDomain_ProcessExit method is never called. Hence processExitTokenSource is never Canceled and my computations are never canceled.
What hapens? And how do I configure the web server to behave normally? I want to cancel it myself by cancelation token.