Global error handling with e-mail notification

In this article I am going to share some techniques on globally trapping and handling errors that occur in a web application and then how to notify administrators/developers that the error has occurred. I will use the Application_OnError subroutine of the global.asax file to trap the errors and then the aspNetEmail component to send the error notification e-mails.[bold]Introduction[/bold]When porting our campus? student information portal to ASP.NET, we realized that the previous ASP ...

Contributed by
Rating: 5 stars5 stars5 stars5 stars5 stars / 2
August 21, 2002
Rate this Article:
MEH MEH++


SEARCH ASP FREE
TOOLS YOU CAN USE

advertisement
In this article I am going to share some techniques on globally trapping and handling errors that occur in a web application and then how to notify administrators/developers that the error has occurred. I will use the Application_OnError subroutine of the global.asax file to trap the errors and then the aspNetEmail component to send the error notification e-mails.[bold]Introduction[/bold]When porting our campus? student information portal to ASP.NET, we realized that the previous ASP version generated many errors that we had no idea had occurred. It was decided that in the new version we needed some way to trap errors and then e-mail us information about the error.We didn?t want to use System.Web.Mail because our administrators did not want to install SMTP server on all of our web servers. After looking around a bit, we decided to go with the aspNetEmail component, which in addition to allowing us to use our single campus SMTP server, also allowed for us to dynamically create the HTML error e-mails and include DataGrids.[bold]Error Trapping[/bold]Error trapping and handling at an application level is super easy to do in ASP.NET. All errors occur at the application level, so you can trap errors using the Application_OnError method of global.asax.In our Application_OnError subroutine, we grab the exception for the error using Context.Error.GetBaseException() as seen in the code below:


Sub Application_Error(ByVal sender As ObjectByVal e As EventArgs)
Dim ex As Exception Context.Error.GetBaseException()

Dim objErrHandler As New ErrorHandler()
objErrHandler.SendHtmlErrorEmail(ex)
End Sub

After the exception is grabbed, it is passed to the SendHtmlErrorEmail function of the ErrorHandler class, which does the work of generating the e-mail.[bold]Collecting additional information[/bold]In addition to being sent information about the error itself, we also needed to be sent information about the session that generated the error, like QueryString & Form variables, Server Variables and Cookies. This kind of information helps tremendously in the bug-tracking process.We wanted to get the variables into a DataTable so that later we could easily bind it to a DataGrid. The variables are either stored in a NameValueCollection or an HttpCookiesCollection, so I wrote a couple of functions that iterate through the collections and add rows to a datatable:


 Private Function GetVariables(ByVal inputVarCollection As System.Collections.Specialized.NameValueCollection) As DataTable
Dim objTable 
As New DataTable()
objTable.Columns.Add("Name"GetType(String))
objTable.Columns.Add("Value"GetType(String))

Dim strItem As String
Dim objRow 
As DataRow
For Each strItem In inputVarCollection
objRow 
objTable.NewRow()
objRow("Name") = strItem
objRow
("Value") = inputVarCollection(strItem)
objTable.Rows.Add(objRow)
Next

Return objTable
End 
Function

Private Function 
GetCookieVars() As DataTable
Dim objTable 
As New DataTable()
objTable.Columns.Add("Name"GetType(String))
objTable.Columns.Add("Value"GetType(String))

Dim strItem As String
Dim objRow 
As DataRow
For Each strItem In HttpContext.Current.Request.Cookies
objRow 
objTable.NewRow()
objRow("Name") = strItem
objRow
("Value") = HttpContext.Current.Request.Cookies(strItem).Value
objTable
.Rows.Add(objRow)
Next

Return objTable
End 
Function

[bold]Creating the DataGrids[/bold]I fashioned the error e-mail after the output generated when you use ASP.NET tracing. The easiest way to do this was to use DataGrids, but since they were all going to be the same design and they needed to be programmatically generated on the fly, I wrote a method that set up the templates for the grid:


Private Function CreateDataGrid() As System.Web.UI.WebControls.DataGrid

Dim objDataGrid 
As New DataGrid()
objDataGrid.Width System.Web.UI.WebControls.Unit.Percentage(100)
objDataGrid.BorderWidth System.Web.UI.WebControls.Unit.Pixel(0)
objDataGrid.CellPadding "2"

objDataGrid.HeaderStyle.BackColor System.Drawing.Color.LightGray
objDataGrid
.HeaderStyle.ForeColor System.Drawing.Color.Black
objDataGrid
.HeaderStyle.Font.Name "Arial"
objDataGrid.HeaderStyle.Font.Size System.Web.UI.WebControls.FontUnit.Point(10)
objDataGrid.HeaderStyle.Font.Bold True

objDataGrid
.ItemStyle.BackColor System.Drawing.Color.White
objDataGrid
.ItemStyle.ForeColor System.Drawing.Color.Black
objDataGrid
.ItemStyle.Font.Name "Arial"
objDataGrid.ItemStyle.Font.Size System.Web.UI.WebControls.FontUnit.Point(10)

objDataGrid.AlternatingItemStyle.BackColor System.Drawing.ColorTranslator.FromHtml("#eeeeee")
objDataGrid.AlternatingItemStyle.ForeColor System.Drawing.Color.Black
objDataGrid
.AlternatingItemStyle.Font.Name "Arial"
objDataGrid.AlternatingItemStyle.Font.Size System.Web.UI.WebControls.FontUnit.Point(10)

Return 
objDataGrid

End 
Function

[bold]Creating the e-mail[/bold]This is the most complicated step of the process and one of the main reasons that we went with the aspNetEmail component. System.Web.Mail didn?t allow us to add controls (like DataGrid) to an e-mail message, so we would have had to build a lot of ugly ASP-like code to generate nice, uniform looking tables. Why reinvent the wheel when there are server controls that do the dirty work for you? We were able to add the DataGrid controls to our e-mail messages using aspNetEmail?s AppendControlToBody function. The code below will add a DataGrid containing cookie information and send the e-mail:


Dim objMessage As New EmailMessage("your smtp server")

Dim objCookiesDG As DataGrid CreateDataGrid()
objCookiesDG.DataSource GetCookieVars()
objCookiesDG.DataBind()
objMessage.AppendControlToBody(objCookiesDG)

objMessage.FromAddress "e-mail address"
objMessage.To "comma separated e-mail addresses"
objMessage.Subject "Error: Portal Error"
objMessage.BodyFormat MailFormat.Html
objMessage
.Send()

[bold]Conclusion[/bold]It is super easy to globally handle and trap errors at an application level, and with a couple of steps, you can create e-mail notification of those errors in a standard, easy to read format. You can view the entire ErrorHandlerClass below:


Imports System.Text
Imports aspNetEmail

Public Class ErrorHandler

Private Function CreateDataGrid() As System.Web.UI.WebControls.DataGrid

Dim objDataGrid 
As New DataGrid()
objDataGrid.Width System.Web.UI.WebControls.Unit.Percentage(100)
objDataGrid.BorderWidth System.Web.UI.WebControls.Unit.Pixel(0)
objDataGrid.CellPadding "2"

objDataGrid.HeaderStyle.BackColor System.Drawing.Color.LightGray
objDataGrid
.HeaderStyle.ForeColor System.Drawing.Color.Black
objDataGrid
.HeaderStyle.Font.Name "Arial"
objDataGrid.HeaderStyle.Font.Size System.Web.UI.WebControls.FontUnit.Point(10)
objDataGrid.HeaderStyle.Font.Bold True

objDataGrid
.ItemStyle.BackColor System.Drawing.Color.White
objDataGrid
.ItemStyle.ForeColor System.Drawing.Color.Black
objDataGrid
.ItemStyle.Font.Name "Arial"
objDataGrid.ItemStyle.Font.Size System.Web.UI.WebControls.FontUnit.Point(10)

objDataGrid.AlternatingItemStyle.BackColor System.Drawing.ColorTranslator.FromHtml("#eeeeee")
objDataGrid.AlternatingItemStyle.ForeColor System.Drawing.Color.Black
objDataGrid
.AlternatingItemStyle.Font.Name "Arial"
objDataGrid.AlternatingItemStyle.Font.Size System.Web.UI.WebControls.FontUnit.Point(10)

Return 
objDataGrid

End 
Function

Private Function 
GetVariables(ByVal inputVarCollection As System.Collections.Specialized.NameValueCollection) As DataTable
Dim objTable 
As New DataTable()
objTable.Columns.Add("Name"GetType(String))
objTable.Columns.Add("Value"GetType(String))

Dim strItem As String
Dim objRow 
As DataRow
For Each strItem In inputVarCollection
objRow 
objTable.NewRow()
objRow("Name") = strItem
objRow
("Value") = inputVarCollection(strItem)
objTable.Rows.Add(objRow)
Next

Return objTable
End 
Function

Private Function 
GetCookieVars() As DataTable
Dim objTable 
As New DataTable()
objTable.Columns.Add("Name"GetType(String))
objTable.Columns.Add("Value"GetType(String))

Dim strItem As String
Dim objRow 
As DataRow
For Each strItem In HttpContext.Current.Request.Cookies
objRow 
objTable.NewRow()
objRow("Name") = strItem
objRow
("Value") = HttpContext.Current.Request.Cookies(strItem).Value
objTable
.Rows.Add(objRow)
Next

Return objTable
End 
Function

Public 
Sub SendHtmlErrorEmail(ByVal ex As Exception)
Dim objMessage As New EmailMessage("your smtp server")

objMessage.Body "<SPAN STYLE=""font-size:18pt; color: red;font-family: Arial;"">Portal Error - " ex.Message "</SPAN>

"

Dim objErrInfoDG As DataGrid CreateDataGrid()

objMessage.Body &= "<TABLE BORDER=0 WIDTH=100% CELLPADDING=1 CELLSPACING=0><TR><TD STYLE=""background-color: black; color: white;font-weight: bold;font-family: Arial;"">Error information</TD></TR></TABLE>"
Dim objTable As New DataTable()
objTable.Columns.Add("Name"GetType(String))
objTable.Columns.Add("Value"GetType(String))

Dim objRow As DataRow

objRow 
objTable.NewRow()
objRow("Name") = "Message"
objRow("Value") = ex.Message
objTable
.Rows.Add(objRow)

objRow objTable.NewRow()
objRow("Name") = "Source"
objRow("Value") = ex.Source
objTable
.Rows.Add(objRow)

objRow objTable.NewRow()
objRow("Name") = "TargetSite"
objRow("Value") = ex.TargetSite.ToString()
objTable.Rows.Add(objRow)

objRow objTable.NewRow()
objRow("Name") = "StackTrace"
objRow("Value") = ex.StackTrace
objTable
.Rows.Add(objRow)

objErrInfoDG.DataSource objTable
objErrInfoDG
.DataBind()
objMessage.AppendControlToBody(objErrInfoDG)


objMessage.Body &= "

<TABLE BORDER=0 WIDTH=100% CELLPADDING=1 CELLSPACING=0><TR><TD COLSPAN=2 STYLE=""background-color: black; color: white;font-weight: bold;font-family: Arial;"">Querystring Collection</TD></TR></TABLE>"
Dim objQSDG As DataGrid CreateDataGrid()
objQSDG.DataSource GetVariables(HttpContext.Current.Request.QueryString)
objQSDG.DataBind()
objMessage.AppendControlToBody(objQSDG)


objMessage.Body &= "

<TABLE BORDER=0 WIDTH=100% CELLPADDING=1 CELLSPACING=0><TR><TD COLSPAN=2 STYLE=""background-color: black; color: white;font-weight: bold;font-family: Arial;"">Form Collection</TD></TR></TABLE>"
Dim objFormDG As DataGrid CreateDataGrid()
objFormDG.DataSource GetVariables(HttpContext.Current.Request.Form)
objFormDG.DataBind()
objMessage.AppendControlToBody(objFormDG)


objMessage.Body &= "

<TABLE BORDER=0 WIDTH=100% CELLPADDING=1 CELLSPACING=0><TR><TD COLSPAN=2 STYLE=""background-color: black; color: white;font-weight: bold;font-family: Arial;"">Cookies Collection</TD></TR></TABLE>"
Dim objCookiesDG As DataGrid CreateDataGrid()
objCookiesDG.DataSource GetCookieVars()
objCookiesDG.DataBind()
objMessage.AppendControlToBody(objCookiesDG)


objMessage.Body &= "

<TABLE BORDER=0 WIDTH=100% CELLPADDING=1 CELLSPACING=0><TR><TD COLSPAN=2 STYLE=""background-color: black; color: white;font-weight: bold;font-family: Arial;"">Server Variables</TD></TR></TABLE>"
Dim objServVarDG As DataGrid CreateDataGrid()
objServVarDG.DataSource GetVariables(HttpContext.Current.Request.ServerVariables)
objServVarDG.DataBind()
objMessage.AppendControlToBody(objServVarDG)

objMessage.FromAddress "e-mail address"
objMessage.To "comma separated e-mail addresses"
objMessage.Subject "Error: Portal Error"
objMessage.BodyFormat MailFormat.Html
objMessage
.Send()
End Sub

End 
Class

[bold]About the Author[/bold]Tyler Peelen is the lead ASP.NET developer for the University of Wisconsin ? Stevens Point, my.uwsp.edu portal project. Although he is only 18, he has a firm grasp of ASP.NET has been programming for 10 years.
blog comments powered by Disqus
ASP.NET CODE ARTICLES

- How to Use the ListBox Control in ASP.NET 2.0
- How to Load XML Documents in ASP.NET 2.0
- DataGrid Code
- ASP.NET Guestbook
- User Controls and Client Side Scripting
- ASP.NET Programming with Microsoft's AS...
- ASP.NET Basics (part 3): Hard Choices
- ASP.NET Basics (part 2): Not My Type
- ASP.NET Basics (part 1): Nothing But .Net
- Directory Tree Browser
- How to get the confirmation of Yes/No from a...
- Complete example using custom errors and wri...
- Paging Certain # records per page .NET style
- General Methods of formatting and Subtractin...
- .NET LinkButton web control

ASP Web Hosting ASP.Net Web Hosting Windows Web Hosting
 
 
 

ASP Free Forums 
 RSS  Tutorials RSS
 RSS  Forums RSS
 RSS  All Feeds
Site Map 
Request Media Kit
Write For Us Get Paid 
Weekly Newsletter
 
Developer Updates  
Free Website Content 
Privacy Policy 
Support 


© 2003-2012 by Developer Shed. All rights reserved. DS Cluster 7 - Follow our Sitemap
Most Popular Topics
All ASP.Net Tutorials