Answer: More Exception Mysteries


Well, you folks were a lot quicker than I was… Steve got basically what I was looking for very quickly after I posted…   Ben’s answer (to add his own local Exception class) was cute, but was clearly cheating as I did say no new classes…  

 

What I was looking for exactly was:

 

class Program

{

    static void Main(string[] args)

    {

 

        AppDomain.CurrentDomain.ExceptionThrown += delegate

        {

            Console.WriteLine(“Mystery inserted code”);

        };

 

        try

        {

            Console.WriteLine(“In try”);

            throw new Exception();

        }

        catch (Exception)

        {

            Console.WriteLine(“In catch”);

        }

        Console.WriteLine(“After try..catch”);

    }

}

 

 

Notice I used the ExceptionThrown event while Steve and co used the CatchingException event… Both happen to work in this case.    Peter and I talked about the difference between these two events… it seems that CatchingException occurs when a catch block is found for a managed exception that has been thrown, before the catch block is entered.  While ExceptionThrown occurs when a managed exception is thrown, or when an unmanaged exception reaches managed code for the first time.

 

If you hook both of them, you see the sequence they event handlers fire in:

In try

ExceptionThrownHandler

CatchingExceptionHandler

In catch

After try..catch

 

Have fun!

 

 

Comments (6)

  1. David Levine says:

    This sequence of events implies that the events are delivered on the same thread on which the exception has been thrown and caught. Is this actually the case, or is this just an artifact of this particular test?

    If the events are delivered on the same thread then this has implications about thread-relative state, such as the thread stack, security invariants, culture, etc. I’d just like to confirm if this is the case. I’m also curious about considerations of appdomain boundaries when subscribing to the new events.

    Also, what would the sequence have been if there was a finally block in a called method? I’d test this myself but I don’t have Whidbey installed. I’m curious about the timing of the events and actions. Thanks.

    public void Main()

    {

    AppDomain.CurrentDomain.ExceptionThrown += delegate { Console.WriteLine("ExceptionThrownHandler"); }

    AppDomain.CurrentDomain.CatchingException += delegate { Console.WriteLine("CatchingExceptionHandler found"); }

    try

    {

    Console.WriteLine("In try");

    Method1();

    }

    catch (Exception)

    {

    Console.WriteLine("In catch");

    }

    Console.WriteLine("After try..catch");

    }

    public void Method1()

    {

    try

    {

    Console.WriteLine("In Method1 try");

    throw new Exception();

    }

    finally

    {

    Console.WriteLine("In Method1 finally");

    }

    }

    I would expect the sequence to be:

    In Try

    In Method1 try

    ExceptionThrownHandler

    CatchingExceptionHandler found

    In Method1 finally

    In Catch

    After try..catch

  2. Jeff says:

    This is interesting. Would an appropriate use of ExceptionThrownHandler and CatchingException be to protect your application from allowing any exceptions to escape to the .Net runtime? We try to protect ourselves in any event handlers from throwing exceptions to the runtime so that we have a change to present a helpful message to the end user. However it’s easy to miss an event handler. Would an appropriate use of these be to serve as a last line of defense from letting exception escape your grasp? As a result of this thread I’ve also found UnhandledException in VS.Net 2003 which I didn’t know about before. I guess I’d have the same question about that handler as well. Has anybody used any of these in a real application? Comments?

  3. Joe White says:

    Hmm. The first use that occurs to me is exception logging. But that raises the question… what happens if the ExceptionThrownHandler ends up throwing another exception? Does the event get fired again, or does the runtime deliberately *not* fire it again (to avoid infinite loops)?

  4. A vectored exception handler (see kernel32!AddVectoredExceptionHandler) lets you add to a global list…