Diagnostics SDK

Desktop integration

Capturing UI-thread exceptions in WPF and WinForms, and crash semantics on shutdown.

Desktop integration (WPF and WinForms)

Desktop UI frameworks route UI-thread exceptions through their own channels, so AppDomain.UnhandledException alone misses them. The SDK hooks these channels via reflection, which means the core package carries no UI-framework references and the same package works everywhere. The catch: Init() must run on the UI thread.

WPF

public partial class App : Application
{
    private readonly IDiagnosticsSession _diagnostics;

    public App()
    {
        // On the UI thread, as early as possible:
        _diagnostics = TicketManDiagnostics.Init();
    }

    protected override void OnExit(ExitEventArgs e)
    {
        _diagnostics.Dispose(); // flushes pending reports
        base.OnExit(e);
    }
}

Hooked automatically: Application.DispatcherUnhandledException, or the current thread's Dispatcher.UnhandledException when the Application object does not exist yet. That is why Init() must run on the UI thread.

The SDK never sets Handled = true, so your app's crash behavior is unchanged. If the exception goes on to kill the process, the fatal-crash path also fires; the two reports share a fingerprint and are grouped server-side.

WinForms

Same pattern. Call TicketManDiagnostics.Init() at the top of Main, before Application.Run. Hooked automatically: Application.ThreadException.

If you use Application.SetUnhandledExceptionMode(UnhandledExceptionMode.ThrowException), UI exceptions become fatal crashes instead and are captured by the crash path.

Shutdown and crash semantics

  • session.Dispose() flushes pending reports within a 5-second budget and detaches the non-fatal hooks.
  • The fatal-crash hook intentionally stays attached for the process lifetime, even after disposal. With an async Main, a using-declared session is disposed while a crashing exception unwinds, before the runtime rethrows it at the entry point. The crash is still captured and spooled, then delivered the next time the app starts.

MAUI and other frameworks

Not auto-hooked in v1. Wire the framework's unhandled-exception event manually:

SomeFrameworkEvent += (s, e) => session.Client.CaptureException(e.Exception);