How do I trap ctrl-c (SIGINT) in a C# console app

The Console.CancelKeyPress event is used for this. This is how it's used:

public static void Main(string[] args)
{
    Console.CancelKeyPress += delegate {
        // call methods to clean up
    };

    while (true) {}
}

When the user presses Ctrl + C the code in the delegate is run and the program exits. This allows you to perform cleanup by calling necessary methods. Note that no code after the delegate is executed.

There are other situations where this won't cut it. For example, if the program is currently performing important calculations that can't be immediately stopped. In that case, the correct strategy might be to tell the program to exit after the calculation is complete. The following code gives an example of how this can be implemented:

class MainClass
{
    private static bool keepRunning = true;

    public static void Main(string[] args)
    {
        Console.CancelKeyPress += delegate(object sender, ConsoleCancelEventArgs e) {
            e.Cancel = true;
            MainClass.keepRunning = false;
        };
        
        while (MainClass.keepRunning) {
            // Do your work in here, in small chunks.
            // If you literally just want to wait until ctrl-c,
            // not doing anything, see the answer using set-reset events.
        }
        Console.WriteLine("exited gracefully");
    }
}

The difference between this code and the first example is that e.Cancel is set to true, which means the execution continues after the delegate. If run, the program waits for the user to press Ctrl + C. When that happens the keepRunning variable changes value which causes the while loop to exit. This is a way to make the program exit gracefully.


See MSDN:

Console.CancelKeyPress Event

Article with code samples:

Ctrl-C and the .NET console application


I'd like to add to Jonas' answer. Spinning on a bool will cause 100% CPU utilization, and waste a bunch of energy doing a lot of nothing while waiting for CTRL+C.

The better solution is to use a ManualResetEvent to actually "wait" for the CTRL+C:

static void Main(string[] args) {
    var exitEvent = new ManualResetEvent(false);

    Console.CancelKeyPress += (sender, eventArgs) => {
                                  eventArgs.Cancel = true;
                                  exitEvent.Set();
                              };

    var server = new MyServer();     // example
    server.Run();

    exitEvent.WaitOne();
    server.Stop();
}