Inhoudsopgave

Implementeer globale exception handling

Elke applicatie hoort globale exception handling te hebben. Niet omdat je verwacht dat er iets misgaat, maar omdat er altijd iets misgaat op een onverwachte manier. Zonder globale exception handling heb je geen registratie van wat er is gebeurd, en geen controle over hoe de applicatie reageert.

Er zijn twee categorieën exceptions om af te handelen: verwachte fouten en onverwachte exceptions. Verwachte fouten zijn dingen waar je op anticipeert — ongeldige invoer, een mislukte HTTP-call, een ontbrekend bestand. Die kun je het beste afhandelen dicht bij de plek waar ze ontstaan. Onverwachte exceptions zijn de exceptions die je niet hebt voorzien — bugs, null references, fouten in third-party libraries. Daarvoor heb je een globaal vangnet nodig.


Globale exception handling hoort thuis op het instappunt van je applicatie. Welke hooks je gebruikt hangt af van je presentatielaag, maar de bedoeling is altijd dezelfde: log wat er is gebeurd en beslis vervolgens of de applicatie door kan gaan.

Log onverwachte exceptions als Fatal wanneer de applicatie niet kan herstellen, en als Error wanneer dat wel kan. Een onbekende applicatiestaat is gevaarlijk — het is vaak beter om netjes te crashen en opnieuw op te starten dan door te gaan in een mogelijk corrupte staat.

In plaats van geen globale handler te hebben en de exception volledig kwijt te raken, voeg je de juiste handlers voor jouw platform toe.


ASP.NET Core API

app.UseExceptionHandler(errorApp =>
{
    errorApp.Run(async context =>
    {
        var feature = context.Features.Get<IExceptionHandlerFeature>();
        Log.Fatal(feature?.Error, "Unhandled exception");
        context.Response.StatusCode = 500;
    });
});

Avalonia

// Program.cs
AppDomain.CurrentDomain.UnhandledException += (_, e) =>
    Log.Fatal(e.ExceptionObject as Exception, "Unhandled exception");

TaskScheduler.UnobservedTaskException += (_, e) =>
{
    Log.Error(e.Exception, "Unobserved task exception");
    e.SetObserved();
};

// App.axaml.cs
if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
    desktop.UnhandledException += (_, e) =>
    {
        Log.Fatal(e.Exception, "UI thread exception");
        e.Handled = true;
    };

UnhandledException wordt afgevuurd wanneer de applicatie al aan het afsluiten is — log als Fatal. UnobservedTaskException wordt afgevuurd wanneer een gefaalde Task door de garbage collector wordt opgeruimd zonder dat hij is geobserveerd — de applicatie blijft draaien, dus log als Error en roep SetObserved() aan om de crash te voorkomen.


MAUI

MauiExceptions.UnhandledException += (_, e) =>
    Log.Fatal(e.ExceptionObject as Exception, "Unhandled exception");

AppDomain.CurrentDomain.UnhandledException += (_, e) =>
    Log.Fatal(e.ExceptionObject as Exception, "Unhandled exception");

TaskScheduler.UnobservedTaskException += (_, e) =>
{
    Log.Error(e.Exception, "Unobserved task exception");
    e.SetObserved();
};

WPF

// App.xaml.cs
Application.Current.DispatcherUnhandledException += (_, e) =>
{
    Log.Fatal(e.Exception, "UI thread exception");
    e.Handled = true;
};

AppDomain.CurrentDomain.UnhandledException += (_, e) =>
    Log.Fatal(e.ExceptionObject as Exception, "Unhandled exception");

TaskScheduler.UnobservedTaskException += (_, e) =>
{
    Log.Error(e.Exception, "Unobserved task exception");
    e.SetObserved();
};

CLI

AppDomain.CurrentDomain.UnhandledException += (_, e) =>
    Log.Fatal(e.ExceptionObject as Exception, "Unhandled exception");

TaskScheduler.UnobservedTaskException += (_, e) =>
{
    Log.Error(e.Exception, "Unobserved task exception");
    e.SetObserved();
};

AppDomain.CurrentDomain.UnhandledException en TaskScheduler.UnobservedTaskException gelden voor alle platforms en horen altijd aanwezig te zijn. De platformspecifieke hook handelt UI-thread exceptions af voor applicaties die een UI-thread hebben.

Globale exception handling vervangt niet het afhandelen van verwachte fouten dicht bij de plek waar ze ontstaan. Het is het vangnet voor al het andere.

Referenties

© 2026 Rob van der Velden. Alle rechten voorbehouden.