The actual answer for you question is here and I really shouldn't answer it again, but I want to show you some code sample and I don't want to write it in comment :)
In one of my projects from time to time there was an unpredictable exception. To catch it I write this code in Program.cs
:
[STAThread]
static void Main()
{
// add UnhandledException handler
AppDomain.CurrentDomain.UnhandledException += UnhandledExceptionHandler;
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new MainForm());
}
private static void UnhandledExceptionHandler(object sender, UnhandledExceptionEventArgs e)
{
// prepare message for user
var message = "There was an unknown exception while running <app_name>!";
var exception = e.ExceptionObject as Exception;
if (exception != null)
{
// change message if there was actual exception
message = $"There was an {exception.GetType().Name} exception while running <app_name>! {exception.Message}";
// adding inner exceptions messages
var innerException = exception.InnerException;
while (innerException != null)
{
message += $"\r\n-> {innerException.GetType().Name}: {innerException.Message}";
innerException = innerException.InnerException;
}
#if DEBUG
// add tracing info
message += $"\r\n\r\n{GetStackTrace(exception)}";
#endif
}
if (e.IsTerminating) message += "\r\n\r\n<app_name> will be closed.";
// showing message to the user
MessageBox.Show(message, "Unhandled Exception", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
#if DEBUG
private static string GetStackTrace(Exception exception)
{
var trace = new System.Diagnostics.StackTrace(exception, fNeedFileInfo: true);
var frames = trace.GetFrames()
.Select((f, i) => {
var filename = f.GetFileName();
var methodInfo = f.GetMethod();
var frame = $"#{i} in the method {methodInfo.DeclaringType.FullName}.{methodInfo.Name}()";
if (filename != null) frame += $" (source file: {System.IO.Path.GetFileName(filename)}@{f.GetFileLineNumber()}:{f.GetFileColumnNumber()})";
return frame;
});
return $"Full stack trace ({trace.FrameCount} frames total):\r\n{string.Join("\r\n", frames)}";
}
#endif
Now, when unhandled exception occurring - there will be a message box, that shows full exception message (and inner exceptions messages). There was also a full stack trace for Debug build with method name, line number and source filename where exception occure.
About HandleProcessCorruptedStateExceptions
You mention a HandleProcessCorruptedStateExceptions
attribute in your comment. The docs clearly says that you shouldn't use it unless you absolutely sure that you need it.
Corrupted process state exceptions are exceptions that indicate that
the state of a process has been corrupted. We do not recommend
executing your application in this state.
By default, the common language runtime (CLR) does not deliver these
exceptions to managed code, and the try/catch
blocks (and other
exception-handling clauses) are not invoked for them. If you are
absolutely sure that you want to maintain your handling of these
exceptions, you must apply the
HandleProcessCorruptedStateExceptionsAttribute
attribute to the method
whose exception-handling clauses you want to execute. The CLR delivers
the corrupted process state exception to applicable exception clauses
only in methods that have both the
HandleProcessCorruptedStateExceptionsAttribute
and
SecurityCriticalAttribute attributes
.
Corrupted process state means that some really catastrophic things happens and it safer for your app to die right now. If you are still not scared enough, here is the Main()
method from the example above with the HandleProcessCorruptedStateExceptions
attribute set:
[STAThread]
[HandleProcessCorruptedStateExceptions, SecurityCritical]
static void Main()
{
try
{
// add UnhandledException handler
// AppDomain.CurrentDomain.UnhandledException += UnhandledExceptionHandler;
// * in this particular case is not quite useful to handle this exceptions,
// because you already wrap your entire application in a try/catch block
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new MainForm());
}
catch (Exception ex)
{
// handle it somehow
}
}