ASP.NET 2.0 comes equipped with a new system that allows for the raising of health monitoring events (also referred to as web events). The main benefit of this system is that because it is completely manageable through configuration files. Operations and other IT staff can monitor the health of deployed web applications without the direct intervention of developers. The health monitoring system is composed of two primary components:
Events and providers are linked together in your application's Web.config file. Event types are assigned to named groups in the Web.config's <eventMappings> element. By default, ASP.NET already has several event providers defined as well as event groups.
Table 31.1 shows the web events that come with ASP.NET 2.0.
ASP.NET 2.0 also contains several default web event providers. Those providers are described in Table 31.2.
By default, very little of this system is configured. If you don't specify any other web event information in your application's Web.config file, your application will send the All Errors and Failure Audits events to the EventLogWebEventProvider class.
Using the Health Monitoring System
Using the health monitoring system really boils down to manipulating the Web.config file to determine which events are handled by which event providers. As mentioned earlier, errors and failure audits are sent to the system event log by default. Using the Web.config file, you can use additional ASP.NET Web Event providers to handle additional event types.
This section shows you how to use a SQL Server 2005 database table as the destination for error events such as unhandled exceptions. Although the system event log might be handy in a few circumstances, storing all application errors in a central location that can be queried from remote locations is extremely useful. For example, if your application is running in a web farm scenario (multiple web servers hosting the same application), you will want all of the errors to be accessible in the same place and tagged with the name of the machine that originated the error. Logging errors using the SqlWebEventProvider does exactly that.
To start, create a new ASP.NET web application and add a Web.config file to the project. The SQL Web Event provider uses a table called aspnet_WebEvent_Events that is created when you create an application services database using the aspnet_regsql.exe tool.
Listing 31.1 contains the modified Web.config that will utilize the SQL Web Event provider.
Listing 31.1. A Web.config File Supporting Web Event Persistence in SQL Server
Next, add the following line of code to your default.aspx.cs file:
throw new ApplicationException("test error");
When you run the application, you will get the application exception and VS 2005 will break. Continue execution and then wait a minute or two. Because the SqlWebEventProvider class uses a buffered system, the error won't appear within the database immediately. Figure 31.1 shows the contents of the aspnet_WebEvent_Events table after an error occurs.
Figure 31.1. Storing web errors in SQL Server.
Also shown in this figure are lifetime events. Lifetime events indicate significant changes that occur in an application's lifetime such as application startup and shutdown. This information can be important when diagnosing problems with a production server. To support lifetime events in your application, change the preceding Web.config to the one shown in Listing 31.2.
Listing 31.2. A Web.config File Supporting Both Errors and Lifetime Events
This configuration file adds a new entry to the <eventMappings> section indicating that events in the group "Lifetime" are of the type WebApplicationLifetimeEvent. The <rules> section indicates that all events in the group "Lifetime" are to be handled by the SqlWebEventHandler class. This provides the necessary hooks to get information like application startup and shutdown stored in the SQL Server database.
If you are a tinkerer or just curious, you might try to raise these events manually instead of letting ASP.NET handle them on your behalf. This can't be done, however. All of the default web event classes have an internal protection level so that they cannot be instantiated by code outside the System.Web assembly. This is done deliberately to ensure that only the ASP.NET engine can manually raise the default events. If you want to raise custom events, the next section, "Creating Custom Events," should prove helpful.
Creating Custom Events
Before getting into the details of how to create a custom event, it is important to know when custom events should and should not be created. One important factor to keep in mind is that the developer does not have explicit control over when ASP.NET raises its own default custom events outside of defining event mappings and rules in the Web.config file. In other words, a programmer cannot explicitly raise an "Application Startup" event through code. The following guidelines should help you make the decision as to when to create a custom event:
A common pitfall that a lot of people run into is that they create a web event that inherits from an existing base event, and then manually fire that event in the same place where ASP.NET would have automatically fired it. For example, if a developer overrides the WebErrorEvent and calls the Raise() method within the catch portion of a TRy/catch block, she is essentially reinventing the wheel. In this situation, the only reason a developer should take manual control over raising such error events is if the developer needs to store more information in the event than the default ASP.NET WebErrorEvent class provides.
The next sample will illustrate the use of a custom web event that will get signaled when a user of a research department's website requests a search. As you'll see in the next section on creating a custom provider, this request can then either be handled automatically via web services or dispatched to a research department employee.
Add a new Class Library project to the solution that contains the website from the previous samples. Add a reference to the System.Web Assembly and add a class to the project called AsyncSearchRequest. Listing 31.3 shows the class that inherits from WebBaseEvent.
Listing 31.3. The AsyncSearchRequest Class
The constructors were created so that you can see where you can inject your own code into the instantiation process. The FormatCustomEventDetails method is used to provide additional text data that will be logged with the event when sent to a provider.
One of the most powerful features of the new ASP.NET Web Management system is that you can plug any of your custom events into any of the existing event providers or any custom providers that you or a third party create.
Listing 31.4 contains a new Web.config for the web application that associates the newly created custom event with the SQL Server Web Event provider.
Listing 31.4. A Modified Web.config File Supporting Custom Web Events
To raise this event, you need to do it manually using the Raise() method on the custom event class. Because this class isn't part of the default ASP.NET framework, it won't raise events unless your code forces it to happen, as shown in the following example:
SampleEvents.AsyncSearchWebEvent searchEvent = new SampleEvents.AsyncSearchWebEvent( "Search Requested", this, WebEventCodes.WebExtendedBase + 1); searchEvent.SearchCriteria = "C#; searchEvent.Raise();
Every event requires an event code in order to be raised. Event codes less than 100,000 are the sole property of ASP.NET and cannot be used by custom events. Therefore, your event codes should start at WebExtendedBase and increment from there. Event codes above 100,000 can be reused by any event. After running the preceding code and waiting a few minutes for the event buffer to flush, you will see a new event appear in the aspnet_WebEvent_Events table. The Details column contains the following text:
Event code: 100001 Event message: Search Requested Event time: 1/22/2006 1:45:07 PM Event time (UTC): 1/22/2006 8:45:07 PM Event ID: a0569b9574994157826690f25b38c13f Event sequence: 7 Event occurrence: 1 Event detail code: 0 Application information: Application domain: c1085da7-1-127824362038281250 Trust level: Full Application Virtual Path: /HealthMonitor1 Application Path: C:\Documents and Settings\Kevin\My Documents \Writing\SAMS\C# 2005 Unleashed\31\Code\HealthMonitor1\ Machine name: LAB01 Custom event details: -- Custom Event Data -- Search Critera: C# Event Raised On: 1/22/2006 1:45:07 PM
Creating Custom Event Providers
To illustrate how to create a custom Web Event provider, this section will show you how to create a Research Dispatch provider that handles AsyncSearchWebEvent events and dispatches them accordingly. To create a basic Web Event provider, create a class that inherits from the base class BufferedWebEventProvider (you can create an unbuffered one, but this sample uses a buffered provider to provide a comparison with the buffered SqlWebEventProvider class). To see this in action, add a new class called SearchWebEventProvider to the class library that contains the AsyncSearchWebEvent class. This class is shown in Listings 31.5.
Listing 31.5. A Simple Custom Web Event Provider
The code for the provider itself isn't very complex. The complexity can come from choosing the storage medium or notification medium used when handling the event. The preceding sample shows how you can create a simple provider shell to be used with the search event.