I'm maintaining a legacy C# Winform application, using .NET 4.0 framework. The application works fine, but occasionally due to bugs in the application, the application will fail to work properly when the the application creates invalid data in the database.
At certain points, we bind the (invalid/corrupt) data to a datagrid, which causes numerous errors when it attempts to map a null column to a datagrid column.
An exception of type 'System.InvalidCastException' occurred in mscorlib.dll but was not handled in user code
Additional information: Object cannot be cast from DBNull to other types.
As well as
An exception of type 'System.Reflection.TargetInvocationException' occurred in System.Windows.Forms.dll but was not handled in user code
The errors cause a nice popup to show when run under the Visual Studio debugger detailing the error as well as allowing me to see the line where the error occurred.
In this particular case, I know what the issue is, so I can easily correct it. However, this class of error occurs too-often in other parts of the application, so it's not always obvious what is happening, and my users don't always provide good error reports. To try and combat this, I'd like to add logging to the application (using log4net), which works in our situation as each user has their own copy of the application so I can obtain per-user logs after the fact.
Using hints from stackoverflow as well as various other sources, I found a lot of good information on setting up handlers for these unhandled exceptions. Unfortunately, my handlers are not being called for the majority of the 'unhandled' exceptions.
The mostly relevant parts of the application are below:
static class Program {
private static readonly ILog log = LogManager.GetLogger("Main");
static void Main() {
// Add some error handlers which log error data to the logfile
//
// For UI events (set the unhandled exception mode to force all Windows Forms
// errors to go through our handler)
Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException);
Application.ThreadException += new ThreadExceptionEventHandler(delegate(object s, ThreadExceptionEventArgs e) {
ExceptionLogger(e.Exception);
});
// Non-UI thread exceptions
AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(delegate(object sender, UnhandledExceptionEventArgs e) {
ExceptionLogger(e.ExceptionObject as Exception);
});
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
log.Debug("Starting Application");
Application.Run(mainForm = new MainForm());
}
private static void ExceptionLogger(Exception e) {
log.Error("Unhandled Error", e);
string errorMsg = "An application error occurred. Please contact the administrator with the following information:\n\n";
errorMsg = errorMsg + e.Message + "\n\nStack Trace:\n" + e.StackTrace;
if (MessageBox.Show(errorMsg, "TLMS Error", MessageBoxButtons.AbortRetryIgnore, MessageBoxIcon.Stop) == DialogResult.Abort)
Application.Exit();
}
The Exception handler seems to work if the errors occur directly in my own code, but the handler is not called if/when the errors occur directly in the .NET libraries, and I want the handler called for all Unhandled exceptions, including those outside of code I've written.
Being able to use the debugger to track down the errors is invaluable if I can recreate the exact users steps within the debugger after the fact. However, at no point is ExceptionLogger being called, either running standalone or inside the debugger, and there is no visual indication that any error occurred. Because the exceptions are being suppressed, the users sometimes don't realize until much too late that everything they've done is completely screwed up and the data is even more corrupt.
The application platform is being built and run on x86 (apparently exceptions can be lost if run on x64), and the application has been tested on both 64-bit and 32-bit platforms with no change in behavior.