Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Global try catch

I know try catch have been discussed a lot but I haven’t found a solution to my problem yet.

I’m writing a Silverlight application where every exception should generate a MessageBox that says something like “Sorry of the inconvenience”.

Since I cannot guarantee that my code will be free from exceptions my coworker has instructed me to have a try catch in every method (a couple of hundred) like this:

public void Method1()
{
    try
    {
        ...
    }
    catch (Exception e)
    {
        MessageBox.Show("Something went wrong, we apologize for the inconvenience. \n" + e.Message);
    }
}

public void Method2()
{
    try
    {
        ...
    }
    catch (Exception e)
    {
        MessageBox.Show("Something went wrong, we apologize for the inconvenience. \n" + e.Message);
    }
}

But it seems so excessive. I’ve read that one does not use try catch in this way plus there will be a lot of duplicated code plus the code will be obfuscated and hard to read.

Are there any alternatives like a global try catch I can use?

like image 346
user438236 Avatar asked Mar 30 '12 15:03

user438236


2 Answers

Try-catches in each and single method is silly. But:

What is the reason your colleague wants you to catch exceptions to that extent? Do you let exceptions slip through to a level where they are unwanted?

I had a similar case with a product already in use with our customers. It was a WPF project that is similar to silverlight. My job was to ride out bugs in old bad code, that nobody still working with us mastered. The application cross-function with other programs in windows and it was impossible to foresee what could go wrong in different environments.

I had these problems:

  1. The program stopped working because of uncaught exceptions.
  2. It was hard to understand what went wrong, in order to fix the bugs. Our customers normally report errors by emailing screen dumps where it was hard to see what happened.

My approach was:

  1. Catching exceptions on selected "user and system end points". That is typically event handlers for button click, drag-n-drop, navigation commands, and so on from the user side, and typically windows messages and server responses from the system side.
  2. A class OopsBox to make the unexpected error handling a one-liner in each catch. Each catch has an as friendly message as possible, and hides the dirty stuff behind an expand button. The box is also used for error messages for expected errors, and in those cases there is no expand button and no dirty stuff to display as we know what went wrong already. OopsBox

We gained this:

  • Users had an easier time figuring out a workaround, as they were not thrown out of context, in cases when the error were not severe.
  • It was, and still is, easier to grasp what went wrong when some unexpected behaviour was reported.
  • The Oops boxes started out in large frequencies but I believe the product is stabilizing faster now, and the Oops-boxes are much rarer.
  • Still to this day, when something goes wrong at a customer's, I get the call stack from them in an email. :)

It cost this:

  • A large walk-through of all the user and system end points.
  • Some logic had to be re-written to be able to put the catches at the right places.

Summary

  • Exceptions should be caught before they do any damage, like throwing the user out of context, and in a level where it makes sense.

  • When users run your program and something unexpected happens, make sure you have a way to point you to where to start looking. I did this by catching otherwise unhandled exceptions on "user and system end points" that I selected for this purpose.

  • Error box or not, try to find a way to not throw the user out of context when something goes wrong. It is hard to make it work in all cases though, but it is fatal when it happens.

like image 85
JOG Avatar answered Nov 06 '22 21:11

JOG


You can capture unhanded (and thread) exceptions using the Application.ThreadException and AppDomain.CurrentDomain.UnhandledException properties.

Your Main would look something like this:

[STAThread]
static void Main() { 

    if (Debugger.IsAttached) {
        Run();
        return;
    } 

    Application.ThreadException += ApplicationThreadException;
    AppDomain.CurrentDomain.UnhandledException += CurrentDomainUnhandledException;
    Run();
}

Note the debugger check, just so the debugger can catch these exceptions when your developing.

The Run function is pretty simple

    static void Run() {
        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);
        Application.Run(new MainForm());
    }

And then the two exception handlers.

    static void ApplicationThreadException(object sender, ThreadExceptionEventArgs e) {
        ErrorInformationDialog eid = new ErrorInformationDialog(e.Exception.Message, e.Exception);
        eid.ShowDialog();
    }

    static void CurrentDomainUnhandledException(object sender, UnhandledExceptionEventArgs e) {
        ErrorInformationDialog eid = new ErrorInformationDialog(e.ExceptionObject as Exception);
        eid.ShowDialog();
    }

And ErrorInformationDialog is just a form I put together to display an error notification and give instructions for reporting it.

like image 23
Nick Thomson Avatar answered Nov 06 '22 21:11

Nick Thomson