using Avalonia.Threading; using LehrerApp.Core.Services; namespace LehrerApp.Desktop.Services; /// /// Zentrale Exception-Behandlung (13.2.1): protokolliert jeden unerwarteten Fehler und zeigt /// eine verständliche Meldung statt eines rohen Absturzes. /// /// Reichweite ehrlich betrachtet: .UIThread.UnhandledException kann /// Ausnahmen aus Befehlen/Ereignis-Handlern auf dem UI-Thread abfangen und die App am Leben /// erhalten (Handled = true) — das deckt den weit überwiegenden Teil realer Abstürze in einer /// Desktop-App ab. AppDomain.UnhandledException und TaskScheduler.UnobservedTaskException sind /// Sicherheitsnetze für Fehler außerhalb des UI-Threads; die App kann eine "IsTerminating"- /// Ausnahme dort nicht mehr verhindern, aber wenigstens vollständig protokollieren, bevor sie endet. /// public static class GlobalExceptionHandler { private static AppLogger? _logger; private static NotificationService? _notifications; public static void Install(AppLogger logger, NotificationService? notifications = null) { _logger = logger; _notifications = notifications; Dispatcher.UIThread.UnhandledException += OnDispatcherUnhandledException; AppDomain.CurrentDomain.UnhandledException += OnAppDomainUnhandledException; TaskScheduler.UnobservedTaskException += OnUnobservedTaskException; } /// Muss aufgerufen werden, sobald der DI-Container steht, damit spätere Fehler /// (die vor dem Container auftreten könnten) noch als Toast sichtbar werden. public static void AttachNotifications(NotificationService notifications) => _notifications = notifications; private static void OnDispatcherUnhandledException(object? sender, DispatcherUnhandledExceptionEventArgs e) { _logger?.Error("Unbehandelter Fehler auf dem UI-Thread.", e.Exception); _notifications?.ShowError("Es ist ein unerwarteter Fehler aufgetreten. Details wurden protokolliert."); e.Handled = true; // App am Leben halten statt abzustürzen. } private static void OnAppDomainUnhandledException(object sender, UnhandledExceptionEventArgs e) { _logger?.Error( $"Unbehandelter Fehler außerhalb des UI-Threads (IsTerminating={e.IsTerminating}).", e.ExceptionObject as Exception); } private static void OnUnobservedTaskException(object? sender, UnobservedTaskExceptionEventArgs e) { _logger?.Error("Unbeobachtete Ausnahme in einem Hintergrund-Task.", e.Exception); e.SetObserved(); // verhindert, dass die Ausnahme unbemerkt verschwindet. } }