By Mike Gunderloy
See how familiar this scenario sounds: You develop a new Web application and test it exhaustively in-house. Then you deploy it to the client’s server, and mystery errors start cropping up. Of course, Murphy’s Law being what it is, the client’s server is usually in a colocation facility in another state, and the errors are intermittent.
The first thing to do when you’re facing errors of unknown origin is to collect as much information as you can. In this article, I’ll show you how to equip your ASP.NET applications with an error trap as a last resort, and to use it to notify you when something goes wrong.
Introducing the Application Error event
To show you how this works, I’ll create a very simple ASP.NET application. The application is designed to allow the user to specify a filename and download that file from the Web server. Figure A shows the rudimentary user interface I’ve put together for testing.
When the user clicks the button, it executes the code shown in Listing A to download the selected file.
This works well as long as the file that the user requests is in the application’s root directory. But if the user types the name incorrectly or asks for a nonexistent file, the user will get an error message. The goal is to trap this message and send it to the developer of the application.
To do this, I’ll use the HttpApplication object and its Error event. As you can guess from the names, HttpApplication represents an entire Web application, and its Error event is fired whenever there is an untrapped error in the application. ASP.NET uses a special file, global.asax, to hold handlers for Page- and Application-level events. Entering this code (shown in Listing B) for the event will trap any errors in the application and display their information in the user’s browser:
There are a couple of things you should note about this code. First, when the error arrives at this event, ASP.NET will have wrapped it up in an HttpException object. To get at the original event, you can retrieve the InnerException object, as shown in the code. Second, the code uses a StringBuilder object to make for a slightly prettier display of the stack trace. You’ll need to include an Imports statement for the System.Text namespace for this to work.
With this code in place, any error will generate a page like the one shown in Figure B. Reading through the stack trace, you can see exactly where the problem occurred.
Getting the information back
So far, this technique doesn’t help a whole lot. Instead of letting ASP.NET automatically display the error information, the code displays the error information itself. The next step is to pack up the information and send it to someone who might be able to do something about it—namely, the developer of the application. For this, I’ll use the static SmtpMail object. This particular object, which is part of the System.Web.Mail namespace, is one of the hundreds of useful gems buried in the .NET Framework. It enables sending an e-mail message with a single line of code. Listing C shows the modified event handler.
The major change here is this allows information to accumulate in a StringBuilder instead of pushing it out to the Response object. As part of this switch, I’m now using regular breaks between lines instead of HTML: <br> tags. The Send method of the SmtpMail object takes four arguments:
- The e-mail address of the sender
- The e-mail address of the recipient
- The subject line
- The message to send
With these changes, the errors go right back to the developer, and the end user receives a relatively polite message on screen.
One more refinement
There’s one more refinement that you should make to this code before using it. When you’re using any scarce resource, you need to think about the denial of service effects. What would happen if someone started sending requests to the test application for nonexistent files as fast as they could be generated? The developer’s mailbox would quickly fill up with junk mail. To prevent this from happening, you can throttle the sending process back, shown in Listing D, so that it limits the number of messages sent:
The comments in the code should be pretty self-explanatory. The basic idea is to not send an e-mail unless it’s been at least one minute since the previous e-mail. Of course, you might want to adjust that time span up or down depending on how heavily loaded your application is and how much e-mail you’re willing to tolerate if something starts going seriously wrong.
Belt and suspenders
There you have it—a drop-in, application-error routine that you can use in any ASP.NET application. Of course, this should not be your only approach to handling errors, unless you like getting a lot of e-mail. In any application of reasonable complexity, there will be operations that can go wrong, whether this is writing a file or trying to download material from another server.
You should use standard Try/Catch error handling in your application to catch these expected errors. But in those cases that you didn’t think of, or didn’t discover during testing, it’s nice to have this final bit of security.