The Web Events feature in ASP.NET 2.0
One of the major new services provided in ASP.NET 2.0 is the Web
Events feature provided by the health monitoring system. By modifying the
Web.config file, you can use the health monitoring system to log unhandled
exceptions, expired forms, authentication tickets, and any other data you want
logged in your application. This column will get you started using the Web
Events feature, and will also provide examples of how to use the various
providers in ASP.NET 2.0.
Logging is accomplished by defining a rule
that associates events with a provider. The rule defines the type of events
that are sent to the provider. The following base events are available for you
to log:
WebBaseEvent | The base event class for all events. Contains the
required properties for all events such as event code, event detail code, the
date and time the event was raised, sequence number, the event message, and
event details. |
WebManagementEvent | The base event class for management events, such as
application lifetime, request, error, and audit events. |
WebHeartbeatEvent | The event generated by the application in regular
intervals to capture useful runtime state information. |
WebAuditEvent | The base class for security audit events, which are used
to mark conditions such as authorization failure, decryption failure, etc. |
WebRequestEvent | The base class for all informational request events. |
WebBaseErrorEvent | The base class for all events indicating error
conditions. |
The types of providers available allow you to send event output
to Event Viewer, SQL Server, Windows Management Instrumentation (WMI), and
e-mail. The pre-configured providers and event mappings reduce the amount of
work necessary to get event output logged.
ASP.NET 2.0 uses the Event
Log provider out-of-the-box to log events based on application domains starting
and stopping, as well as logging any unhandled exceptions. This helps to cover
some of the basic scenarios. For example, let's say that your application
throws an exception, but the user doesn't save the error and you can't
reproduce it. With the default Event Log rule, you would be able to gather the
exception and stack information to get a better idea of what kind of error
occurred. Or, if your application is losing session state, you can look in the
Event Log to determine whether the application domain is recycling, and why the
application domain stopped in the first place.
Also, the health
monitoring system is extensible. For example, you can define custom Web events,
fire them within your application, and then define a rule to send the event
information to a provider such as your e-mail. This allows you to easily tie
your instrumentation to the health monitoring providers. As another example,
you could fire an event each time an order is processed and set up a rule that
sends each event to the SQL Server database. You could also fire an event when
a user fails to log on multiple times in a row, and set up the event to use the
e-mail-based providers.
The configuration for the default providers
and events is stored in the global Web.config file. The global Web.config file
stores all the Web-based settings that were stored in the Machine.config file
in ASP.NET 1x. The global Web.config file is located in the following
directory:
%windir%\Microsoft.Net\Framework\v2.0.*\config\Web.config
The <healthMonitoring> section of the global Web.config file
provides default configuration settings. You can override these setting or
configure your own settings by implementing the <healthMonitoring>
section in the Web.config file for your application.
The
<healthMonitoring> section of the global Web.config file contains the
following items:
- providers Contains providers set up for the Event Viewer, WMI, and SQL
Server.
- eventMappings Contains mappings for the various WebBase classes. You can extend
this list if you generate your own event class. Generating your own event class
gives you finer granularity over the providers you send information to. For
example, you could configure unhandled exceptions to be sent to SQL Server,
while sending your own custom events to e-mail.
- rules Links the eventMappings to the provider.
- buffering Used with SQL Server and e-mail providers to determine how often
to flush the events to the provider.
Below is a code example from the global Web.config file.
<healthMonitoring>
<!-- Event Log Provider being added. -->
<providers>
<add name="EventLogProvider" type="System.Web.Management.EventLogWebEventProvider,System.Web,Version=2.0.0.0,Culture=neutral,PublicKeyToken=b03f5f7f11d50a3a" />
</providers>
<!-- Event mapping provides a friendly name to the events based on the WebBaseErrorEvent class. -->
<eventMappings>
<add name="All Errors" type="System.Web.Management.WebBaseErrorEvent,System.Web,Version=2.0.0.0,Culture=neutral,PublicKeyToken=b03f5f7f11d50a3a"
startEventCode="0" endEventCode="2147483647" />
</eventMappings>
<!-- Rule tying the "All Errors" event mapping to the EventLog Provider. -->
<rules>
<add name="All Errors Default" eventName="All Errors" provider="EventLogProvider"
profile="Default" minInstances="1" maxLimit="Infinite" minInterval="00:01:00"
custom="" />
</rules>
</healthMonitoring>
Provider sample
This provider sample contains the following files:
- The ViewEvents.aspx file � Triggers the MyEvent custom web event in Page_Load and Log Event button click event. Has a GridView that uses the database connection in the
Web.config file to list the events logged to SQL Server.
Be sure to
configure the connectionString in the Web.config file to point to your ASPNETDB database. - The Web.config file � Has all the various providers and rules configured and
commented out. Uncomment the rule you want to test, then browse the
Default.aspx and ViewEvent.aspx pages to see what the output looks
like.
- The MyEvent.cs file � Located in the App_Data folder. This is used in the
ViewEvents.aspx page to fire a custom event.
- The Default.aspx file � Throws a System.NullReferenceException to see what an unhandled
exception logs.
- The EmailTemplateTest.aspx file � Used for the TemplateemailProvider sample. The code-behind file
for the EmailTemplateTest.aspx file has lines of code you can uncomment, which
will cause the page to throw an exception.
How to store events to Event Viewer
As I mentioned earlier, the provider for logging events in the
Event Viewer is configured for you in the global Web.config file. By default,
all events based on
WebBaseErrorEvent and
WebFailureAuditEvent are logged. You can add additional rules to log additional
information to the Event Log. For example, if you wanted to log all events (
i.e., every event based on
WebBaseEvent), you could add the following rule to your Web.config file:
<healthMonitoring>
<rules>
<add name="All Events" eventName="All Events" provider="EventLogProvider" profile="Critical" />
</rules>
</healthMonitoring>
This rule would link the
All Events event map to the Event Log provider. Both eventMapping and the
provider are included in the global Web.config file. You can then use the
ViewEvents.aspx page to trigger the events generated by browsing the page. The
page will also fire the
MyEvent custom event in the
Page_Load and a Button Click event.
To see the type of data generated, browse the
Default.aspx page. This will throw a
System.NullReferenceException exception, and the following event will be logged in the Event
Viewer:
Event Type: Warning
Event Source: ASP.NET
2.0.50601.0
Event Category: Web Event
Event ID: 1311
Date:
8/16/2005
Time: 9:37:44 PM
User: N/A
Computer:
Computer name
Description:
Event code:
3005
Event message: An unhandled exception has occurred.
Event time:
8/16/2005 9:37:44 PM
Event time (UTC): 8/17/2005 2:37:44 AM
Event ID:
88838b4e73cf4a0d9a36ac737ff9d1a0
Event sequence: 39
Event occurrence:
1
Event detail code: 0
Application information: Application domain:
d047d537-2-127687190240098660
Trust level: Full
Application Virtual
Path: /WebSite3
Application Path: Physical
path
Machine name: Computer
name
Process information: Process ID: 3776
Process name:
WebDev.WebServer.EXE
Account name: DOMAIN\user
Exception information:
Exception type: NullReferenceException
Exception message: Object reference
not set to an instance of an object.
Request information: Request URL:
http://localhost:1698/WebSite3/Default.aspx
Request path:
/WebSite3/Default.aspx
User host address: 127.0.0.1
User:
DOMAIN\User
Is authenticated: True
Authentication Type: NTLM
Thread
account name: DOMAIN\User
Thread information:
Thread ID: 8
Thread
account name: DOMAIN\User
Is impersonating: False
Stack trace: at
_Default.Page_Load(Object sender, EventArgs e) in c:\Documents and
Settings\user\Desktop\WebEvents\WebSite3\WebSite3\Default.aspx.cs:line
15
at System.Web.Util.CalliHelper.EventArgFunctionCaller(IntPtr fp, Object
o, Object t, EventArgs e)
at
System.Web.Util.CalliEventHandlerDelegateProxy.Callback(Object sender,
EventArgs e)
at System.Web.UI.Control.OnLoad(EventArgs e) at
System.Web.UI.Control.LoadRecursive()
at
System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint,
Boolean includeStagesAfterAsyncPoint)
Custom event details: For more
information, see Help and Support Center at
http://support.microsoft.com.
Logging all events to the Event Log
generates informational events as well. The following event shows the URL
authorization succeeding for the page request:
Event
Type: Information
Event Source: ASP.NET 2.0.50601.0
Event Category: Web
Event
Event ID: 1314
Date: 8/16/2005
Time: 11:04:44 PM
User:
N/A
Computer: Computer
name
Description:
Event code: 4003
Event message: URL
authorization succeeded for the request.
Event time: 8/16/2005 11:04:44
PM
Event time (UTC): 8/17/2005 4:04:44 AM
Event ID:
fec3d73fba0247eaba425e5ccfada18e
Event sequence: 2
Event occurrence:
1
Event detail code: 0
Application information:
Application domain:
d047d537-1-127687250829701433
Trust level: Full
Application Virtual
Path: /WebSite3
Application Path: C:\Documents and
Settings\user\Desktop\WebEvents\WebSite3\WebSite3\
Machine name:
Computer name
Process information:
Process
ID: 2292
Process name: WebDev.WebServer.EXE
Account name:
DOMAIN\user
Request information:
Request URL:
http://localhost:2087/WebSite3/Default.aspx
Request path:
/WebSite3/Default.aspx
User host address: 127.0.0.1
User:
DOMAIN\User
Is authenticated: True
Authentication Type: NTLM
Thread
account name: DOMAIN\User
Custom event details:
For more
information, see Help and Support Center at
http://support.microsoft.com.
How to store events to SQL Server
This method uses the
ASPNETDB database, which is generated by the Aspnet_regsql.exe tool. The
default provider uses the LocalSqlServer connection string, which uses either a
file-based database in the App_data folder or the local SQLExpress instance of
SQL Server. Both the LocalSqlServer connection string and the SqlProvider are
configured in the global Web.config file.
The LocalSqlServer
connection string in the global Web.config file looks like this:
<connectionStrings>
<add name="LocalSqlServer" connectionString="data source=.\SQLEXPRESS;Integrated Security=SSPI;AttachDBFilename=|DataDirectory|aspnetdb.mdf;User Instance=true" providerName="System.Data.SqlClient" />
</connectionStrings>
If you want to use another SQL Server server, you'll need to use the
Aspnet_regsql.exe tool, which can be found in the
%windir%\Microsoft.Net\Framework\v2.0.*\Aspnet_regsql.exe folder. Use the
Aspnet_regsql.exe tool to generate a custom
ASPNETDB database on the SQL Server server, then add the connection string
to your applications .config file, and then add a provider by using the new
connection string. Once you have the
ASPNETDB database created, you'll need to set a rule to link an
eventMapping to the sqlProvider.
To configure a custom database,
follow these steps:
- Generate an ASPNETDB database.
- Run aspnet_regsql.exe �W, and walk through the
wizard.
- Run the command to automate the process: Aspnet_regsql
�A w �S SQL Server -E.
- Add a connection string that points to the database, so
that it looks like this:
<connectionStrings>
<add name="MYASPNETDB" connectionString="Server=<SQL Instance>;Integrated Security=SSPI;Database=aspnetdb"/>
</connectionStrings>
- Add a provider to use the MYASPNETDB connection string, so
that it looks like this:
<healthMonitoring>
<providers>
<add name="MySqlWebEventProvider" type="System.Web.Management.SqlWebEventProvider" connectionStringName="MYASPNETDB" maxEventDetailsLength="1073741823" buffer="false"/>
</providers>
</healthMonitoring>
Whether you use the default SqlProvider or configure your own
provider, you'll need to add a rule linking the provider with an event map. The
following rule links the new provider that you created above to the
All Events event map. This rule will log all the events based on
WebBaseEvent and send them to the MySqlWebEventProvider that will use the
MYASPNETDB connection string. The following code adds a rule to link the
provider with an event map:
<healthMonitoring>
<rules>
<add name="All Events" eventName="All Events" provider="MySqlWebEventProvider" profile="Critical"/>
</rules>
</healthMonitoring>
If you wanted to only send errors to SQL Server, you could add the
following rule:
<add name="All Errors" eventName="All Errors" provider="MySqlWebEventProvider" profile="Critical"/>
How to forward events to WMI
You can also forward the events to WMI. The WMI provider is
configured for you in the global Web.config file by default.
The
following code example adds a rule to forward the events to WMI:
<providers>
<add name="WmiWebEventProvider" type="System.Web.Management.WmiWebEventProvider,System.Web,Version=2.0.0.0,Culture=neutral,PublicKeyToken=b03f5f7f11d50a3a" />
</providers>
You will need to add a rule to associate an eventMapping to the
provider, and also a WMI listener application to listen for the events. The
following code example adds a rule to link the WMI provider to the
All Events event map:
<rules>
<add name="All Events" eventName="All Events" provider="WmiWebEventProvider" profile="Critical" />
</rules>
The sample console application SampleASPNET uses the
ManagementEventWatcher object to monitor for events and display them in the console
window.
To use SampleASPNET, follow these steps:
- Launch SampleASPNET.exe.
- Browse the ViewEvents.aspx page; when you do, you will see
events listed in the console application.
- Click Log Event Button_Click. The page
will post back, and you'll see the additional events also logged.
Note If you are monitoring events on a remote computer, the listening
application needs to be running on that computer as an account with admin
access.
How to forward events to e-mail
You can also forward events to e-mail. This would allow you to get
information about your application directly in your (probably overflowing)
Inbox. Be careful about which event rules you map to your e-mail provider, as
you can unintentionally send yourself a lot of information that may be better
suited for SQL Server or the Event Log.
There are two e-mail
providers, SimpleMailWebEventProvider and TemplatedMailWebEventProvider. Each
has the same configuration attributes, with the exception of the "template" and
"detailedTemplateErrors" attributes, which are only available on the
TemplatedMailWebEventProvider.
Note Neither of these e-mail providers is configured for you. You'll
need to add them to your Web.config file.
The main difference between
these two e-mail providers is that SimpleMailWebEventProvider sends e-mails in
a generic template that cannot be modified. The sample Web.config file adds
this e-mail provider to the list of configured providers by using the following
rule:
<add name="mySimple-mailWebEventProvider" type="System.Web.Management.Simple-mailWebEventProvider"
to="e-mail@foo.com" from="e-mail@foo.com" maxMessagesPerNotification="1" maxEventsPerMessage="10"
buffer="true" bufferMode="Critical Notification"
subjectPrefix="Web Events"/>
The following rule is also added to tie the e-mail provider to the
All Events event map:
<add name="All Events" eventName="All Events" provider="mySimple-mailWebEventProvider" profile="Critical"/>
The e-mail alert message is similar to the following:
Subject: Event Notification 12, part 1: Web
EventsMicrosoft.Samples.WebEvents.MyEvent event received in
/WebSite3
** Application Information
**
---------------
Application domain: d047d537-9-127687218865923053
Trust level: Full Application Virtual Path: /WebSite3 Application Path:
C:\Documents and Settings\user\Desktop\WebEvents\WebSite3\WebSite3\ Machine
name: <computer name>
** Events **
---------------
Event
code: 100010
Event message: Button1_Click
Event time: 8/16/2005
10:12:52 PM
Event time (UTC): 8/17/2005 3:12:52 AM
Event ID:
6e5cd252d6114a9e98687598dc6b5d50 Event sequence: 12 Event occurrence: 5 Event
detail code: 0
Custom event
details:
---------------
The following is an e-mail alert
message that shows an unhandled exception:
Subject:
Event Notification 7, part 1: Web
EventsSystem.Web.Management.WebRequestErrorEvent event received in
/WebSite3
** Application Information
**
---------------
Application domain: d047d537-5-127687293149504903
Trust level: Full Application Virtual Path: /WebSite3 Application Path:
C:\Documents and Settings\user\Desktop\WebEvents\WebSite3\WebSite3\ Machine
name: <computer name>
** Events **
---------------
Event
code: 3005
Event message: An unhandled exception has occurred.
Event
time: 8/17/2005 12:17:37 AM
Event time (UTC): 8/17/2005 5:17:37
AM
Event ID: 14b7f24102e140bbbae302d80e5a5f36 Event sequence: 7 Event
occurrence: 1 Event detail code: 0
Process information:
Process
ID: 2292
Process name: WebDev.WebServer.EXE
Account name:
DOMAIN\User
Exception information:
Exception type:
System.NullReferenceException
Exception message: Object reference not set
to an instance of an object.
Request information:
Request URL:
http://localhost:2087/WebSite3/Default.aspx
Request path:
/WebSite3/Default.aspx
User host address: 127.0.0.1
User:
DOMAIN\User
Is authenticated: True
Authentication Type: NTLM
Thread
account name: DOMAIN\User
Thread information:
Thread ID:
7
Thread account name: DOMAIN\User
Is impersonating: False
Stack
trace: at _Default.Page_Load(Object sender, EventArgs e) in c:\Documents and
Settings\user\Desktop\WebEvents\WebSite3\WebSite3\Default.aspx.cs:line
15
at System.Web.Util.CalliHelper.EventArgFunctionCaller(IntPtr fp, Object
o, Object t, EventArgs e)
at
System.Web.Util.CalliEventHandlerDelegateProxy.Callback(Object sender,
EventArgs e)
at System.Web.UI.Control.OnLoad(EventArgs e) at
System.Web.UI.Control.LoadRecursive()
at
System.WebUI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint,
Boolean includeStagesAfterAsyncPoint)
TemplatedMailWebEventProvider
allows you to specify an ASPX page as a -- you guessed it -- template. The
output of the ASPX page is used in the body of the e-mail, allowing you to
customize the look of the data you receive.
The sample application
uses the following code to add TemplatedMailWebEventProvider to the Web.config
file and specify the EmailTemplateTest.aspx page as the template. (The
EmailTemplateTest.aspx page loops through the available events in the buffer,
and displays them in a table.)
<add name="myTemplatedMailWebEventProvider" type="System.Web.Management.TemplatedMailWebEventProvider"
to="e-mail@foo.com" from="e-mail@foo.com " buffer="true"
bufferMode="Critical Notification" maxMessagesPerNotification="10" maxEventsPerMessage="10"
template="e-mailTemplateTest.aspx" detailedTemplateErrors="false" />
The e-mail alert message is similar to the following:
Subject: Event Notification 3, part 1: 10 events received in
/WebSite3
Occurrence Source Time Code Detail Code Message
4
System.Web.Security.UrlAuthorizationModule 8/17/2005 12:40:45 AM 4003 0 URL
authorization succeeded for the request.
4 8/17/2005 12:40:45 AM 4004 0
File authorization succeeded for the request.
7 ASP.ViewEvents_aspx
8/17/2005 12:40:45 AM 100010 0 loading webevent sample page
8
ASP.ViewEvents_aspx 8/17/2005 12:40:45 AM 100010 0 Button1_Click
5
SystemWeb.Security.UrlAuthorizationModule 8/17/2005 12:40:45 AM 4003 0 URL
authorization succeeded for the request.
5 8/17/2005 12:40:45 AM 4004 0
File authorization succeeded for the request.
9 ASP.ViewEvents_aspx
8/17/2005 12:40:45 AM 100010 0 loading webevent sample page
10
ASP.ViewEvents_aspx 8/17/2005 12:40:45 AM 100010 0 Button1_Click
6
System.Web.Security.UrlAuthorizationModule 8/17/2005 12:40:46 AM 4003 0 URL
authorization succeeded for the request.
6 8/17/2005 12:40:46 AM 4004 0
File authorization succeeded for the request.
In both cases, if the
buffer attribute is false, the e-mail will contain only one event. With
buffering set to true, you also need to specify a bufferMode, which indicates
how often to flush the buffer. There are some default bufferModes in the global
Web.config file.
If detailedTemplateErrors="true", then any errors
that occur when you execute the template will be sent in the body of the
e-mail. If detailedTemplateErrors="false", a generic error is sent.
A
detailed error thrown by EmailTemplateTest.aspx looks like this:
Server Error in '/WebSite3' Application.
An unhandled
exception occurred during the execution of the template page used to create
this event notification. The 1 events that were part of this message were
discarded.
Description: An unhandled exception occurred during the
execution of the current web request. Please review the stack trace for more
information about the error and where it originated in the
code.
Exception Details: System.Web.HttpException: Session state can
only be used when enableSessionState is set to true, either in a configuration
file or in the Page directive. Please also make sure that
System.Web.SessionStateModule or a custom session state module is included in
the <configuration>\<system.web>\<httpModules> section in the
application configuration.
Source File: c:\Documents and
Settings\user\Desktop\WebEvents\WebSite3\WebSite3\e-mailTemplateTest.aspx.cs
Line: 17
Stack Trace: [HttpException (0x80004005): Session state can
only be used when enableSessionState is set to true, either in a configuration
file or in the Page directive. Please also make sure that
System.Web.SessionStateModule or a custom session state module is included in
the <configuration>\<system.web>\<httpModules> section in the
application configuration.]
System.Web.UI.Page.get_Session()
+146
e-mailTemplateTest.Page_Load(Object sender, EventArgs e) in
c:\Documents and
Settings\user\Desktop\WebEvents\WebSite3\WebSite3\e-mailTemplateTest.aspx.cs:17
System.Web.Util.CalliHelper.EventArgFunctionCaller(IntPtr
fp, Object o, Object t, EventArgs e)
+13
System.Web.Util.CalliEventHandlerDelegateProxy.Callback(Object sender,
EventArgs e) +45
System.Web.UI.Control.OnLoad(EventArgs e)
+80
SystemWeb.UI.Control.LoadRecursive()
+49
System.Web.UI.Page.ProcessRequestMain(Boolean
includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint)
+3749
[HttpUnhandledException (0x80004005): Exception of type
'System.Web.HttpUnhandledException' was
thrown.]
System.Web.UI.Page.HandleError(Exception e)
+929
System.Web.UI.Page.ProcessRequestMain(Boolean
includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint)
+7864
System.Web.UI.Page.ProcessRequest(Boolean
includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint)
+229
System.Web.UI.Page.ProcessRequest()
+12
System.Web.UI.Page.ProcessRequest(HttpContext context)
+80
System.Web.HttpServerUtility.ExecuteInternal(IHttpHandler handler,
TextWriter writer, Boolean preserveForm, VirtualPath path, VirtualPath
filePath, String physPath, Exception error, String queryStringOverride)
+1012
[HttpException (0x80004005): Error executing child request for
/WebSite3/e-mailTemplateTest.aspx.]
System.Web.HttpServerUtility.ExecuteInternal(IHttpHandler
handler, TextWriter writer, Boolean preserveForm, VirtualPath path, VirtualPath
filePath, String physPath, Exception error, String queryStringOverride)
+1525
System.Web.HttpServerUtility.Execute(String path, TextWriter writer,
Boolean preserveForm)
+754
System.Web.HttpServerUtility.ExecuteLocalRequestAndCaptureResponse(String
path, TextWriter writer, ErrorFormatterGenerator errorFormatterGenerator)
+249
If the attribute is false and there is an error, you will only
get a generic error message, which looks like this:
Server
Error in '/WebSite3' Application.
An unhandled exception occurred
during the execution of the template page used to create this event
notification. The 8 events that were part of this message were
discarded.
Description: The current configuration prevents the
exception details from being included in this message. Add the
"detailedTemplateErrors=true" attribute to the provider configuration to enable
exception details to be reported.
Note For the buffering-related attributes, every flush results in a
notification. If the flush contains more events than
maxEventsPerMessage allows, the notification will be broken up into multiple e-mails,
but they are all still considered to be the same notification. For example, a
flush generates 13 events, but
maxEventsPerMessage only allows five. You will get three e-mails: the first two
e-mails will each contain five events, and the third e-mail will contain three
events.
If there are more e-mails than
maxMessagesPerNotification allows, some events are dropped. For example, if you set
maxMessagesPerNotification to two and you use the same
maxEventsPerMessage as above, you would only receive two e-mails. The events that
would be on the third e-mail are dropped. Any drops or truncation of
notifications will be noted in one of the e-mails for the simple mail provider.
The top of the e-mail will show the following:
**
Warnings **
---------------
The 10 events remaining for this
notification period will be discarded because the maximum number of messages
allowed per notification was exceeded. (Warning ID: 101)
Since you
have control of the format of the e-mail for the templated provider, you have
to check for drops/truncation yourself and determine whether to include that in
the e-mail.
Note Mail providers use System.Net.Mail, so you have to configure
System.Net.Mail in your Web.config file.