Structured Exception Handling
How Exception Management Works
- An exception is thrown
- The application tries to handle the exception up call stack
- If the exception is not handled, the application will finally show dreaded "unhandled exception"
Good structured exception management techniques will help you avoid unhandled exceptions. You can decrease the chance of a user seeing an unhandled exception by implementing a global exception manager.
Common Areas of Exception
- Accessing an array item outside the bounds of the array
- Accessing a NULL object
- Attempting to access unavailable system resources
- Attempting to executing an invalid SQL statement
- Throw your own
Throwing Exceptions
If you throw your own exception, try to limit to truly exceptional cases. An exceptional case is when the application encounters a critical and irreparable situation like those described above.
When throwing your own exceptions its important to select the correct exception. Often you will want to use ApplicationException, ArgumentException, NotImplementedException, or perhaps some other flavor of exception. You also have the option of creating your own custom exception.
Custom Exceptions
When you create custom exceptions, there are a few guidelines to keep in mind.
[Serializable]
public class CustomException : ApplicationException
{
public CustomException(){}
public CustomException(string message) :
base(message){}
public CustomException(string message,
Exception innerException) :
base(message,innerException) {}
}
- Inherit from System.ApplicationException
- Mark up with the Serializable attribute
- Add three constructors
- Default - no parameters
- Message
- Message and inner object
The class doesn't do much and it doesn't have to do much. The benefit of the custom exceptions is that they are strongly typed.
Handling Exceptions
There are two parts to handling an exception: back and front end processing. You must do something on the server to deal with the exception and you must do another "something" to notify the user that an exceptional occurance has happened.
- Back End
- Publish the exeption and allow for a graceful failure.
- Front End
- Tell the user what has happened, and (possibly) how to correct the situation.
Publishing Exeptions
Publishing exceptions will record the exception information to a database, an event/error log, email or some other form of persistence. There are some tools available to help you do this. The Microsoft Exception Management Application Block has the basic plumbing to publish exceptions like this and my employer has a framework where this functionality is already baked in to an application.
Notifing the User
I have come up with a system that makes notifing the user very easy.
Each page in your web application should inherit from your own base class that subclasses System.Web.UI.Page in order to encapsulate the functionality of a WebForms page. Once you have this base class you can place very useful additions to your application in the class.
What I do is programmatically add in a CustomValidator control on to each page. Then when an exception is being handled the program will carry out a few actions. First, the exception is published, second the exception message is set equal to the CustomValidator's ErrorMessage property and the CustomValidator's IsValid property is flagged as false. Finally the method will write the exception information to the output window so the details are available even after I have closed the browser window. To polish everything off a ValidationSummary control is added to the ASPX page to display any error information to the user. (See the example for details)
Unhandled Exceptions
Unhandled exceptions may be avoided by implementing a global exception handler. ASP.NET does have a construct to hide unhandled exceptions from the user by turning on CustomErrors in the web.config, but just protecting the user from an ugly screen is not enough. A global exception handler will publish unhandled exception and then show the user a friendly page. (See the example for details)
Best Practices
- Publish exceptions!
- Use try/catch in public methods
- Catch exceptions from specific to general in scope
- Wait to the last minute to handle exceptions. Rethrowing exceptions in the object stack is preferable
- Catch an exception in the low level of the object stack if you can correct the situation
- Use "throw" instead of "throw ex": Using "throw ex" will change the error line number being reported in the call stack in the exception object :(
Resources
- Perform Exception Handling in .NET Exceptionally : Mark Strawmyer
- Part I: Don't Commit Errorcide : Paul Kimmel
- Part II: Don't Commit Errorcide : Paul Kimmel
- Exception Handling in Web Services : Thiru Thangarathinam
- User Friendly Exception Handling : Jeff Atwood
- Managing Unhandled Exceptions in .NET : Kevin McFarlane
- The Perfect 404 : Ian Lloyd