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));
+ }
}
}
}