views:

499

answers:

7

So I am sold on the concept of attempting to collect data automatically from a program - i.e., popping up a dialog box that asks the user to send the report when something goes wrong.

I'm working in MS Visual Studio C#.

From an implementation point of view, does it make sense to put a try/catch loop in my main program.cs file, around where the application is run? Like this:

        try
        {
            Application.Run(new myMainForm());
        }
        catch (Exception ex)
        {
            //the code to build the report I want to send and to 
            //pop up the Problem Report form and ask the user to send

        }

or does it make sense to put try/catch loops throughout pieces of the code to catch more specific exception types? (I'm thinking not because this is a new application, and putting in more specific exception catches means I have an idea of what's going to go wrong... I don't, which is why the above seems to make sense to me.)

-Adeena

+7  A: 

I think you are right, you would not know what's going to go wrong, which is the point.

However, you might as well consider adding a handler to the ThreadException event instead.

The code above will work but there will be scenarios where multi threading might be an issue with such code, since not all code inside your windows forms program will be running in the main Application.Run loop thread.

Here's a sample code from the linked article:

[STAThread]
static void Main() 
{
   System.Windows.Forms.Application.ThreadException += new ThreadExceptionEventHandler(ReportError);
   System.Windows.Forms.Application.Run(new MainForm());
}

private static void ReportError(object sender, ThreadExceptionEventArgs e)
{
   using (ReportErrorDialog errorDlg = new ReportErrorDialog(e.Exception))
   {
    errorDlg.ShowDialog();
   }
}

More documentation on MSDN.

On a minor point, using the ThreadException event also allow your main message loop to continue running in case the exception isn't fatal (i.e. fault-tolerance scenarios) whilst the try/catch approach may requires that you restart the main message loop which could cause side effects.

chakrit
Do I need to use the code inside the "ReportError" function? (i.e., the ReportErrorDialog) or can I replace that with my own code (which is a form for reporting the problem)?
adeena
You can use any code inside ReportError, it is a normal event fired.
chakrit
+1  A: 

From an implementation point of view, does it make sense to put a try/catch loop in my main program.cs file, around where the application is run?

Sure and always.

You should use Try/Catch-Blocks wherever you do something critical, that might raise an exception.

Therefore you can not really stick to a pattern for that, because you should now, when what exception will be raised. Otherwise these are unhandled exceptions, which let your program crash.

But there are many exceptions, that need not to stop the application entirely, exceptions, that just can be swallowed over, as they are expected and do not critically need the application to stop. Example for that are UnauthorizedAccessExceptions when moving or accessing data with your programm.

You should try to keep you Try/Catch-Blocks as small as needed, as well as to use not too much of them, because of performance.

Some out there use Try/Catch for steering the program's execution. That should entirely be avoided wherever possible, cause raising an Exception is performance killer number 1.

BeowulfOF
+1  A: 

Wrapping a try catch around the whole application will mean the application will exit upon error.

While using a try and catch around each method is hard to maintain.

Best practice is to use specific try catches around units of code that will throw specific exception types such as FormatException and leave the general exception handling to the application level event handlers.

try
        {
            //Code that could error here
        }
        catch (FormatException ex)
        {
            //Code to tell user of their error
            //all other errors will be handled 
            //by the global error handler
        }

Experience will tell you the type of things that could go wrong. Over time you will notice your app often throwing say IO exceptions around file access so you may then later catch these and give the user more information.

The global handlers for errors will catch everything else. You use these by hooking up event handlers to the two events System.Windows.Forms.Application.ThreadException (see MSDN) and AppDomain.UnhandledException (see MSDN)

Be aware that Out of Memory exceptions and StackOverflowException may not be caught by any error catching.

John
A: 

The best approach is to sing up for AppDomain.UnhandledException and Application.ThreadException In your application's main function. This will allow you to record any unhandled exceptions in your application. Wraping run in a try catch block does not catch every thing.

Aaron Fischer
Sorry, but this is only somewhat helpfull, because the most exceptions do not need the program to stop entirely. These events are usefull for for some special glitches anyway.
BeowulfOF
This is for reporting unhandled exceptions. If you can handle an exception it should be handled. And if you have a try catch around application.run your app still terminates.
Aaron Fischer
A: 

if you just want to capture crashes, then ignore all errors and let DrWatson generate a minidump for you. Then you can look at that ina debugger (windbg is preferred for minidumps) and it'll show you the line your code went wrong on, and also all the parameters, stack trace, and registers. You can set Drwatson to generate a full dump where you'll get an entire memory core dump to investigate.

I wouldn't recommend putting a try/catch around the entire app unless you want your app to never "crash" in front of the user - it'll always be handled, and probably ignored as there's nothing you can do with the exception at that point.

Sending the minidump to you is another matter though, here's an article, you'll have to do some work to get it sent via email/http/ftp/etc.

gbjbaanb
A: 

Related to this question and advice...

I do have my try/catch around my Application.Run as stated in the original question.

New problem. When I run the program through the debugger in MS Visual Studio and "force" a crash (i.e., there is a bug I'm not going to fix until I've worked out the crash reporting stuff), the catch loop pops open my "Problem Report" form and works fine.

However, when I build the application, install it on a machine and then run it, reproducing my bug... I just get the windows J-I-T exception message. My form is no where to be seen.

Why does a try/catch seem to work in the debugger, but not with a built/installed app?

-Adeena

adeena
A: 

Hi,

If you do want to automatically get stack traces, Microsoft do allow you to submit them via the Error Reporting Services. All you need to do is sign up for a Digital Certificate from VeriSign and register it (for free) with Microsoft.

Microsoft then gives you a login for you to download the mini-dumps from a website, which are submitted when a user clicks "Send Error Report".

Although people can hit "Don't Send", at least it is a Microsoft dialog box and possibly not one that you have to code yourself. It would be running 24/7, you wouldn't have to worry about uptime of your web server AND you can submit workaround details for users AND you can deliver updates via Windows Update.

Information about this service is located in this "Windows Error Reporting: Getting Started" article.

Dominic Zukiewicz