Related
So I have been doing some research into how I should be doing try-catch-finally blocks and there is some conflicting information in every post I read. Can someone clarify?
One common idea is to not catch exceptions that you do not know what to do with at that point in the code. The exception will bubble up until it presumably gets to a global exception handler if nothing else catches it. So at that point you display a message to the user that an unknown type of exception occurred, log it, etc.
Now after reading it sounds like this is the only exception handler that you will need? You should not be using it for flow control, so you should be checking if something is returned as null or is invalid causing the exception and correcting it in code. ie. testing for null and doing something about it before it can cause the exception.
But then there are other things such as running out of memory that you would not be able to test for, it would just occur during an operation and the exception would be thrown. But I would not be able to do anything about this either so this would be bubbled up to the global handler.
I think there are some that I am missing, like when dealing with files there can be some thrown from the external code. File not found exception seems like one that may come up often, so I would catch it and in the finally block gracefully close down anything I opened related to other code/processing and then notify the user and log it right there?
The only reason why you would want to catch an exception is for the finally part of the block to make sure that whatever you started before the exception is closed/finalized in a known state? But even then you would want to throw this exception after performing these tasks so the user is notified by the global exception handler, there is no point duplicating this code at this point?
So other than a global exception handler you would have try-catch-finally blocks for these scenarios.
So assuming that I am missing something here, there may be the possibility that you want to try and catch a specific type of exception and then do something with it. I cannot think of anything that you would want to do in the catch block though since the global one would log/notify the user and if you have an exception that usually means that there is no deal for the code to continue on.
Is there any easy way to know which exceptions will be thrown from which modules? I think the only way I have read is to read the MSDN or component suppliers documentation, other than that there is no way to know what exception you would be trying to catch if you were looking for a specific one (not sure why you would)
This question came up since in my application I had a section of code in a try-catch block, and it ended up that when an exception occurred it was either because an object was null, or a string was invalid. Once I wrote code to handle those scenarios the try-catch block is no longer needed, if an exception is encountered now there is nothing the code can do to recover so it should be logged and let the user know so it can be fixed.
But this goes against what I have been reading and what has been preached to me, bad code is code with no try-catch blocks. So how does this all tie together and what piece am I missing here?
The first part of your question is all correct: you should only catch exceptions that you know how to handle. Otherwise, just let them bubble up until they reach code that can handle them.
(Note that "handle" doesn't mean "log" or "display an error". It means to correct the problem that caused the exception, or work around it in some way.)
If they never encounter code that can handle them, or if they are unhandlable exceptions (like OutOfMemory), then they will eventually reach the global unhandled exception handler. This is where you will log the exception (if appropriate), display a generic error to the user (if appropriate), and more often than not, terminate the application. You cannot simply continue as if nothing happened—the exception indicates that the application is in an unexpected state. If you try and continue, you're just going to crash, or worse.
I think there are some that I am missing, like when dealing with files there can be some thrown from the external code. File not found exception seems like one that may come up often, so I would catch it and in the finally block gracefully close down anything I opened related to other code/processing and then notify the user and log it right there?
FileNotFound is a good example of an exception that you will want to handle locally. In the same method (or perhaps one level up, in your UI code) that attempts to load the file, you'll have a catch block for FileNotFound exceptions. If appropriate, display a friendly error message to the user and ask them to choose another file. If it's internal code, give up and try something else. Whatever you need to do. There are few good reasons for FileNotFound to bubble up outside of your code.
This is sort of like using exceptions for flow control, but unavoidable. There is no way to avoid using exceptions (or error codes) for I/O, so you just need to handle the failure case. You could try and verify that the file exists first, before trying to open it, but that would not solve the race issue wherein the file gets deleted or becomes otherwise inaccessible between the time your verification code runs and when you actually try and open it. So now all you've done is duplicated your error-handling code in two places, which serves little purpose.
You have to handle exceptions like FileNotFound locally. The further away from the code that throws, the less likely you can do anything reasonable about it.
Another good example of this, aside from I/O-related exceptions, is a NotSupportedException. For example, if you try to call a method that isn't supported, you might get this exception. You will likely want to handle it and have code in the catch block that falls back to a safe alternative.
The only reason why you would want to catch an exception is for the finally part of the block to make sure that whatever you started before the exception is closed/finalized in a known state? But even then you would want to throw this exception after performing these tasks so the user is notified by the global exception handler, there is no point duplicating this code at this point?
This does not require catching the exception. You can have a try block with only a finally block. A catch block is not required. In fact, this is precisely what using statement implements. If you have state that needs to be cleaned up in the event of an exception being thrown, you should implement the IDisposable pattern and wrap usage of that object in a using block.
Is there any easy way to know which exceptions will be thrown from which modules? I think the only way I have read is to read the MSDN or component suppliers documentation, other than that there is no way to know what exception you would be trying to catch if you were looking for a specific one (not sure why you would)
Precisely. This is not really a problem, though, since you are only catching the exceptions that you can do something about. If you don't know that a module can throw a particular exception, you obviously can't have written code that can handle that exception.
The documentation will tell you all of the important exceptions that you might need to handle, like FileNotFound, SecurityException, or what have you.
This question came up since in my application I had a section of code in a try-catch block, and it ended up that when an exception occurred it was either because an object was null, or a string was invalid. Once I wrote code to handle those scenarios the try-catch block is no longer needed, if an exception is encountered now there is nothing the code can do to recover so it should be logged and let the user know so it can be fixed.
Avoiding exceptions in the first place is always the best option. For example, if you can design your application so that a null object or invalid string is impossible, great. That is what we call robust code. In that case, you don't need to catch these exceptions because there's no way that you can handle it. You thought you already handled the problem, so if an exception is getting thrown anyway, it is a sign of a bug. Don't gloss over it with a catch block.
But sometimes, catch blocks are still necessary, and you write code inside of the catch block to handle the problem. In that case, there's probably no reason to re-throw the exception or log it, so you don't have any code duplication.
But this goes against what I have been reading and what has been preached to me, bad code is code with no try-catch blocks. So how does this all tie together and what piece am I missing here?
Completely wrong. I don't know where you've been reading that, but it is nonsense. Exceptions are exceptional conditions. If your code has catch blocks strewn all over it, that is a sign that you are doing it wrong. Either you're using exceptions for flow control, you're swallowing exceptions in a misguided attempt to "improve reliability", or you don't know about the global unhandled exception handler.
Doesn't sound like you're missing anything to me.
The only thing I feel compelled to mention that doesn't fit strictly into any of your questions is that sometimes you might want to catch an exception and rethrow it as a different exception. The most common situation where you would do this is if you were designing a library of re-usable code. Inside of the library, you might catch internal exceptions and, if you cannot handle them, rethrow them as general exceptions. The whole point of a library is encapsulation, so you shouldn't let exceptions bubble up that the caller cannot possibly do anything about.
There is no true guide for exceptions management (raising and handling). Every app has to decide what level of flow control should be used and how exception has to be raised/handled.
General rules are:
exceptions are raised in exceptional situations
handle exception you can handle and do meaningful things for your app so
exception raising can be used in flow control, actually it's the only way you can reliably handle flow control when you are dealing with devices, so hardware interrupts. (printers, bill validators, file transfer...)
The rest is up to you. The meaning of exception management is made by you.
Imagine you need to download some files from an FTP server, one you don't control. Of course you can't trust other people so you need to prepare for temporary outages and such. So you wrap your downloading code in a try-catch-block and look for WebException if you catch one you might check for FtpStatusCode.ActionNotTakenFileUnavailableOrBusy if that was the error you simply retry. Similarly if you call a web service a 404 might be trouble, but a 429 means that you wait a little and retry, because you had been rate-limited.
Usually you can know which exceptions can be thrown by experience or documentation but C# lacks checked exceptions. Things like NullPointerException or ArgumentNullException can be properly handled with guards in your code. But other things, like errors external dependencies can sometimes be caught and handled by you without crashing the application.
I have read several times that using
catch (Exception ex)
{
Logger.LogError(ex);
}
without re throwing is wrong, because you may be hiding exceptions that you don't know about from the rest of the code.
However, I am writing a WCF service and am finding myself doing this in several places in order to ensure that the service does not crash. (SOA states that clients should not know or care about internal service errors since they unaware of the service implementation)
For instance, my service reads data from the file system. Since the file system is unpredictable I am trapping all exceptions from the read code. This might be due to bad data, permission problems, missing files etc etc. The client doesn't care, it just gets a "Data not available" response and the real reason is logged in the service log. I don't care either, I just know there was a problem reading and I don't want to crash.
Now I can understand there may be exceptions thrown unrelated to the file system. eg. maybe I'm out of memory and trying to create a read buffer has thrown an exception. The fact remains however, that the memory problem is still related to the read. I tried to read and was unable to. Maybe there is still enough memory around for the rest of the service to run. Do I rethrow the memory exception and crash the service even though it won't cause a problem for anything else?
I do appreciate the general idea of only catching exceptions you can deal with, but surely if you have an independent piece of code that can fail without affecting anything else, then it's ok to trap any errors generated by that code? Surely it's no different from having an app wide exception handler?
EDIT: To clarify, the catch is not empty, the exception is logged. Bad example code by me, sorry. Have changed now.
I wouldn't say that your service works as expected if there are permission problems on the disk. imho a service returning "Data not available" is even worse than a service returning "Error".
imagine that you are the user of your service. You make a call to it and it returns "No data". You know that you're call is correct, but since you don't get any data you'll assume that the problem is yours and go back investigating. Lots of hours can be spent in this way.
Which is better? Treating the error as an error, or lie to your users?
Update
What the error depends on doesn't really matter. Access problems should be dealt with. A disk that fails sometimes should be mirrored etc etc. SOA puts more responsibilities on you as a developer. Hiding errors doesn't make them go away.
SOA should pass errors. It may not be a detailed error, but it should be enough for the client to understand that the server had a problem. Based on that, the client may try again later on, or just log the error or inform the service desk that a manual action might need to be taken.
If you return "No data", you won't give your users a chance to treat the error as they see fit.
Update2
I do use catch all in my top level. I log exceptions to the event log (which is being monitored).
Your original question didn't have anything in the catch (which it do now). It's fine as long as you remember to monitor that log (so that you can correct those errors).
If you are going to adopt this strategy you are going to make it very hard for deployment teams to work out why the client fails to work. At the minimum log something somewhere.
One of the main issues becomes that you will never know that something went wrong. It isn't only your clients / consumers that have the error hidden from them, it is you as the service developer yourself.
There's absolutely no problem with that code. Make sure the user gets a nice message, like "Data not available due to an internal problem. The issue has been logged and the problem will be dealt with." And everybody's fine.
It's only a problem if you eat and swallow the exception so that nobody in the world will ever fix it.
Exceptions need always to be dealt with, either by writing special code or by just fixing the path that results in the exception. You can't always anticipate all errors, but you can commit to fixing them as soon as you become aware of them.
I believe the idea is to prevent missing errors. Consider this: The service returns fine but is not doing as expected. You have to go and search through event logs, file logs etc. to find a potential error. If you put a trace write in there, you can identify hopefully the cause, but likely the area of hte issue and a timestamp to correlate errors with other logs.
If you use .NET Trace, you can implement in code and not turn it on until required. Then to debug you can turn it on without having to recompile code.
WCF Services can use FaultException to pass exceptions back to the client. I have found this useful when building a WCF n-tier application server.
It's commendable to ensure that your service does not crash, in a production environment. When debugging, you need the application to crash, for obvious reasons.
However, from your explanations, I get the impression that you're catching the exceptions you expect to be thrown, and catch the rest with an empty catch block, meaning you'll never know what happened.
It's correct to catch all exceptions as a last resort, but please log those too, they are no less interesting than those you expected. After catching and logging all exceptions related to network, I/O, security, authentication, timeout, bad data, whatever, log the rest.
In general you can say that every exception occurs in a specific circumstance. For debugging purposes it is usefull to have as much information as possible about the failure so the person who is about to fix the bug know where to look and can fix the code in a minimum amount of time, which save his boss some money.
Besides that, throwing and catching specific exceptions will make your code more readable/understable and easier to maintain. Catching a general exception will fail on this point in every point of view. Therefore, also make sure that, when throwing an exception, that is is well documented (e.g. in XML comments so the caller knows the method can throw the specific exception) and has a clear name on what went wrong. Also include only information in the exception that is directly related to the problem (like id's and such).
In vb.net, a somewhat better approach would be "Catch Ex As Exception When Not IsEvilException(Ex)", where "IsEvilException" is a Boolean function which checks whether Ex is something like OutOfMemoryException, ExecutionEngineException, etc. The semantics of catching and rethrowing an exception are somewhat different from the semantics of leaving an exception uncaught; if a particular "catch" statement would do nothing with the exception except rethrow "as is", it would be better not to catch it in the first place.
Since C# does not allow exception filtering, you're probably stuck with a few not-very-nice choices:
Explicitly catch and rethrow any "evil" types of exceptions, and then use a blanket catch for the rest
Catch all exceptions, rethrow all the evil ones "as-is", and then have your logic handle the rest
Catch all exceptions and have your logic handle them without regard for the evil ones, figuring that if the CPU is on fire it will cause enough other exceptions to be raised elsewhere to bring the program down before persistent data gets corrupted.
One problem with exception handling in both Java and .net is that it binds tightly three concepts which are actually somewhat orthogonal:
What condition or action triggered the exception
Should the exception be acted upon
Should the exception be considered resolved
Note that sometimes an exception will involve two or more types of state corruption (e.g. an attempt was made to update an object from information at a stream, and something goes wrong reading the stream, leaving both the stream and the object being updated in bad states). Code to handle either condition should act upon the exception, but the exception shouldn't be considered resolved until code for both has been run. Unfortunately, there is no standard pattern for coding such behavior. One could add a virtual read-only "Resolved" property to any custom exceptions one implements, and rethrow any such exceptions if "Resolved" returns false, but no existing exceptions will support such a property.
If something is wrong, then it is wrong. It should crash.
You can never assure proper operations if something is crashing in the code. Even if that means that a page/form will always crash as soon as it is visited, you can never assure that things will keep working, or any changes be functionally committed.
And if a data resource crashes and instead returns a resource with 0 entries, the user will just be incredibly confused by something not returning any results when there should be obvious results. Valueable time will be spent by the user trying to find out what (s)he did wrong.
The only times I would recommend catching all exceptions (and logging them, not ignoring them), is if the code that is being ran is from plugins/compiled code from users, or some weird COM library, that you have no control over yourself.
I have a application with similar code (not written by me)
try
{
EnumerateSomeCoolHardwareDevice();
}
catch (Exception ex)
{
}
UPDATE - This is .NET C# & EnumerateSomeCoolHardwareDevice() is using SerialPort?
I know how bad this code is but it works like this for a reason!
My question thou: I can see that it crashes somewhere in the EnumerateSomeCoolHardwareDevice(); but it doesn't get caught by the Catch (...) - It just crashes with the send report dialog! This also currently only happen in the release build... Is their ANY reason why my exception will NOT be caught by the catch (...)?
My guess is that you're not getting an Exception in your language/framework but rather EnumerateSomeCoolHardwareDevice() does weird things that simply cause the OS to kill your process. Remember that hardware details are abstracted by frameworks like Java and .NET, so whenever you do something with hardware directly, you're probably relying on unmanaged resources ... and whatever goes wrong there can kill you, catch or not.
One possible reason would be if the EnumerateSomeCoolHardwareDevice() function uses threading. If an exception is thrown in a thread and isn't handled within it's thread then it can crash an application. This simple app can demonstrate what I mean:
public static void testThread()
{
throw new Exception("oh god it's broken");
}
static void Main(string[] args)
{
try
{
Thread thread = new Thread(testThread);
thread.Start();
Console.ReadKey(); //Just to make sure we don't get out of the try-catch too soon
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
If you run that the app will crash and burn rather than catching the exception as you might expect.
In .NET catch (Exception ex) will only catch .NET exceptions, not native exceptions.
This question (catching native exceptions in C#) may help.
Assuming .NET, if EnumerateSomeCoolHardwareDevice uses Win32 methods via PInvoke (to access the hardware) and an error occurs, most Native methods return an error code. If that error code is not handled, and another native method is called anyway (perhaps with empty out parameters from the failed call), a serious native error (such as bad memory access or something similar) can cause a straight program crash, no exception thrown.
Have you tried the attribute
assembly:RuntimeCompatibility(WrapNonExceptionThrows = true)
That should wrap any non-.Net exceptions into System.Exception so it will be catched in your code.
If it is only happening on the production machine and not the dev machines then it could be down to DLL mismatches. Double check ALL the referenced DLLs and frameworks are the same version.
Secondly if the error is not being thrown by the EnumerateSomeCoolHardwareDevice() then it will crash the app as there is no way for the exception to get back up the stack (or thats my understanding of try/catches) in my experience this has happened to me before.
Lastly, the microsoft error report usually allows you to inspect what will be sent to MS, this should let you see where the error happened and why (assuming it has readable information within it).
Check the Event Viewer as the error should also be logged there, and normally provides an invaluable source of detail regarding the error and with a bit of digging through the error listed there you should be able to trace the fault.
If you are in .Net version 1.1 use a no parameters catch block like
catch{
...
}
Prior to .Net 2.0 there could be native exceptions that do not derive from System.Exception.
Also hook to appdomain unhandled exception event and see what happens.
There may be a try..catch inside EnumerateSomeCoolHardwareDevice().
If the exception is caught and handled there, the outer exception won't be hit unless the Exception is thrown again.
(Assuming Java) Both Error and Exception are subclasses of Throwable. If there is an assertion failing in EnumerateSomeCoolHardwareDevice() for example you will get an Error.
My guess is that there's a stack overflow happening. The .NET VM simply shuts down Release build processes that encounter a stack overflow, no CLR exceptions thrown. There's probably an internal try / catch inside that function that catches StackOverflowException one way or other, that's why it's not propagating to your code in Debug builds either.
The easiest way to figure out what's going on is by making a debug build, attaching a debugger and instructing the debugger to break before any exceptions are thrown (in Visual Studio, Debug/Exceptions and tick "Thrown" for "Common Language Runtime Exceptions" and possibly other ones as well, in cordbg.exe "catch exception")
If it is crashing madly and is using a SerialPort object then it is probably because at some point it skips onto a background thread and an exception happens here. IIRC the .DataReceived event or however you get information back from a serial port returns data on a background thread. Should an exception be thrown in this routine then the entire application will bail.
Find the background thread and put some exception handling round it.
What types of exception have you seen behaving in this way? Do you have a list of them?
Some exceptions will keep propgating up the call stack, even if they've been caught in a catch block, such as ThreadAbortException.
Others are essentially unhandleable, such as StackOverflowException or ExecutionEngineException.
If it is one of these (or some others I have probably missed), then the behaviour is probably as expected. If it is some others, then a deeper look with more information will be necessary.
Could someone explain to me why it is considered inapropriate to have a try-catch in the main() method to catch any unhandled exceptions?
[STAThread]
static void Main()
{
try
{
Application.Run(new Form1());
}
catch (Exception e)
{
MessageBox.Show("General error: " + e.ToString());
}
}
I have the understanding that this is bad practice, but not sure why.
I don't think its necessarily bad practice. There are a few caveats however...
I believe the point of whoever called this "bad practice" was to reinforce the idea that you should be catching exceptions closest to where they occur (i.e. as high up the call stack as possible/appropiate). A blanket exception handler isn't typically a good idea because its drastically reduces the control flow available to you. Coarse-grained exception handling is quite importantly not a reasonable solution to program stability. Unfortunately, many beginner developers think that it is, and take such approaches as this blanket try-catch statement.
Saying this, if you have utilised exception handling properly (in a fine-grained and task-specific manner) in the rest of your program, and handled the errors accordingly there (rather than juist displaying a generic error box), then a general try-catch for all exceptions in the Main method is probably a useful thing to have. One point to note here is that if you're reproducably getting bugs caught in this Main try-catch, then you either have a bug or something is wrong with your localised exception handling.
The primary usage of this try-catch with Main would be purely to prevent your program from crashing in very unusual circumstances, and should do hardly any more than display a (vaguely) user-friendly "fatal error" message to the user, as well as possibly logging the error somewhere and/or submitting a bug report. So to conclude: this method does have its uses, but it must be done with great care, and not for the wrong reasons.
Well, this method will only capture exceptions thrown in your main thread. If you use both the Application.ThreadException and the AppDomian.UnhandledException events instead then you'll be able to catch and log all exceptions.
I don't see how that's bad practice at all.
Letting your program crash with an unhandled exception error isn't going to instill any confidence in your end users.
Maybe someone else could provide a counter view.
Update:
Obviously you'll need to do something useful with the exception.
log it
show the user a dialog stating WHY the application is exiting (in plain text, not a stacktrace)
something else that makes sense in the context of your application.
I don't think that's a bad practice in and of itself. I think the bad practice would be if that was the ONLY try/catch block you had in your application.
In antiquity, placing a try/catch in C++ caused a fairly heavy performance penalty, and placing one around main would mean storing extra stack info for everything, which again was bad for performance.
Now computers are faster, programmers less addicted to performance, and runtimes are better built, so it's not really bad anymore (but still you might pay a little more for it, haven't benchmarked it's effect in years). So it's old folklore like iterating against the grain (compilers actually fix the iteration anyways for you nowadays). In C# it's perfectly fine, but it'd look iffy to someone from 10 years ago.
Any exception which gets to Main() is likely fatal.
If it was something easy, it should have been handled higher up. If it was something beyond your control, like OutOfMemoryException, then the program should crash.
Windows application which crash have a standard way of doing so, they trigger the Windows Error Reporting dialog. (You've likely seen it before). You can sign up to recieve crash data when this happens.
I'm not sure I think its a bad practice. What you want to do is make sure that the exception and the current state of the program when it crashes ends up in the hands of a developer, preferably logged with date, time and the user who was working with it. Basically - you want to make sure that your team has all the information they need to debug the problem, regardless of whether or not the user goes to them about the crash. Remember that many users will not, in fact, contact support if they get a crash.
The bad practice here would be catching the exception, showing a simple "Error" dialog box, and closing the application. In that case, the state of that exception is lost forever.
From a debugging standpoint, this can make life more difficult, as it makes every exception a user handled exception. This changes the debugger's behavior, unless you break on unhandled exceptions, which potentially has other issues.
That being said, I think this is a good practice at release time. In addition, I recommend listening on the AppDomain.UnhandledException and the Application.ThreadException events, as well. This will let you trap even more exceptions (such as some system exceptions that will not be caught in your "global" handler above).
That allows you to log the errors and provide the user with a good, clean message.
Change it to this and it's fine
catch(Exception ex)
{
YourLoggingSystem.LogException(ex);
}
Of course, this line should NEVER be hit as you'll have other exception handlers throughout your code catching things with much more context.
Top-level exception handling is pretty essential, but I'd recommend using:
Application.ThreadException += new ThreadExceptionEventHandler(YourExceptionHandlingMethod);
However, this will only catch exceptions on the GUI thread (much like your try..catch block) - you should use similar code for each new thread you start to handle any unexpected exceptions from them.
More about it here.
You've got the catch-all exception there which will trap everything. So if you've got any unhandled exceptions in you code you'll never see them.
On the positive side, your application will never crash!
If this is required behaviour then you'll need to have sufficient logging and reporting to let both the user and you, as developer, know what's happened and recover or exit as gracefully as possible.
I'm not saying it's bad practice, the only thing I would do different though is use the built in event for that:
Application.ThreadException += new System.Threading.ThreadExceptionEventHandler(Application_ThreadException);
static void Application_ThreadException(object sender, System.Threading.ThreadExceptionEventArgs e)
{
MessageBox.Show(e.Exception.Message); //or do whatever...
}
I think this is discouraged because exceptions are caught only once and there may be multiple things, like background threads, that need to know if a process throws.
Is this a WinForms app? Forms.Application.Run raises events whenever a thread throws an unhandled exception. The MSDN docs try to explain this, but the handler they show doesn't work! Read the updated example from the WinForms UE site.
If your program tries to keep running despite a catch-all catching who-knows-what kind of violation of assumptions down below, it's in a danger zone for things like remote exploitation of security flaws (buffer overflows, heap corruption). Putting it in a loop and continuing to run is a big red flag for software quality.
Getting out as quickly as possible is the best, e.g. exit(1). Log and exit is good though slightly riskier.
Don't believe me? The Mitre Common Weakness Enumeration (CWE) agrees. Closely related is its advice against catching NULL pointer dereferencing in this way.
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
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.
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.
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.
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.
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.
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.