.NET
console application
exit event
C# programming
application lifecycle

.NET console application exit event

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

Introduction

Console applications often need one last chance to flush logs, release resources, or persist final state before the process ends. In .NET, the most common hook for that is AppDomain.CurrentDomain.ProcessExit, and for interactive termination with Ctrl+C, Console.CancelKeyPress is also important. The key detail is that exit handlers are best-effort cleanup hooks, not guaranteed recovery points for every kind of termination.

Use ProcessExit for Final Cleanup

The basic pattern is simple:

csharp
1using System;
2
3class Program
4{
5    static void Main()
6    {
7        AppDomain.CurrentDomain.ProcessExit += OnProcessExit;
8
9        Console.WriteLine("Application running. Press Enter to exit.");
10        Console.ReadLine();
11    }
12
13    static void OnProcessExit(object? sender, EventArgs e)
14    {
15        Console.WriteLine("ProcessExit fired.");
16    }
17}

This event is raised when the process is shutting down normally. It is a good place for small cleanup actions such as:

  • flushing buffered logs
  • disposing static resources
  • writing a shutdown marker

Keep the work short. Shutdown time is not the right place for long-running operations.

Handle Ctrl+C with CancelKeyPress

If the app runs interactively, Console.CancelKeyPress gives you a chance to react to Ctrl+C:

csharp
1using System;
2using System.Threading;
3
4class Program
5{
6    static bool _running = true;
7
8    static void Main()
9    {
10        Console.CancelKeyPress += (_, e) =>
11        {
12            Console.WriteLine("Cancellation requested.");
13            e.Cancel = true;
14            _running = false;
15        };
16
17        while (_running)
18        {
19            Thread.Sleep(200);
20        }
21
22        Console.WriteLine("Exiting cleanly.");
23    }
24}

This is useful when you want graceful shutdown instead of immediate termination. By setting e.Cancel = true, you tell the runtime not to terminate immediately, giving your code a chance to finish controlled cleanup.

Know What Exit Events Do Not Cover

Exit handlers are not guaranteed for every failure mode. They generally do not save you when:

  • the process is force-killed
  • the machine crashes or loses power
  • the OS terminates the process abruptly

That means exit events should complement normal durable writes, not replace them. If your app must never lose a piece of important state, persist that state during normal operation instead of waiting for shutdown.

This is a common operational mistake: treating the exit event as a transaction boundary. It is not.

Dispose Managed Resources Explicitly

Do not use ProcessExit as a substitute for normal using and Dispose patterns. Proper resource management should happen in regular control flow.

csharp
1using System;
2using System.IO;
3
4class Program
5{
6    static void Main()
7    {
8        using var writer = new StreamWriter("app.log", append: true);
9        writer.WriteLine("Application started.");
10    }
11}

This is preferable to relying on a shutdown hook to dispose resources that the program already controls directly.

ProcessExit is best for last-mile cleanup around process lifetime, not for basic ownership discipline.

Consider Modern Hosting Models

If the console app is really a hosted service built on GenericHost, the preferred shutdown path is usually hosted-service cancellation and host lifetime management rather than only raw domain events. In that model, cancellation tokens and hosted stop hooks are often cleaner than app-domain shutdown events.

Still, ProcessExit remains useful for straightforward console utilities and small process-level hooks.

Common Pitfalls

  • Putting long-running or blocking work inside ProcessExit and expecting it always to finish.
  • Assuming exit handlers run after force-kill, crash, or power loss scenarios.
  • Using shutdown events instead of normal disposal patterns during regular program flow.
  • Handling Ctrl+C without deciding whether the program should cancel immediate termination.
  • Treating exit events as the only place to persist important application state.

Summary

  • 'AppDomain.CurrentDomain.ProcessExit is the standard .NET console hook for normal process shutdown.'
  • 'Console.CancelKeyPress is useful when interactive cancellation such as Ctrl+C should trigger graceful shutdown.'
  • Exit handlers should be short and best-effort.
  • They do not replace normal resource disposal or durable state persistence.
  • Use higher-level host shutdown hooks when the console app is built as a managed service process.

Related reading
Course
Intermediate
27 lessons
14 hours
OOD Fundamentals

Master object-oriented design from first principles, SOLID, design patterns, and classic interview problems with hands-on coding.

View the course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

All Rights Reserved.