views:

232

answers:

2

Update: I've filed a bug report on Microsoft Connect: https://connect.microsoft.com/VisualStudio/feedback/details/568271/debugger-halting-on-exception-thrown-inside-methodinfo-invoke#details

If you can reproduce this problem on your machine, please upvote the bug so it can be fixed!


Ok I've done some testing and I've reduced the problem to something very simple:

i. Create a method in a new class that throws an exception:

public class Class1 {
    public void CallMe() {
        string blah = null;
        blah.ToLower();
    }
}

ii. Create a MethodInfo that points to this method somewhere else:

Type class1 = typeof( Class1 );
Class1 obj = new Class1();
MethodInfo method = class1.GetMethod( "CallMe" );

iii. Wrap a call to Invoke() in a try/catch block:

try {
    method.Invoke( obj, null ); // exception is not being caught!
} catch {
}

iv. Run the program without the debugger (works fine).

v. Now run the program with the debugger. The debugger will halt the program when the exception occurs, even though it's wrapped in a catch handler that tries to ignore it. (Even if you put a breakpoint in the catch block it will halt before it reaches it!)

In fact, the exception is happening when you run it without the debugger too. In a simple test project it's getting ignored at some other level, but if your app has any kind of global exception handling, it will get triggered there as well. [see comments]

This is causing me a real headache because it keeps triggering my app's crash-handler, not to mention the pain it is to attempt to debug.

A: 

You can't catch all exceptions. There's a few assumptions in your example. You are, for instance, assuming the exception was raised on the calling thread. Catching unhandled exceptions on other threads depends on which runtimes you're using (console, winforms, WPF, ASP.Net, etc).

Additionally, calls to System.Environment.FailFast() do not generate any handlable condition - the process is effectively terminated with no chance for intervention.

Nathan Ernst
He's calling Invoke(), not BeginInvoke(), so the call happens on the current thread. There is some external code that gets in between the call when the invocation is done, though.
Dave Markle
@Dave, but that does not guarantee that the invoked method in question does not cause another thread to be created. My assertion above holds.
Nathan Ernst
@Dave, by that, I mean, the method called by `Invoke`, could in turn create a thread (directly, or indirectly), I don't mean that `Invoke`, itself, will arbitrarily create another thread.
Nathan Ernst
It could also torrent the entire Lady Gaga anthology in the background on each call, but I don't see a reason why it would do that either.
Dave Markle
@Dave, but there is zero guarantee that it doesn't. I personally live in a world where clients invoking my libs cause me to spawn external threads, and while I do my damnedest to handle errors properly on that thread, there are occasions when I cannot. And I'm faced with 2 possiblilites: ignoring the error and providing bad data, or failing and potentially allowing the client to respond. Regardless, I cannot and do not fail silently.
Nathan Ernst
+4  A: 

I can reproduce this on my .NET 4 box, and you're right -- it only happens on .NET 4.0.

This smells very much like a bug to me, and should go on MS Connect. Major bummer if this is tripping your crash handler. Sounds like a non-pleasing way to work around this is to wrap the invoked method inside its own handler. :-(

One thing I can not reproduce, though, is tripping the crash handler. Here's my program:

namespace trash {
    public class Class1 {
        public void CallMe() {
            string blah = null;
            blah.ToLower();
        }
    }

    class Program {
        static void Main(string[] args) {
            AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException);           
            var class1 = typeof(Class1);
            var method = class1.GetMethod("CallMe");

            try {
                var obj = new Class1();
                method.Invoke(obj, null); // exception is not being caught!
            }
            catch (System.Reflection.TargetInvocationException) {
                Console.Write("what you would expect");
            }

        }

        static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e) {
            Console.Write("it would be horrible if this got tripped but it doesn't!");
        }
    }
}
Dave Markle
I haven't yet been able to reproduce the crash handler tripping in a test app either, however I'm working on it. For some reason my real app is dying pretty hard and the exception (which I print to a log file) looks very similar.
chaiguy
I did however discover something else interesting: if you bind to a property in WPF that throws an exception, the debugger will halt there too when you run it--you don't even need to call MethodInfo.Invoke at all ! The crash handler tripping when not in debug mode seems to be false, as it turns out it was a different problem causing that--meaning, this could be a VS2010 bug.
chaiguy
This answer is the same result I get. Basically there is a catch-all somewhere inside `Invoke`, something I think they seriously regret now, but it causes no end of headaches. NB. I believe exactly when the UnhandledException handler will execute depends on the version of Windows! So you may get different results on XP/Vista/7. My testing is on 7 and the UnhandledException event never fires, but it does halt in the debugger.
Daniel Earwicker