Global exception handling. Threadsafe MessageBoxAlertAdminDialog
This commit is contained in:
parent
5a80a0cc06
commit
114925ebce
@ -256,18 +256,21 @@ namespace AppScaffolding
|
||||
|
||||
private static void logStartupState(Configuration config)
|
||||
{
|
||||
#if DEBUG
|
||||
var mode = "Debug";
|
||||
#else
|
||||
var mode = "Release";
|
||||
#endif
|
||||
if (System.Diagnostics.Debugger.IsAttached)
|
||||
mode += " (Debugger attached)";
|
||||
|
||||
// begin logging session with a form feed
|
||||
Log.Logger.Information("\r\n\f");
|
||||
Log.Logger.Information("Begin. {@DebugInfo}", new
|
||||
{
|
||||
AppName = EntryAssembly.GetName().Name,
|
||||
Version = BuildVersion.ToString(),
|
||||
#if DEBUG
|
||||
Mode = "Debug",
|
||||
#else
|
||||
Mode = "Release",
|
||||
#endif
|
||||
|
||||
Mode = mode,
|
||||
LogLevel_Verbose_Enabled = Log.Logger.IsVerboseEnabled(),
|
||||
LogLevel_Debug_Enabled = Log.Logger.IsDebugEnabled(),
|
||||
LogLevel_Information_Enabled = Log.Logger.IsInformationEnabled(),
|
||||
|
||||
@ -124,7 +124,7 @@ namespace LibationWinForms.Dialogs
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
MessageBoxLib.ShowAdminAlert("Error attempting to save accounts", "Error saving accounts", ex);
|
||||
MessageBoxLib.ShowAdminAlert(this, "Error attempting to save accounts", "Error saving accounts", ex);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -46,7 +46,7 @@ namespace LibationWinForms.Dialogs
|
||||
|
||||
if (template is null)
|
||||
{
|
||||
MessageBoxLib.ShowAdminAlert($"Programming error. {nameof(EditTemplateDialog)} was not created correctly", "Edit template error", new NullReferenceException($"{nameof(template)} is null"));
|
||||
MessageBoxLib.ShowAdminAlert(this, $"Programming error. {nameof(EditTemplateDialog)} was not created correctly", "Edit template error", new NullReferenceException($"{nameof(template)} is null"));
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@ -77,6 +77,7 @@ namespace LibationWinForms.Dialogs
|
||||
catch (Exception ex)
|
||||
{
|
||||
MessageBoxLib.ShowAdminAlert(
|
||||
this,
|
||||
"Error scanning library. You may still manually select books to remove from Libation's library.",
|
||||
"Error scanning library",
|
||||
ex);
|
||||
|
||||
@ -40,7 +40,7 @@ namespace LibationWinForms
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
MessageBoxLib.ShowAdminAlert("Error attempting to export your library.", "Error exporting", ex);
|
||||
MessageBoxLib.ShowAdminAlert(this, "Error attempting to export your library.", "Error exporting", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -126,6 +126,7 @@ namespace LibationWinForms
|
||||
catch (Exception ex)
|
||||
{
|
||||
MessageBoxLib.ShowAdminAlert(
|
||||
this,
|
||||
"Error importing library. Please try again. If this still happens after 2 or 3 tries, stop and contact administrator",
|
||||
"Error importing library",
|
||||
ex);
|
||||
|
||||
@ -4,22 +4,27 @@ using System.Linq;
|
||||
using System.Windows.Forms;
|
||||
using DataLayer;
|
||||
using Dinah.Core.Logging;
|
||||
using Dinah.Core.Threading;
|
||||
using LibationWinForms.Dialogs;
|
||||
using Serilog;
|
||||
|
||||
namespace LibationWinForms
|
||||
{
|
||||
public static class MessageBoxLib
|
||||
public static class MessageBoxLib
|
||||
{
|
||||
/// <summary>
|
||||
/// Logs error. Displays a message box dialog with specified text and caption.
|
||||
/// </summary>
|
||||
/// <param name="synchronizeInvoke">Form calling this method.</param>
|
||||
/// <param name="text">The text to display in the message box.</param>
|
||||
/// <param name="caption">The text to display in the title bar of the message box.</param>
|
||||
/// <param name="exception">Exception to log</param>
|
||||
/// <returns>One of the System.Windows.Forms.DialogResult values.</returns>
|
||||
public static DialogResult ShowAdminAlert(string text, string caption, Exception exception)
|
||||
/// <param name="exception">Exception to log.</param>
|
||||
public static void ShowAdminAlert(System.ComponentModel.ISynchronizeInvoke owner, string text, string caption, Exception exception)
|
||||
{
|
||||
// for development and debugging, show me what broke!
|
||||
if (System.Diagnostics.Debugger.IsAttached)
|
||||
throw exception;
|
||||
|
||||
try
|
||||
{
|
||||
Serilog.Log.Logger.Error(exception, "Alert admin error: {@DebugText}", new { text, caption });
|
||||
@ -27,10 +32,22 @@ namespace LibationWinForms
|
||||
catch { }
|
||||
|
||||
using var form = new MessageBoxAlertAdminDialog(text, caption, exception);
|
||||
return form.ShowDialog();
|
||||
|
||||
if (owner is not null)
|
||||
{
|
||||
try
|
||||
{
|
||||
owner.UIThreadSync(() => form.ShowDialog());
|
||||
return;
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
|
||||
// synchronizeInvoke is null or previous attempt failed. final try
|
||||
form.ShowDialog();
|
||||
}
|
||||
|
||||
public static void VerboseLoggingWarning_ShowIfTrue()
|
||||
public static void VerboseLoggingWarning_ShowIfTrue()
|
||||
{
|
||||
// when turning on debug (and especially Verbose) to share logs, some privacy settings may not be obscured
|
||||
if (Log.Logger.IsVerboseEnabled())
|
||||
|
||||
@ -49,7 +49,7 @@ namespace LibationWinForms
|
||||
#if !DEBUG
|
||||
checkForUpdate();
|
||||
#endif
|
||||
|
||||
// logging is init'd here
|
||||
AppScaffolding.LibationScaffolding.RunPostMigrationScaffolding(config);
|
||||
}
|
||||
catch (Exception ex)
|
||||
@ -58,14 +58,17 @@ namespace LibationWinForms
|
||||
var body = "An unrecoverable error occurred. Since this error happened before logging could be initialized, this error can not be written to the log file.";
|
||||
try
|
||||
{
|
||||
MessageBoxLib.ShowAdminAlert(body, title, ex);
|
||||
MessageBoxLib.ShowAdminAlert(null, body, title, ex);
|
||||
}
|
||||
catch
|
||||
{
|
||||
MessageBox.Show($"{body}\r\n\r\n{ex.Message}\r\n\r\n{ex.StackTrace}", title, MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// global exception handling (ShowAdminAlert) attempts to use logging. only call it after logging has been init'd
|
||||
postLoggingGlobalExceptionHandling();
|
||||
|
||||
Application.Run(new Form1());
|
||||
}
|
||||
@ -170,7 +173,7 @@ namespace LibationWinForms
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
MessageBoxLib.ShowAdminAlert("Error checking for update", "Error checking for update", ex);
|
||||
MessageBoxLib.ShowAdminAlert(null, "Error checking for update", "Error checking for update", ex);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -182,5 +185,16 @@ namespace LibationWinForms
|
||||
|
||||
Updater.Run(upgradeProperties.LatestRelease, upgradeProperties.ZipUrl);
|
||||
}
|
||||
|
||||
private static void postLoggingGlobalExceptionHandling()
|
||||
{
|
||||
// this line is all that's needed for strict handling
|
||||
AppDomain.CurrentDomain.UnhandledException += (_, e) => MessageBoxLib.ShowAdminAlert(null, "Libation has crashed due to an unhandled error.", "Application crash!", (Exception)e.ExceptionObject);
|
||||
|
||||
// these 2 lines makes it graceful. sync (eg in main form's ctor) and thread exceptions will still crash us, but event (sync, void async, Task async) will not
|
||||
Application.ThreadException += (_, e) => MessageBoxLib.ShowAdminAlert(null, "Libation has encountered an unexpected error.", "Unexpected error", e.Exception);
|
||||
// I never found a case where including made a difference. I think this enum is default and including it will override app user config file
|
||||
Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -43,7 +43,7 @@ namespace LibationWinForms
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
MessageBoxLib.ShowAdminAlert("Error downloading update", "Error downloading update", ex);
|
||||
MessageBoxLib.ShowAdminAlert(null, "Error downloading update", "Error downloading update", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user