Developing with the Exception Handling Application Block


The previous section covered the design of the Exception Handling Application Block and how it can be extended through custom ExceptionFormatters and ExceptionHandlers. I went into great detail to cover this, because I feel that it is important for you to know that you aren't constrained to only using the exception formatters and exception handlers that ship with the Exception Handling Application Block. However, if the exception formatters and exception handlers that ship with the block do serve all your needs, then you will have to write very little code to use the block.

Writing code to leverage the Exception Handling Application Block is trivial because most of the processes are handled by the ExceptionPolicy service. The bulk of the work that you need to do is configuring these exception policies, not coding them. This section details how to configure and develop an application to use the features of the Exception Handling Application Block.

Configuring the Exception Handling Application Block

The ExceptionPolicy class uses configuration data to create exception policies that handle predefined exception types with predefined ExceptionHandlers. As is the case with the other application blocks, the Enterprise Library Configuration Tool provides the easiest and least error-prone method for creating and modifying this configuration data.

To add the Exception Handling Application Block, open the application's domain configuration file in the tool, right-click on the application node, and select New > Exception Handling Application Block. Figure 5.10 shows the resulting configuration hierarchy. A new configuration section is added to the nodes underneath the settings for the Configuration Application Block, and a configuration hierarchy has been created to hold the settings for the Exception Handling Application Block.

Figure 5.10. Hierarchy After Adding the Exception Handling Application Block


After the block has been added, the next task is to create the exception policies. An exception policy defines how to handle a specific type of exception that may occur in an application. An application may be configured with many exception policies.

To add an exception policy to an application's configuration, right-click on the Exception Handling Application Block node and select New > Exception Policy. You can configure each exception policy to handle many types of exceptions. To add an exception type to an exception policy, right-click the exception policy node and select New > Exception Type. When you add an exception type to an exception policy, the Enterprise Library Configuration Tool displays the Type Selector dialog to make it easy to add an exception type to an exception policy. The Type Selector dialog will only let you select a class that derives either directly or indirectly from the base Exception class.

Figure 5.11 shows how the Type Selector dialog is used to add an exception type for the System. Exception to an exception policy. This will handle any exception that may occur, because System.Exception is the base class for all exceptions, and when the Exception Handling Application Block looks for a particular exception type, it will navigate up a class hierarchy until it finds a match.

Figure 5.11. Adding an Exception Type to an Exception Policy


Every exception type for an exception policy must be configured with a PostHandlingAction. Table 5.1 listed the values for the PostHandlingAction property. The default is NotifyRethrow. Because this exception will eventually use a WrapHandler to create a new exception, I have changed the PostHandlingAction property to ThrowNewException so the Exception Handling Application Block will throw the new exception that is created by the WrapHandler and return true to the calling application. Figure 5.12 shows where this change is made.

Figure 5.12. PostHandlingAction for an Exception Type


For each exception type in an exception policy, you can configure many exception handlers to run. The combination of the exception handlers, exception types, and exception policies dictate how a specific exception is handled in an application. For example, let's say a distributed, multitiered application is being developed. There are a few different ways to handle any exceptions that might occur in this application. If an exception occurs in the data layer, it may be desirable to simply log the exception and propagate it to the business layer; exceptions at the business layer may be logged and then wrapped in a custom exception before being propagated to the UI layer; in the UI layer, exception messages may be replaced with a user-friendly message before notifying the user. An exception policy can be created for each of these scenarios in the application. Rather than writing code to perform each of these specific tasks, the exception policies just need to be configured to handle specific exception types in specific ways.

Wrapping an Exception

To wrap one exception in another, an exception type should be configured with a WrapHandler. To do this, select the exception type for a particular exception policy, right-click on it, and select New > Wrap Handler. In Figure 5.13, an exception policy named Wrap Policy has been created and configured to wrap an exception with a new System.ApplicationException.

Figure 5.13. Configuration for a WrapHandler


Clicking the ellipses button for the WrapExceptionTypeName property will open the same Type Selector dialog that was used to create the exception type (shown in Figure 5.11). In this case, you use the dialog to specify which type of exception should be created to wrap around the handled exception. The WrapHandler shown in Figure 5.13 will create a new ApplicationException with the original exception as its InnerException and the exception message An exception has occurred and been wrapped inside this exception when an exception of type System.Exception (or a class derived from it) is handled for the Wrap Policy.

Replacing an Exception

Replacing an exception is very similar to wrapping an exception, except that the InnerException is not populated with the original exception that is received. If this policy were changed to use a Replace Handler instead of a WrapHandler, the calling code would not change; it could remain completely untouched. To configure an exception type to use a Replace Handler, select the exception type for a particular exception policy, right-click on it, and select New > Replace Handler.

Logging an Exception

Logging an exception means that exception information is written to some type of storage. The Exception Handling Application Block relies on the Logging and Instrumentation Application Block to determine how and where to log the exception information. The only requirement from the Logging and Instrumentation Application Block is that it can obtain enough information to create an instance of a LogEntry class. Therefore, to configure an exception to use a logging handler, the configuration information listed in Table 5.4 needs to be set in the Exception Handling Application Block.

Table 5.4. Logging Handler Properties

Property

Description

EventID

An Event number or identifier.

FormatterTypeName

The type of ExceptionFormatter to use to format the exception information. (ExceptionFormatters were covered earlier in this chapter.)

LogCategory

The category name that is used to route the LogEntry to one or more log Sinks.

Priority

The importance of the log message. Only messages above the minimum priority are processed.

Severity

LogEntry severity enumeration: Unspecified, Information, Warning, or Error.

Title

Additional description of the LogEntry message.


This configuration information gives the Logging and Instrumentation Application Block all the information that it needs to create a LogEntry. To configure an exception type to use a logging handler, select the exception type for a particular exception policy, right-click on it, and select New > Logging Handler. When a logging handler is configured, the Logging and Instrumentation Application Block is automatically added to the available application blocks if it hasn't already been added.

In Figure 5.14, the Log Only Policy has been configured with a logging handler. The logging handler has been configured to log the exception information with a log Category of Exceptions. This Category has been configured in the Logging and Instrumentation Application Block to use a Flat File Sink, which has been configured to store its information in a file called exceptions.log. See Chapter 6 for more detail about log Categories and log Sinks.

Figure 5.14. Configuration for a Logging Handler (Including Configuration in the Logging and Instrumentation Application Block)


Setting an ExceptionFormatter

Other than the FormatterTypeName property, all the properties that must get configured for the logging handler are used to create a LogEntry for the Logging and Instrumentation Application Block. You use the FormatterTypeName property to configure the ExceptionFormatter that the logging handler uses to write exception information. By default, the logging handler is configured to use the TextExceptionFormatter to write each of the exception's data elements onto a separate line, with the indentation incremented for each exception as it gets further down the stack.

You can change the type of exception formatter by clicking the ellipses for this property. This opens the Type Selector dialog again; however, this time it is only populated with classes that derive from the ExceptionFormatter base class. Choosing one of these classes changes the exception formatter that will be used for that Log Handler. Figure 5.15 shows how to select the custom CsvExceptionFormatter that was created earlier in this chapter.

Figure 5.15. Changing the ExceptionFormatter for a Logging Handler


It is important to note that as the configuration for a particular exception handler changes or an exception policy changes to use different exception handlers, the code to handle these exceptions remains unmodified. Even though the exception formatter for this exception has changed, the code that is needed to use it remains unchanged.

Simple Customized Exception Handling

This chapter has shown the different ways to create a custom exception handler so that it can be used by the Exception Handling Application Block. The first way is to develop a custom exception handler that derives from the ExceptionHandler base class and leverages the existing design-time features for all custom exception handlers. The second method expands upon this; however, instead of relying on the existing configuration and design-time features for a custom exception handler, a strongly typed one can be created.

To add the first kind of custom exception handler to an exception type, select New > Custom Handler. Once the exception handler has been added, you must set its TypeName property to the type of exception handler that will handle this exception. The Type Selector dialog is used to make it easy for you to select the type of exception handler to use. The dialog box is only populated with classes that the Enterprise Library Configuration Tool knows to derive from the base ExceptionHandler class. Figure 5.16 shows how the AppMessageExceptionHandler class is added to the Global Policy exception policy for a System.Exception exception type for an application.

Figure 5.16. Setting the TypeName for a Custom Handler


A custom handler can also use its Attributes property to retrieve additional configuration data. The Attributes property is a NameValueCollection. A custom handler can read the extra configuration data that it needs from this NameValueCollection instead of requiring the existence of a strongly typed configuration schema. For example, the custom handler that is created in the Exception Handling Application Block Quick Start displays "The following exception was caught by the Quick Start Global Exception Handler:" to the end user when an unhandled exception has been caught. However, instead of hard-coding this string in the code, it could have been read from configuration and used via the Attributes property as shown in Listing 5.17.

Listing 5.17. Resulting InnerException by Using the ContextualWrapHandler

[C#] string errorMsg = handlerData.Attributes["ErrorMsg"]; [Visual Basic] Dim errorMsg as String = handlerData.Attributes("ErrorMsg")

For this to work, the Attributes property would have to be populated with an item named ErrorMsg. The Enterprise Library Configuration Tool provides a NameValueItem Collection Editor to make adding and configuring NameValue items easy. Figure 5.17 shows how to use the NameValueItem Collection Editor to configure the Attributes property with the needed ErrorMsg item.

Figure 5.17. Setting Attributes for the AppMessageExceptionHandler


Advanced Customized Exception Handling

The drawback to using a NameValueCollection to specify configuration settings is that it is more error-prone because no validation can be done on the items contained in the collection when it is being configured. You won't know until runtime if an error has been made with the configuration data that is set through the Attributes property.

An alternative is to provide a more advanced custom exception handler that uses strongly typed configuration data and design-time classes that work the same way that the WrapHandler, ReplaceHandler, and LoggingExceptionHandler do. Adding and using an advanced custom exception handler is similar to adding and using any of the exception handlers that ship with the application block. Right-click on the exception type for an exception policy and select the new custom exception handler (refer back to Figure 5.9 for an example of creating a custom exception handler of this type).

Chaining Exceptions

Exception handlers can be chained together to perform multiple actions when an exception occurs. You do this by adding multiple exception handlers to an exception type. The order in which the handlers execute is the order in which the exception handlers occur in the configuration. For this reason, there are additional menu options to move an exception handler up and down in its hierarchy in the configuration. Figure 5.18 displays a Global Policy that chains together a Replace Handler and a custom handler named Notification Handler. Since it is generally a good idea to replace an exception before notifying end users about the exception, the Replace Handler should occur before the Notification Handler in the configuration hierarchy. Figure 5.18 shows how to move the Replace Handler up in the hierarchy.

Figure 5.18. Moving a Handler Up in the Chain so It Is Executed First


As previously discussed, any handler in the chain can change the exception before it gets passed to another handler. Exception handlers receive the exception that is returned from the previous handler. The first handler in a chain will always receive the original exception, and the last handler in the chain will always produce the exception that may be returned to the application.

Using the Exception Handling Application Block's API

Writing code for an application so that it can use the Exception Handling Application Block is extremely straightforward. The only code you need to write is to call the ExceptionPolicy's static HandleException method. This method expects the exception that was caught by the calling application and the name of an exception policy that has been configured to handle this exception.

For example, Listing 5.18 displays the kind of code you would need to write if you're not using the Exception Handling Application Block. In this example, a data access routine is used to populate and return a typed DataSet in an application's business layer. If an exception occurred during this process, code might have been written to wrap this exception before propagating it. When the exception gets propagated, some other code may display the exception to an end user or log the exception somewhere or both.

Listing 5.18. Handling an Exception without the Exception Handling Application Block

[C#] try {    return GetAnnouncements(moduleId); } catch (Exception ex) {     String formattedInfo = FormatException(ex);     BusinessLayerException businessLayerException =          new BusinessLayerException          ("Failed to retrieve necessary data", ex);     Throw(businessLayerException); } [Visual Basic] Try   Return GetAnnouncements(moduleID) Catch ex As Exception   Dim formattedInfo As String = FormatException(ex)   Dim businessLayerException as BusinessLayerException = _       new BusinessLayerException _       (""Failed to retrieve necessary data", ex)   Throw businessLayerException End Try

This is not bad code. It is perfectly acceptable to handle exceptions this way. However, if it is likely that the behavior will change or the behavior could be reused in many places, externalizing the behavior via the Exception Handling Application Block can make a lot of sense. If you use the Exception Handling Application Block, you don't need to write any code to create and throw a particular exception. Instead, this responsibility can be delegated to the Exception Handling Application Block. Thus, the code in Listing 5.18 can be rewritten as shown in Listing 5.19 to notify the block which exception occurred and which policy should be executed.

Listing 5.19. The Exception Handling Application Block Determines How to Handle Exceptions

[C#] try {     return GetAnnouncements(moduleId); } catch (Exception ex) {     bool rethrow = ExceptionPolicy.HandleException                     (ex, "Business Layer Policy");     if (rethrow)          throw; } [Visual Basic] Try       Return GetAnnouncements(moduleID) Catch     Dim rethrow As Boolean = ExceptionPolicy.HandleException _                               (ex, "Business Layer Policy")     If (rethrow) Then         Throw     End If  End Try

This has the distinct advantage that the way an exception is handled is separated from the code that initiates the exception handling process. If sometime later it is deemed necessary to change the behavior for how the exception is handled, then no code would need to be changed. For example, if this exception is currently being wrapped or replaced with another exception, but later it is decided that the exception also needs to be logged before it is replaced and then someone should be notified about the exception, no code would need to be changed. All the changes are made in the configuration data for the exception policy.




Fenster Effective Use of Microsoft Enterprise Library(c) Building Blocks for Creating Enterprise Applications and Services 2006
Effective Use of Microsoft Enterprise Library: Building Blocks for Creating Enterprise Applications and Services
ISBN: 0321334213
EAN: 2147483647
Year: 2004
Pages: 103
Authors: Len Fenster

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net