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 ...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 Object, ByVal 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. | DISCLAIMER: The content provided in this article is not warranted or guaranteed by Developer Shed, Inc. The content provided is intended for entertainment and/or educational purposes in order to introduce to the reader key ideas, concepts, and/or product reviews. As such it is incumbent upon the reader to employ real-world tactics for security and implementation of best practices. We are not liable for any negative consequences that may result from implementing any information covered in our articles or tutorials. If this is a hardware review, it is not recommended to open and/or modify your hardware. |
More ASP.NET Code Articles More By Tyler Peelen developerWorks - FREE Tools! | Hear how IBM Rational Project and Portfolio Management integrated solutions help teams put the right tools and processes in place to maximize the effectiveness and efficiency of project teams and ensure that the business vision is being executed correctly. Learn how to automate and integrate requirements prioritization, top-down project planning, communications and controls, and methodology deployment to keep your scope, costs, and schedules under control. Tackle with an end-to-end approach the management of scope and scope changes, usage of methodology to control and empower project teams, and optimization of resources to align activity costs with the overall project plan. FREE! Go There Now!
| | | | When you create browser-based applications that display XML data feeds, you often need to code the data-retrieval mechanism and the user interface. Mozilla Firefox provides an infrastructure that frees you from these tasks, so you can concentrate on your application's functionality. Learn how to use Asynchronous JavaScript + XML (Ajax) to download XML data from a Web server, and discover how you can use Extensible Stylesheet Language Transformations (XSLT) to transform it dynamically into Firefox user-interface elements expressed in XML User Interface Language (XUL). You can apply these techniques to any application that uses XML data sources. FREE! Go There Now!
| | | | Learn how you can extend modern application lifecycle management to IBM System z through the IBM Rational Software Delivery Platform (SDP). The Did you say mainframe? e-kit includes podcasts, webcasts, tutorials, white and red papers, demos, and articles designed to help ease the challenges of modernizing your enterprise. This complimentary kit for mainframe developers is a practical, how-to guide for making the most of an existing development environment, including the skills and infrastructure already in place at an established enterprise. FREE! Go There Now!
| | | | Listen to this webcast to get an overview of Info 2.0 and a technical demo of how to quickly build an enterprise mashup. IBM's Info 2.0 technology leverages emerging Web 2.0 technologies such as mashups, feeds, AJAX, and JSON in order to simplify assembly of information using feeds and services. Come learn about the technical elements of Info 2.0 including the Feed Generation framework, Mashup Engine, and mashup assembly components. Learn how to pull information from databases, departmental information, and the Web to create mashups critical to your company’s success. We will also discuss best practices to help you get started. FREE! Go There Now!
| | | | Ken Krugler, co-founder of code search company Krugle, and Laura Merling, vice president of Marketing and Business Development for Krugle, join to talk about the ins and outs of code search and what it means as a new feature for developerWorks users. FREE! Go There Now!
| | | | Learn the basics of the IBM Customer Information Control System (CICS). With a hands-on exercise, learn how to get your first CICS application up and running on your desktop using TXSeries V6.1 for Windows. The tutorial shows you how to download and install a free trial version of TXSeries V6.1. FREE! Go There Now!
| | | | Here's a fun way to learn about DB2! Learn or teach the basics of DB2 and relational database with an interactive game called The DB2 Detective Game. The game teaches relational database concepts and shows how technology can be applied to solving real-life problems (the game's theme is a crime investigation). This tutorial has been updated for DB2 9. FREE! Go There Now!
| | | | This paper is about the critical role that a discipline called integrated requirements management can play in helping to ensure that your business goals and IT investments are continuously aligned—whether you are sourcing, integrating, building or maintaining software. It also looks at ways that automated IBM Rational® products can work together to help you use requirements in the very best way. FREE! Go There Now!
| | | | Try the latest version of IBM Rational Manual Tester V7.0.1 by downloading a free trial from IBM developerWorks. This manual test authoring and execution tool promotes test step reuse to reduce the impact of software change on testers and business analysts and addresses the needs of teams performing at least a portion of their testing manually. FREE! Go There Now!
| | | | Visit IBM developerWorks to try the IBM SOA Sandbox for process. The SOA Sandbox for process focuses on providing a trial environment with the necessary tooling and components required to gain a better understanding of business processes and how to best improve existing business processes to derive value quickly. FREE! Go There Now!
| | | | All FREE IBM® developerWorks Tools! | |