Instrumentation means to add code to an application that lets you know how your application is performing in a deployed environment, and application blocks are smaller sub-frameworks that solve a category of problem. Two application blocks I have used recently are Microsoft's Data Access Application Block (DAAB) and Exception Management Application Block (EMAB).
In this article, I will describe how to use Microsoft's Exception Management Application Block to instrument your code, making it exceptionally easy to keep tabs on the exceptions your applications are throwing. To be clear, I know you clever programmers out there are capable of using the EventLog, logging to files, and databases, but the EMAN is an extension of basic logging that is well-crafted, sound, and it already exists. If you are interested in learning how to write to the EventLog explicitly or streaming event information to files and databases because you are in learning mode, that's great. Learning is fun. However, if you're interested in producing professional results as quickly and cost efficiently as possible, this article will show you how to instrument your code for logging exceptions, demonstrate how to use a great application block, and you might learn a few things about the .NET framework on your journey. I did.
What's in the Exception Management Application Block?
The Exception Management Application Block can be downloaded and installed from Microsoft's Web site. I won't list all of the code here because it is pretty involved, and you can explore this part yourself. Instead, we will take a cross-section of the application block to show you how to start using and extending it.
The EMAB has three significant pieces. (Keep in mind I am editing a bit, but these are the important pieces.) Publishers implement the IExceptionPublisher interface defined by the Microsoft.ApplicationBlocks.ExceptionManagement.dll. Publishers are the pieces of code that actually write to a repository. The second piece is the ExceptionManager class. Requests to log exceptions are routed through the static method ExceptionManager.Publish(exception). The third piece is the App.config file. The .config file is used to tell the ErrorManager which publisher to use after deployment. This means that you can implement new IExceptionPublishers, and deploy them after your application has been instrumented and deployed to your consumers.
Using the DefaultPublisher
The EMAB ships with a sample application that demonstrates how to implement a FileStream publisher—a text file—and contains a DefaultPublisher. The DefaultPublisher is the EventLog. By default, if you just ship the EMAB with your application without adding to it and call ErrorManaged.Publish(exception), entries are published to the local computer's EventLog.
A reasonable person may say "Hey, I can do that with the EventLog.WriteEntry shared method in the System.Diagnostics namespace. Why do I need the application block?" The answer is that the EventLog class by itself doesn't support multiple logging to other sources such as databases, and the EventLog is not designed to be externally configurable. The application block is, though, and Microsoft has accepted the cost of ownership of the application block. You and I have to do very little. It is important that when you are writing code for money that this is understood to be a freebie.
If we want change publishers, we realize—inherit from the interface—IexcetpionPublisher and define a Publish method. The nuts and bolts of reading an external XML App.config file are adroitly and professionally handled by Microsoft. Here is what we'd have to do to make an externally configurable section in an App.config file. First, we would have to define the XML schema. Next, we'd have to define a class that maps to the XML schema in the configuration file unless it is acceptable to read a .config file in an ad hoc way (not especially professional to ignore the framework due to a lack of understanding). Finally, we'd have to implement the IConfigurationSectionHandler. Classes that implement this interface can be used to map XML data to objects. Very useful and very professional.
On top of mapping an XML App.config file section to an object, Microsoft has coded some fallback behavior. For example, they wrote the code that uses Reflection to load assemblies dynamically permitting us to change, add, or multicast to publishers on the fly, and Microsoft has implemented the application block so that if a custom publisher fails, the default publisher will publish the original error and a second exception indicating why your custom publisher failed. This is a lot of good work, and it's free.
Using the application block couldn't be easier. All we need to do is add a reference to the application block assemblies Microsoft.ExceptionManagement.ApplicationBlocks.dll and Microsoft.ExceptionManagement.ApplicationBlocks.Interfaces.dll, add an Imports statement to the application block, and call ErrorManager.Publish, passing an exception to the Publish method. Listing 1 shows you how to do it.
Listing 1: Logging an exception.
Imports Microsoft.ApplicationBlocks.ExceptionManagement Public Class Form1 Inherits System.Windows.Forms.Form [ Windows Form Designer generated code ] Private Sub Button1_Click(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles Button1.Click Try ' Simulates an exception Throw New Exception("This is an error!") Catch ex As Exception ExceptionManagement.Publish(ex) End Try End Sub End Class
Catching an exception and publishing it is all there is to using this application block.
Another benefit of the application block is that the EMAB already adds additional information to the basic exception. The additional logged information includes the machine name, a timestamp, the application domain name (the application that threw the exception), the thread, the Windows identity (or user), the contents of the exception, and the call stack trace. Figure 1 shows the logged exception in the event viewer—Started|Run Eventvwr.msc—and Figure 2 shows some of the generous detail logged on our behalf as part of the default behavior of the EMAB, regardless of the type of the publisher.
Figure 1: An exception logged to the default publisher.
Figure 2: A bit of the detail added to an exception logged by the Exception Management Application Block.
Easy, isn't it? That's exactly what you want. When you are getting code, even for free, you want that code to be helpful and relatively easy to use. Good code should hide its complexity, and the EMAB does this well.
Reviewing the App.config File
The App.config file is an XML file that contains application configuration information. The ExceptionManagementQuickStartSamples—shipped with the EMAB—contains a sample App.config file. App.config files are converted to executablename.exe.config by Visual Studio .NET when you compile your project. The sample App.config file that ships with the samples demonstrates how to configure several possible publishers. Listing 2 contains an excerpt from that file, followed by a discussion of the salient elements. (The sample App.config also contains commented text that will describe the configuration samples.)
Listing 2: An excerpt from the sample App.config file.
<?xml version="1.0" encoding="utf-8" ?> <configuration> <configSections> <section name="exceptionManagement" type="Microsoft.ApplicationBlocks.ExceptionManagement. ExceptionManagerSectionHandler,Microsoft. ApplicationBlocks.ExceptionManagement" /> </configSections> <!-- Default publisher explicitly enabled--> <!--<exceptionManagement mode="on" />--> <!-- Default publisher explicitly disabled--> <!--<exceptionManagement mode="off" />--> <exceptionManagement mode="on"> <publisher assembly="ExceptionManagementQuickStartSamples" type="ExceptionManagementQuickStartSamples.ExceptionPublisher" fileName="c:\QuickStartSamplesExceptionLog.txt" /> </exceptionManagement> </configuration>
Worth noting is that you can use the application block without an App.config file. If you do, the DefaultPublisher—EventLog—will be used to log events. The next item worth noting is that you can configure more than one publisher at a time. This means that you can multicast exceptions to more than one publisher at a time. So, how do we configure publishers explicitly?
The App.config file needs a <configSections> element. This element contains the name of an assembly and a class that implements the IConfigurationSectionHandler. The <configSections> element defines the assembly and class to load to read and objectify in the name attribute of the <section> element. In the listing, the <section> element is interpreted to mean that elements named <exceptionManagement> should load the Microsoft.ApplicationBlocks.ExceptionManagement.dll assembly and create an instance of ExceptionManagerSectionHandler to read and create an object from <exceptionManagement> blocks. (Keep in mind that XML is case-sensitive.) The result is that the CLR reads App.config files, and when it comes to sections named <exceptionManagement> it uses the IConfigurationSectionHandler to figure out what to do with the XML in this section. What it does as defined in the EMAB is create an ExceptionManagerSectionHandler object whose properties are the values defined in the element.
If we examine the <exceptionManagement> element in Listing 2, we will see an attribute named mode. Mode indicates which <exceptionManagement> element contains the configured publishers. Finding the on block, the EMAB reads all of the publishers and will multicast to each listed publisher. As with the <configSections> block, the <publisher> element simply indicates the name of the assembly to load, the class that implements IExceptionPublisher, and attributes that are passed as arguments to the publisher. The result is that the CLR uses Reflection to load the assembly, and creates an instance of the IExceptionPublisher initializing the object with the XML attributes. In a nutshell, the XML file dynamically tells the EMAB what publisher to use and how to initialize it when your code calls ExceptionManager.Publish.
Taking an excerpt from Listing 2, we can determine that the quick start sample has a publisher defined in an assembly named ExceptionManagementQuickStartSamples. The class of the publisher is ExceptionPublisher, and the filename attribute indicates that a file C:\QuickStartSamplesExceptionLog.txt is involved and suggests that this particular sample publisher publishes to a file. In fact, it does. Extrapolating from the example, then, publishing to your company's help desk would be a matter of including an e-mail address as an attribute and mailing the exception text to that address using a feature such as Smtp.send. (Implementing the email publisher is left as an exercise for the reader.)
Instrumenting your code means in part to add lines of code that make it easy to see what is going on after you deploy your applications. The Exception Management Application Block provides you with an easy to use, flexible, exception logging tool that solves many of the technical complexities and is easy to use.
Personally, I am a do-it-yourselfer when it comes to writing code. However, when I am writing code for my customers, I have to be judicious about how I spend their money. The exception management application block makes too much sense and is just too good a tool to pass up.
About the Author
Paul Kimmel has written several books on Visual Basic, including the recently released Visual Basic .NET Power Coding from Addison Wesley. Pick up your copy at www.amazon.com. Paul is also available for short- and long-term consulting and .NET training. You may contact him at firstname.lastname@example.org.
# # #