DataStream
LANGUAGES: C#
ASP.NET VERSIONS: 1.0 | 1.1
Publish Exception Info Anywhere
Publish information about exceptions to a variety of locations with a single line of code using the Exception Management Application Block.
By Brian Noyes
.NET Exceptions provide a great way of managing errors within an application. Exceptions can get thrown anywhere in an application, either from doing something wrong with the .NET Framework or a third-party library, or because something unexpected happened in your application and you decided to throw an appropriate exception. Exceptions will bubble up the stack until a matching exception handler (catch block) is found, freeing you from having to pass error context information up the stack yourself - as was often done in the past using DWORD error codes or booleans as the return values of functions.
The challenge lies in what to do within your exception handling catch blocks. You may have catch blocks in any number of places in your application, hopefully including top-level catch blocks that prevent unhandled exceptions from leaking out of your application. Typically, the first thing you want to do is capture that exception information and stuff it somewhere for debugging or offline diagnostic purposes. That somewhere could be any number of places, including a flat file, XML file, database, or generating notifications through e-mail or instant messaging. Unfortunately, attempting to write out exception information to any of those places can result in an exception as well, leading to nested try-catch blocks that start to litter up your application in a hurry.
This process of publishing the exception information is rarely a core function of your application, but more of an ancillary infrastructure requirement that is necessary to ensure that when problems occur, you can identify, isolate, and fix them. The rest of your catch block may perform application-specific logic, such as aborting transactions, performing compensating transactions, calling clean up routines, etc. There is no good way to abstract out application-specific logic like that in a reusable, generic way. But the process of publishing captured exception information can be handled in a generic and extensible manner, and that is precisely what the Exception Management Application Block (EMAB) provides.
You can read all the details about EMAB and download it from MSDN (http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnbda/html/emab-rm.asp). What you will need to do is download and install EMAB on your development machine. This will add some VS .NET projects and documentation to your machine and will also install a Windows Event Log that EMAB will publish to by default. Once it is on your machine, you'll want to compile either the C# or VB .NET version so you can then reference the resulting class library assembly from other application projects that you build.
One of the Most Useful Lines of Code You Will Ever Write
To use EMAB from application code requires a single line of code in any of your application exception catch blocks:
catch (Exception ex)
{
ExceptionManager.Publish(ex);
}
For this to compile, you'll need to set a reference to the EMAB class library, which you compile from the code installed with EMAB. Once you have added this line of code to your catch blocks, any time an exception gets caught by that block, it will be published by EMAB to whichever publishers you have configured for the application.
OK, so what is a publisher and how do you configure it? Figure 1 depicts the basic flow of the way the ExceptionManager works. First off, you need to have a little information in your application configuration file to identify the configuration section that affects the operation of EMAB. When you call Publish on the ExceptionManager from your application code, it will check in that configuration section for information on where to publish.
Figure 1. When you publish an exception with
EMAB, the ExceptionManager checks in your configuration file to decide to which
publishers to send the information.
So the first thing that is great about EMAB is the fact that it requires so little code in your application. If something goes wrong in the publishing process, EMAB will attempt to output exception information about whatever went wrong to its default publisher, which targets the Windows application event log. If that fails as well, it will just quietly ignore the error. So you don't have to worry about nesting try-catch blocks in your app code to cover any problems during the publishing process.
The other thing that is awesome about EMAB is the extensible design that allows you to plug in any number of publishers, including ones that you write, at run time. Using this capability, you might deploy your application to just write to a database event log of your own. But then, if you are troubleshooting some database problems, you could plug in a new XML file publisher without having to change any application code and have the exceptions dumped to an XML file that is easy to reach out and inspect remotely.
Configure the Block
The
application configuration file entries required are pretty straightforward. The
first thing required is a section entry in the
type="Microsoft.ApplicationBlocks. ExceptionManagement.ExceptionManagerSectionHandler, Microsoft.ApplicationBlocks.ExceptionManagement" /> type="EMABPublishers.DBExceptionLogPublisher" exceptionFormat="xml" serverName="localhost"
dbName="ExceptionLog"/> type="EMABPublishers.ExceptionXmlFilePublisher" exceptionFormat="xml" xmlFilePath="C:\CustomExceptions.xml"/> Figure
2. Your
application configuration file entries provide the glue that ties the
ExceptionManager to the appropriate publishers for outputting exception
information. Note that the type attribute of the section element in the
configSections element has been wrapped; you will need to put that section all
on one line if you want to cut and paste this text. Attributes in XML cannot
have a line break in them. The
attributes required for a particular publisher element depend on the
implementation of that publisher. Each publisher can have any number of custom
attributes that identify information it needs to know in order to publish
exception info, and the publisher will be passed that information whenever an
exception is published. For example, the first publisher shown in Figure 2
publishes to a custom database table, so the publisher info needs to contain
the server name and database name where the table is located. The second
publisher in Figure 2 publishes to an XML file, so it needs to know the path to
the XML file to which it should write. Pick Your Publishing Target The only
"built-in" publisher in EMAB is the one that publishes to an application event
log. The block comes with a sample application that includes a publisher for
XML files and for sending an e-mail. They are fairly limited though, so the
download code for this article includes three additional publishers in a
project called EMABPublishers that should be a little more useful to you in
your production applications. The ExceptionXmlFilePublisher writes out
exceptions to a specified XML file, appending each new exception to the
document as a running commentary. The DBExceptionLogPublisher will publish the
exception information to a custom DB table that can be created with the SQL script
included in the download code. Finally, the SqlExceptionPublisher is a
specialized publisher that just handles SqlExceptions and outputs more
specialized information about the SqlErrors collection that is contained in
those exceptions. See my article Gain
Insight Into SQL Errors for more information on the SqlErrors collection. To
create custom publishers, you just need to create a class that implements one
of two interfaces defined in EMAB: IExceptionPublisher or
IExceptionXmlPublisher. If you implement IExceptionPublisher, your
implementation of the Publish method will just be handed the raw Exception
object that was published from the application's call to
ExceptionManager.Publish and it will be up to your publisher to strip out the
properties and inner exceptions it cares about and publish them appropriately.
If you implement the IExceptionXmlPublisher, your publisher will be passed an
XmlDocument object that already has all of the properties and nested inner
exceptions serialized into it, so that can simply be written out if the default
schema and XML format are acceptable to you. Another
thing to be aware of when using EMAB is that it is recommended that you derive
any custom application exception types from EMAB base class
BaseApplicationException, instead of the normal .NET ApplicationException base
class recommended in the .NET design guidelines. This is because EMAB
BaseApplicationException class will also publish out some valuable additional
context information any time an exception is raised, including the machine
name, the date and time of the exception, the thread and AppDomain identity,
the identity of the account that the app is running under, and a collection of
additional information values that you can stuff anything into. This
information will get automatically collected and published along with your
custom exception, which can be really handy in many scenarios. Final Words of Wisdom If you
find yourself thinking that you don't really need EMAB because you already have
a way of getting your exception information published, and you don't think you
need the flexibility of changing where it goes, think again. I have run into
the situation on more than one occasion where an application was designed with
custom code to output their exception information and the designers thought
they would never have a need to put it out somewhere else. But things go wrong
sometimes, and when they do, options are a good thing to have. Being able to
make your application spit out full details on exceptions to some location and
form never conceived of when the application was designed without changing a
line of application code is a powerful option. It also means that the code in
your application related to exceptions is reduced, which eases your maintenance
burden significantly. Any publishing code you write also becomes easily
reusable on other applications - yet another plus. The
bottom line: I highly suggest you check out EMAB and consider including it in
your current and future applications. The benefits of using it are subtle until
you use it a bit, and then you start to realize you have been doing things the
hard way. The
files accompanying this article are available for download. Brian
Noyes is a
software architect with IDesign, Inc. (http://www.idesign.net),
a .NET focused architecture and design consulting firm. Brian specializes in
designing and building data-driven distributed Windows and Web applications. He
has over 12 years experience in programming, engineering, and project
management, and is a contributing editor and writer for asp.netPRO and other
publications. Contact him at mailto:[email protected].