using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows; using System.Windows.Threading; using Tango.Logging; namespace Tango.Logging { /// /// Represents an optimized WPF global exception trapper. /// /// public class WpfGlobalExceptionTrapper : IGlobalExceptionTrapper { private DateTime _lastGlobalExceptionTime = DateTime.Now; /// /// Occurs when the global exception trapper has detected an unhandled exception. /// public event EventHandler ApplicationCrashed; /// /// Initializes the specified application. /// /// The application. public void Initialize(Application app) { AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException; app.Dispatcher.UnhandledException += Dispatcher_UnhandledException; Application.Current.DispatcherUnhandledException += Current_DispatcherUnhandledException; TaskScheduler.UnobservedTaskException += TaskScheduler_UnobservedTaskException; } /// /// Handles the UnobservedTaskException event of the TaskScheduler control. /// /// The source of the event. /// The instance containing the event data. private void TaskScheduler_UnobservedTaskException(object sender, UnobservedTaskExceptionEventArgs e) { OnApplicationCrash(e.Exception); } /// /// Handles the DispatcherUnhandledException event of the Current control. /// /// The source of the event. /// The instance containing the event data. private void Current_DispatcherUnhandledException(object sender, System.Windows.Threading.DispatcherUnhandledExceptionEventArgs e) { e.Handled = OnApplicationCrash(e.Exception); } /// /// Handles the UnhandledException event of the Dispatcher control. /// /// The source of the event. /// The instance containing the event data. private void Dispatcher_UnhandledException(object sender, System.Windows.Threading.DispatcherUnhandledExceptionEventArgs e) { e.Handled = OnApplicationCrash(e.Exception); } /// /// Handles the UnhandledException event of the CurrentDomain control. /// /// The source of the event. /// The instance containing the event data. private void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e) { OnApplicationCrash(new Exception(e.ExceptionObject.ToStringSafe())); } /// /// Called when any unhandled application exception has occurred and write to log. /// /// The error. private bool OnApplicationCrash(Exception exception) { if (DateTime.Now - _lastGlobalExceptionTime > TimeSpan.FromSeconds(1)) { _lastGlobalExceptionTime = DateTime.Now; return true; } _lastGlobalExceptionTime = DateTime.Now; LogManager.Default.OverrideQueue = true; LogManager.Default.Log("Application Crashed", LogCategory.Critical); LogManager.Default.Log(exception, LogCategory.Critical); ApplicationCrashedEventArgs e = new ApplicationCrashedEventArgs(exception); ApplicationCrashed?.Invoke(this, e); if (e.TryRecover) { LogManager.Default.Log("Trying application recovery. Ignoring exception..."); } LogManager.Default.OverrideQueue = false; return e.TryRecover; } } }