diff --git a/src/DynamoCore/Models/DynamoModel.cs b/src/DynamoCore/Models/DynamoModel.cs index 27713cb10e3..59049486ebc 100644 --- a/src/DynamoCore/Models/DynamoModel.cs +++ b/src/DynamoCore/Models/DynamoModel.cs @@ -614,6 +614,8 @@ public static DynamoModel Start(IStartConfiguration configuration) /// Start configuration protected DynamoModel(IStartConfiguration config) { + DynamoModel.IsCrashing = false; + if (config is DefaultStartConfiguration defaultStartConfig) { // This is not exposed in IStartConfiguration to avoid a breaking change. diff --git a/src/DynamoCoreWpf/ViewModels/Core/DynamoViewModel.cs b/src/DynamoCoreWpf/ViewModels/Core/DynamoViewModel.cs index a25503f6729..cba8ac4f30e 100644 --- a/src/DynamoCoreWpf/ViewModels/Core/DynamoViewModel.cs +++ b/src/DynamoCoreWpf/ViewModels/Core/DynamoViewModel.cs @@ -8,6 +8,7 @@ using System.IO; using System.Linq; using System.Reflection; +using System.Threading.Tasks; using System.Windows; using System.Windows.Controls; using System.Windows.Forms; @@ -691,6 +692,7 @@ public struct StartConfiguration protected DynamoViewModel(StartConfiguration startConfiguration) { Dispatcher.CurrentDispatcher.UnhandledException += CurrentDispatcher_UnhandledException; + TaskScheduler.UnobservedTaskException += TaskScheduler_UnobservedTaskException; this.ShowLogin = startConfiguration.ShowLogin; @@ -772,13 +774,28 @@ protected DynamoViewModel(StartConfiguration startConfiguration) MLDataPipelineExtension = model.ExtensionManager.Extensions.OfType().FirstOrDefault(); } + + private void TaskScheduler_UnobservedTaskException(object sender, UnobservedTaskExceptionEventArgs e) + { + try + { + var crashData = new CrashErrorReportArgs(e.Exception); + Model?.Logger?.LogError($"Unobserved task exception: {crashData.Details}"); + Analytics.TrackException(e.Exception, true); + } + catch + { } + } + private void CurrentDispatcher_UnhandledException(object sender, DispatcherUnhandledExceptionEventArgs e) { - if (e.Handled) + if (e.Handled || DynamoModel.IsCrashing) { return; } + // Try to handle the exception so that the host app can continue in most cases. + // In some cases Dynamo code might still crash after this handler kicks in. In these edge cases we might see 2 CER windows (the extra one from the host app) e.Handled = true; CrashGracefully(e.Exception); } @@ -787,12 +804,12 @@ private void CrashGracefully(Exception ex) { try { - Model?.Logger?.LogError($"Unhandled exception {ex.Message}"); - DynamoModel.IsCrashing = true; + var crashData = new CrashErrorReportArgs(ex); + Model?.Logger?.LogError($"Unhandled exception: {crashData.Details} "); Analytics.TrackException(ex, true); - Model?.OnRequestsCrashPrompt(new CrashErrorReportArgs(ex)); + Model?.OnRequestsCrashPrompt(crashData); Exit(false); // don't allow cancellation } catch @@ -3491,6 +3508,7 @@ public ShutdownParams( public bool PerformShutdownSequence(ShutdownParams shutdownParams) { Dispatcher.CurrentDispatcher.UnhandledException -= CurrentDispatcher_UnhandledException; + TaskScheduler.UnobservedTaskException -= TaskScheduler_UnobservedTaskException; if (shutdownSequenceInitiated) { diff --git a/src/DynamoSandbox/DynamoCoreSetup.cs b/src/DynamoSandbox/DynamoCoreSetup.cs index 2d836862090..bb9474fcb97 100644 --- a/src/DynamoSandbox/DynamoCoreSetup.cs +++ b/src/DynamoSandbox/DynamoCoreSetup.cs @@ -166,8 +166,11 @@ private void ASMPreloadFailureHandler(string failureMessage) private void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e) { - var ex = e.ExceptionObject as Exception; - viewModel?.Model?.OnRequestsCrashPrompt(new CrashErrorReportArgs(ex)); + if (!DynamoModel.IsCrashing)//Avoid duplicate CER reports + { + var ex = e.ExceptionObject as Exception; + viewModel?.Model?.OnRequestsCrashPrompt(new CrashErrorReportArgs(ex)); + } } } }