4

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.

NaterTot
  • 41
  • 3
  • Do you reference any unmanaged code? – paparazzo Dec 03 '13 at 19:31
  • We do link in some older Shockwave and Office libraries, although they aren't being used most of the time. – NaterTot Dec 03 '13 at 19:37
  • See this [link](http://stackoverflow.com/questions/545760/which-config-element-affects-exception-handling-with-unhandledexceptionmode-set) – ahazzah Dec 03 '13 at 19:39
  • ahazzah - I'm already setting the UnhandledExceptionMode from the default, and the optional boolean parameter doesnt' change the behavior (I tried both true/false). – NaterTot Dec 03 '13 at 20:04
  • I'm confused as to what your question is, because you don't actually ask one. – James Dec 03 '13 at 22:48
  • 1
    _Because the exceptions are being suppressed..._ I think the other exceptions _are_ being handled, this is why `ExceptionLogger` doesn't get called. Search the code for `catch` clauses and either remove them (if it's better to terminate than continue), or add logging code to each `catch` clause. – groverboy Dec 04 '13 at 00:29
  • What does the call stack look like when the IDE stops on one of these exceptions (assuming you have the IDE option to stop on first-chance exceptions enabled)? There has to be a catch frame in the call hierarchy that handles/swallows the exception. – 500 - Internal Server Error Dec 04 '13 at 01:17
  • groveryboy - The exception is 'unhandled' (ie; not caught), hence the 'but was not handled' message in the exception when caught in the debugger. – NaterTot Dec 04 '13 at 16:05
  • Internal Server Error - The top of the stack-trace is '[External Code], and the next frame is in my code which is where the debugger allows me to see the exception. Again, I don't have access to the code in the .NET DLL. – NaterTot Dec 04 '13 at 16:07
  • Blam - I created a version of the code that doesn't use any of the unmanaged libraries, and the behavior does not change. The unhandled exceptions are still being supressed. – NaterTot Dec 04 '13 at 16:08
  • Use the '@NaterTot' notation if you want others to be notified that you replied to them. – groverboy Dec 06 '13 at 03:52

1 Answers1

0

So you only see "but was not handled" when the app runs in the debugger. When it runs outside the debugger exceptions are suppressed. If I've got this correct then I still think the app handles the exceptions, because the debugger changes app behaviour sometimes.

I confirmed that InvalidCastException is one of a group of exceptions that .NET 4+ handles differently if the exception context is unmanaged code. An app can override this special handling (see All about Corrupted State Exceptions in .NET 4), but the debugger may ignore the override. There are lots of web resources on this, see also one in MSDN Magazine.

EDIT: If your app users have .NET 3.5 or below installed then the app need not apply the override described in the resources above.

groverboy
  • 1,133
  • 8
  • 20
  • I looked through the entire app, and 100% positive the exceptions are not caught by my application. Thanks for the pointers, I'll look into the CSE issue and see if that's what I'm seeing. – NaterTot Dec 06 '13 at 16:05