How To: Design Exception Management

J.D. Meier, Alex Homer, David Hill, Jason Taylor, Prashant Bansode, Lonnie Wall, Rob Boucher Jr, Akshay Bogawat.

Objectives

  • Learn how to detect exceptions.
  • Learn how to handle exceptions.
  • Learn how to log exception information.
  • Learn how to notify exceptions.

Summary of Steps

  • Step 1 – Identify exceptions that you want to handle.
  • Step 2 – Determine your exception detection strategy.
  • Step 3 – Determine your exception propagation strategy.
  • Step 4 – Determine your custom exception strategy.
  • Step 5 – Determine how to handle unhandled exceptions.
  • Step 6 – Determine appropriate information to gather.
  • Step 7 – Determine your exception logging strategy.
  • Step 8 – Determine your exception notification strategy.

Step 1 – Identify exceptions that you want to handle

When designing exception management for your application, it is important to identify the exceptions that you want to handle.
  • Identify the system or application exceptions that you want to handle. These are exceptions such as accessing system resources for which the user does not have permission, system failures due to disk, CPU, or memory issues.
  • Identify the business exceptions you want to handle. These are exceptions such as violating business rules.

Step 2 – Determine your exception detection strategy

Your design should mandate that structured exception handling is used consistently throughout the entire application. This creates a more robust application that is less likely to be left in an inconsistent state. Structured exception handling provides a control structure. You can use try, catch, and finally blocks to detect exceptions thrown within your code, and react to them appropriately.

Key considerations when detecting exceptions are:
  • Only catch the exception when you must perform any of the following tasks:
    • Gathering exception details for logging.
    • Adding relevant and additional information to the exception.
    • Cleaning up any resources used in the code block.
    • Retrying the operation to recover from the exception.
  • Do not catch an exception and allow the exception to propagate up the call stack, if you do not have any task to accomplish.

Step 3 – Determine your exception propagation strategy

The following list describes exception propagation strategies. Your application can (and should) use a mixture of any or all of these strategies depending on the requirements of each context.

Consider the following strategies and decide which make sense for each context:
  • Allow Exceptions to Propagate. With this strategy, you do not do anything with the exception; you deliberately ignore the exception and let it propagate through the code stack. This strategy is useful when you do not want to add specific information to the exception.
  • Catch and Re-throw Exceptions. With this strategy, you catch the exception, carry out some other processing, and then re-throw it. Usually, in this approach, the exception information remains unaltered. This strategy is useful when you have to clean-up resources, log exception information, or if you need to attempt to recover from the error.
  • Catch, Wrap and Throw Exceptions. With this strategy, you catch generic exceptions, react to it, clean-up resources, or perform any other processing. If you cannot recover, wrap the exception within another exception that is more relevant to the caller, and then throw the new exception so that it can be handled by code higher in the code stack. This strategy is useful when you want to keep the exception relevancy and to provide information to the exception handling code.
  • Catch and Discard Exceptions. This is not the recommended strategy, but might be suitable for some specific scenarios. You catch the exception and proceed with normal application execution. If required, you can log the exception and perform resource cleanup. This strategy is useful for system exceptions that do not impact user operations, such as an exception raised when a log is full.

Step 4 – Determine your custom exception strategy

The following are the key steps for designing custom exceptions:
  • Determine your exception hierarchy. When designing your exception management strategy, you should create an exception hierarchy for organizing the exceptions. This helps to quickly analyze and trace problems. When deciding on a exception hierarchy, you should classify your exceptions to:
    • Indicate the layer in which the exception occurred.
    • Indicate the component in which the exception might have occurred.
    • Indicate the type of exception that occurred, such as a security, system, or business exception.
  • Determine if you need a custom exception. Consider the following guidelines when deciding if you need a custom exception:
    • Do not use custom exceptions if the exception is already available in your exception hierarchy or the .NET Framework.
    • Use custom exceptions if your application must handle a specific exception instead of using a generic exception to avoid using conditional logic.
    • Use custom exceptions if your application must include additional information or functionality to suit a specific requirement.
Consider storing your applications exception hierarchy in a single assembly that can be referenced throughout your application code. This helps to centralize the management and deployment of your exception classes.

Creating a Custom Exception Class

If you need to create a custom exception class, you should always end your custom exception class name with "Exception". Additionally, you should provide three constructors for your custom exception class. This is important to fit in with the standard exception mechanism. The following code provides an example:
public class YourBaseApplicationException : ApplicationException
{
   // Default constructor
   public YourBaseApplicationException ()
   {
   }
   
   // Constructor accepting a single string message
   public YourBaseApplicationException (string message) : base(message)
   {
   }
   
   // Constructor accepting a string message and an 
   // inner exception which will be wrapped by this 
   // custom exception class
   public YourBaseApplicationException(string message, 
            Exception inner) : base(message, inner)
   {
   }
}

Consider how to marshal exceptions across boundaries

The Exception class implements the ISerializable interface, allowing it to manage its own serialization. To allow your exceptions to be marshaled across remoting boundaries, you must add the Serializable attribute to your class and include the additional constructor shown below:
protected YourBaseApplicationException(SerializationInfo info,
                        StreamingContext context) : base(info, context)
{
}

Step 5 – Determine how to handle unhandled exceptions

When an exception is not handled until the last point or boundary, and there is no way to recover from the exception before returning control to the user, your application must handle this unhandled exception.

The strategy for handling such unhandled exceptions is:
  • Gather the required information.
  • Log the exception information.
  • Send any notifications.
  • Perform any clean-up required.
  • Communicate the error information to the user.

When communicating the error information to the user, you should not expose all of the exception details. Instead, you should provide a user-friendly generic error message. In the case of clients that have no user interface, such as Web services, you might choose to throw a generic exception in place of detailed exception. This prevents system details from being exposed to the end-user.

Step 6 – Determine appropriate information to gather

When handling exceptions, one of the most important aspects is to have a sound strategy for gathering exception information. The information captured should accurately represent the exception condition. It should also be relevant and informative to the audience. Audiences usually fall into one of the three categories: end users, application developers, and operators. Analyze the audience you are addressing by looking into the scenario and individual context. Use the following guidelines as a key to providing your audience with relevant information.
End users require a meaningful and well-presented description. When gathering exception information for end users, consider the following:
  • Provide an indication when a request or process fails.
  • Provide a user-friendly message that indicates the nature of the error.
  • Provide information on how to recover from the error, if this is appropriate.
Application developers require more detailed information in order to assist with problem diagnosis. When gathering exception information for application developers, consider following:
  • Provide the date and time that exception occurred
  • Provide the precise location in the code where the exception occurred.
  • Provide exception details such as the exception type, and state of the system when the exception occurred.
  • Provide the ability to generate extra debug information in exceptions for developers working directly on the application, as opposed to developers using the application as a service in their own application.
Operators require relevant information that allows them to react appropriately and take the necessary recovery steps. When gathering exception information for operators, consider following:
  • Provide the date and time that exception occurred
  • Provide exception details such as the exception type, and state of the system when the exception occurred.
  • Provide knowledge that will assist operators to locate the people to notify and the information they will require.

Irrespective of the audience that will receive the exception information, it is useful to provide rich exception information. Store the information in a log file for later examination, and comparison of exception frequency and details. By default, you should capture at least following information:
  • Date and Time that the exception occurred
  • Machine Name where the exception occurred
  • Exception Source
  • Exception Type
  • Exception Message
  • Exception Stack Trace
  • Call Stack
  • Application Domain Name
  • Assembly name where the exception occurred
  • Assembly version name where the exception occurred
  • Thread ID on which the exception occurred
  • Thread User for whom the exception occurred

Step 7 – Determine your exception logging strategy

There is a range of options available for logging exception information. The following key considerations will help you to choose a logging option:
  • Choose Windows Event Log or Windows Eventing 6.0:
    • When your application is deployed on a single machine.
    • When you need to leverage existing tools to view the log.
    • When reliability is a prime concern.
  • Choose a SQL Database:
    • When your application is deployed in a farm or cluster.
    • When you need to centralize your logging.
    • When you need flexibility as to how the exception information is structured and logged.
  • Choose a custom log file:
    • When your application is deployed on single machine.
    • When you need complete flexibility for choosing the log format
    • When you want simple and quick log store.
  • Choose Message Queuing as a delivery mechanism to pass exception messages to their final destination:
    • When reliability is your prime concern.
    • When your applications are deployed in farm or cluster.
    • When you need to centralize logging.

For any application, you can choose a mix of these options depending upon your scenario and exception policy. For example, security exceptions may be logged to the Security Event Log and business exceptions may be logged to database.

Step 8 – Determine your exception notification strategy

As part of your exception management design, you must also decide on your notification strategy. Exception management and logging are often not sufficient in enterprise applications. You should consider complimenting them with notifications to ensure that exceptions do not go un-noticed by administrators and operators.

The following steps provide guidelines for designing notifications:
  1. Identify your notification policy. Identify the business-critical or system-critical exceptions that require immediate attention.
  2. Determine your notification strategy. The following options exist for error detection and raising notifications:
  3. External Notification mechanisms. Create a log monitoring system or use an existing or third-party environment that detects the error conditions in the log data and raises appropriate notifications. This is a good choice when:
    • You want to decouple your monitoring and notification system from your application code
    • You want to keep the core application code clean and have just logging code.
  4. Application built-in notification mechanisms. The application code itself raises appropriate notification when it encounters an error condition. This is a good choice when:
    • You want to generate immediate notifications.
    • You do not want to rely on other monitoring systems.
  5. Determine your notification mechanism. The following options exist for notifying administrators and operators of critical exceptions:
  6. WMI events. The WMI event infrastructure provides the ability for applications to raise WMI events that can be monitored and handled: This is a good choice when:
    • You want to decouple the operational procedures carried out as a result of an unhandled exception from your application code.
    • You want to design an enterprise-wide notification system.
  7. SMTP email. Send email to a distribution list that includes the appropriate support personnel. This approach is common, but is not the most robust or stable choice. This a good choice when:
    • You want to implement a quick and easy notification solution.
  8. SMS text messages. Send an SMS message to a distribution list that includes the appropriate support personnel. This is a good choice when:
    • Administrators and operators may not be on site, may not have access to email, or may be using an email reader mechanism that does not automatically notify them of incoming email.
  9. Custom notification system. This approach might use transactional queuing to deliver notification messages to other locations. This is a good choice when:
    • You must create a robust, asynchronous, and reliable notification system.
    • You want to decouple notification from your application code.

Additional Resources

Last edited Dec 17, 2008 at 7:40 PM by prashantbansode, version 1

Comments

No comments yet.