tags:

views:

732

answers:

5

I wanted to set some handler for all the unexpected exceptions that I might not have caught inside my code. In Program.Main() I used the following code:

AppDomain.CurrentDomain.UnhandledException
    += new UnhandledExceptionEventHandler(ErrorHandler.HandleException);

But it didn't work as I expected. When I started the application in debugging mode and threw an exception it did call the handler, but afterwards the exception helper in Visual Studio popped up as if the exception occurred without any handling. I tried Application.Exit() inside the handler but it didn't work as well.

What I would like to achieve is that the exception is handled with my handler and then the application closes nicely. Is there any other way to do it or am I using the code above in the wrong way?

+7  A: 

It's because you're running it through Visual Studio in Debug mode. If you release and install your app somewhere else, nothing but your global exception handler will be processed.

Peter Lindholm
+2  A: 

Note that unhandled exceptions are still pretty fatal; you can only really use this for logging, or maybe some hasty close-down. Neither this nor Application.ThreadException can be used as a global sink for errors.

The better approach is to add proper handling - for example, around your entire Main() logic. Note that even this can't catch a few exceptions, such as errors during form-load (which get particularly nasty - you can catch them with a debugger attached, but not without).

Marc Gravell
well, yes, of course i know that ;)
agnieszka
then why not catch them in Main()?
Marc Gravell
"i know that" was an answer to the "sink for errors" part.i was taught try-catch in main is a thing you should not do. however, i must say honestly that i don't know why it would be a bad approach (of course if i catch all exceptions i can think of inside the code)
agnieszka
+1  A: 

Normally I use something like this to try and catch all unexpected top-level exceptions.

static class Program
{
    [STAThread]
    static void Main(string[] argv)
    {
        try
        {
            AppDomain.CurrentDomain.UnhandledException += (sender,e)
                => FatalExceptionHandler.Handle((Exception)e.ExceptionObject);

            Application.ThreadException += (sender,e)
                => FatalExceptionHandler.Handle(e.Exception);

            // whatever you need/want here

            Application.Run(new MainWindow());
        }
        catch (Exception huh)
        {
            FatalExceptionHandler.Handle(huh);
        }
    }
}

Maybe it is something you find helpful too? This main code routes all three ways of catching unexpected top-level exceptions through one method call. All you now need is a static class FatalExceptionHandler that includes your top-level exception handling in its Handle method.

And really, any application developer knows there are really just two things to do there:

  1. Show/log the exception like you see fit
  2. Make sure you exit/kill the application process

If you think item two is strange, remember that we only bother to do this in the first place for really exceptional situations. These things are probably bugs that need changes to your application to be accurately addressed. Any other exception handling - the functional kind - should be lower down inside your actual program code, catching specific kinds of exceptions where this makes sense and handling them there in the way that makes sense. Anything else should bubble up to your FatalExceptionHandler to make itself known and stop the possibly crippled program from working from corrupted state

Dead programs tell no lies... ;-)

peSHIr
A: 

Perhaps what you're looking for is Environment.Exit(int errorcode)

Yariv
A: 

That behavior is by design.

But there is a work-around.

Either you call Process.GetCurrentProcess().Kill(); within the handler, or simply do not let the handler end.

Check out the example:

class Program
{
    void Run()
    {
        AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException);

        Console.WriteLine("Press enter to exit.");

        do
        {
            (new Thread(delegate()
            {
                throw new ArgumentException("ha-ha");
            })).Start();

        } while (Console.ReadLine().Trim().ToLowerInvariant() == "x");


        Console.WriteLine("last good-bye");
    }

    int r = 0;

    void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
    {
        Interlocked.Increment(ref r);
        Console.WriteLine("handled. {0}", r);
        Console.WriteLine("Terminating " + e.IsTerminating.ToString());

        Thread.CurrentThread.IsBackground = true;
        Thread.CurrentThread.Name = "Dead thread";            

        while (true)
            Thread.Sleep(TimeSpan.FromHours(1));
        //Process.GetCurrentProcess().Kill();
    }

    static void Main(string[] args)
    {
        Console.WriteLine("...");
        (new Program()).Run();
    }
}

This should not be a default sink for exceptions, surely.

But this should be done to report exceptions gracefully.

modosansreves