There are legions of articles (articli?) out there on how to trap errors in ASP.NET. My purpose here is not to be bigger, better, faster. I'm only trying to blog the code that I use, so that I can use it in the next app that I write. So... keep your expectations low <smiles>
First, add code to the Global.asax:
Sub Application_Error(ByVal sender As Object, ByVal e As EventArgs)
' Code that runs when an unhandled error occurs
ExceptionLogger.HandleException(Server.GetLastError().GetBaseException())
Response.Redirect("~/errorPage.aspx")
End Sub
Next, add the event handler mentioned above
Imports System
Imports System.Web
'Imports System.Diagnostics
'Imports System.Data
'Imports System.Data.SqlClient
'Imports System.Web.Mail
'Imports System.Configuration
Public Class ExceptionLogger
Public Shared Sub HandleException(ByVal ex As Exception)
Try
Static logExceptions As Boolean = Convert.ToBoolean(System.Web.Configuration.WebConfigurationManager.AppSettings("logExceptions"))
Dim ofacErrorLog As New dynData.facErrorLog
Dim ctx As HttpContext = HttpContext.Current
Dim strData As String = String.Empty
'Dim eventID As Guid = System.Guid.NewGuid()
Dim referer As String = String.Empty
Dim oFunctions As New functions
Dim sQuery As String = ""
Dim sForm As String = ""
Dim logDateTime As String = DateTime.Now.ToString()
If Not logExceptions Then Return ' user set web.config setting to false, abort
'initialize
If Not ctx.Request.ServerVariables("HTTP_REFERER") Is Nothing Then
referer = ctx.Request.ServerVariables("HTTP_REFERER").ToString()
End If
If Not ctx.Request.Form Is Nothing Then
sForm = ctx.Request.Form.ToString()
End If
If Not ctx.Request.QueryString Is Nothing Then
sQuery = ctx.Request.QueryString.ToString()
End If
strData = "SOURCE: " & ex.Source & vbCrLf & _
"LogDateTime: " & logDateTime & vbCrLf & _
"MESSAGE: " & ex.Message & vbCrLf & _
"FORM: " & sForm & vbCrLf & _
"QUERYSTRING: " & sQuery & vbCrLf & _
"TARGETSITE: " & ex.TargetSite.ToString & vbCrLf & _
"STACKTRACE: " & ex.StackTrace & vbCrLf & _
"REFERER: " & referer
'send an email
oFunctions.sendMail(strData)
'log the error message
ofacErrorLog.ConnectionString = System.Web.HttpContext.Current.Session("connect")
ofacErrorLog.errorLog_INS(strData, 75000, System.Web.HttpContext.Current.Session("user"))
Catch ex2 As Exception
End Try
End Sub ' end method HandleException
End Class
Notice that the Global.asax redirects to a generic 'An Error Has Ocurred' page. Nothing exciting there.
This code sends an email, and then does a table insert. Both of those topics are covered elsewhere in this blog.
This is the code for the error page itself
<%@ Page Language="VB" MasterPageFile="~/MasterPage.master" AutoEventWireup="false"
CodeFile="errorPage.aspx.vb" Inherits="errorPage" Title="Untitled Page" %>
<asp:Content ID="Content1" ContentPlaceHolderID="ContentPlaceHolder1" runat="Server">
<div style="text-align: center;">
<table style="text-align: left; width: 300px">
<tr>
<td>
<div class="title1">
System Error</div>
A crash has occurred.
</td>
</tr>
<tr>
<td style="text-align: center">
<asp:AdRotator ID="ar1" runat="server" AdvertisementFile="~/ads.xml" />
</td>
</tr>
<tr>
<td>
The error has been logged, and the sys admin has been emailed.
<br />
<br />
If the issue is urgent, please contact the system administrator immediately<br />
</td>
</tr>
</table>
</div>
</asp:Content>
Add this to the web.config file:
<add key="debug" value="False"/>
<add key="logExceptions" value="True"/>
<add key="emailServer" value="mail.myServer.com"/>
<add key="emailUser" value="something@somewhere.com"/>
<add key="emailRecipient" value="mrManager@it.com"/>
<add key="emailPassword" value="secret"/>
This is the 'ads.xml' file referenced in this page. I use it to rotate a series of photos of auto crashes.
<Advertisements>
<Ad>
<ImageUrl>/images/crash01.jpg</ImageUrl>
<AlternateText>Oops</AlternateText>
</Ad>
<Ad>
<ImageUrl>/images/crash02.jpg</ImageUrl>
<AlternateText>Oops</AlternateText>
</Ad>
<Ad>
<ImageUrl>/images/crash03.jpg</ImageUrl>
<AlternateText>Oops</AlternateText>
</Ad>
<Ad>
<ImageUrl>/images/crash04.jpg</ImageUrl>
<AlternateText>Oops</AlternateText>
</Ad>
<Ad>
<ImageUrl>/images/crash05.jpg</ImageUrl>
<AlternateText>Oops</AlternateText>
</Ad>
<Ad>
<ImageUrl>/images/crash06.jpg</ImageUrl>
<AlternateText>Oops</AlternateText>
</Ad>
<Ad>
<ImageUrl>/images/crash07.jpg</ImageUrl>
<AlternateText>Oops</AlternateText>
</Ad>
<Ad>
<ImageUrl>/images/crash08.jpg</ImageUrl>
<AlternateText>Oops</AlternateText>
</Ad>
<Ad>
<ImageUrl>/images/crash09.jpg</ImageUrl>
<AlternateText>Oops</AlternateText>
</Ad>
<Ad>
<ImageUrl>/images/crash10.jpg</ImageUrl>
<AlternateText>Oops</AlternateText>
</Ad>
</Advertisements>
Last, the images used in the XML file above










This is the 'error log' class referenced above, and the code to create the table
CREATE TABLE [_ErrorLog] (
[intRowID] [int] IDENTITY (1, 1) NOT NULL ,
[vchrErrorText] [varchar] (1000) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL ,
[intErrorNum] [int] NOT NULL ,
[dtCreated] [datetime] NOT NULL CONSTRAINT [DF__ErrorLog_dtCreated] DEFAULT (getdate()),
[vchrUserID] [varchar] (15) COLLATE SQL_Latin1_General_CP1_CI_AS NULL
) ON [PRIMARY]
GO
-- =============================================
--
-- =============================================
-- 1/1/1900 created
IF EXISTS (SELECT name
FROM sysobjects
WHERE name = N'_4P_errorLog_INS'
AND type = 'P')
DROP PROCEDURE _4P_errorLog_INS
GO
CREATE PROCEDURE _4P_errorLog_INS
-- _4P_errorLog_INS 'error', 234, 'steve'
@vchrErrorText varchar(1000),
@intErrorNum int,
@vchrUserID varchar(15)
AS
INSERT INTO _errorlog (vchrErrorText , intErrorNum ,vchrUserID ) values (@vchrErrorText, @intErrorNum, @vchrUserID)
go
grant all on _4P_errorLog_INS to public
--select * from _errorlog order by introwid desc
Imports System.Data
Imports Microsoft.ApplicationBlocks.Data
Imports System.Data.SqlClient
Public Class facErrorLog
Dim m_cs As String
Public Property ConnectionString() As String
Get
Return m_cs
End Get
Set(ByVal value As String)
m_cs = value
End Set
End Property
Sub New(ByVal connectionString As String)
m_cs = connectionString
End Sub
Sub New()
End Sub
Sub errorLog_INS(ByVal strErrorText As String, ByVal intErrorNum As Int64, ByVal user As String)
Try
SqlHelper.ExecuteNonQuery(m_cs, CommandType.StoredProcedure, "_4P_errorLog_INS", _
New SqlParameter("@vchrErrorText", strErrorText), _
New SqlParameter("@intErrorNum", intErrorNum), _
New SqlParameter("@vchrUserID", user))
Catch ex As Exception
Throw New Exception(ex.Message, ex.InnerException)
End Try
End Sub
End Class
Here is the 'sendmail' function mentioned above
Public Sub sendMail(ByVal strBody As String)
Try
Dim strEmailServer As String = System.Web.Configuration.WebConfigurationManager.AppSettings("emailServer")
Dim strEmailUser As String = System.Web.Configuration.WebConfigurationManager.AppSettings("emailUser")
Dim strEmailPassword As String = System.Web.Configuration.WebConfigurationManager.AppSettings("emailPassword")
Dim strEmailRecipient As String = System.Web.Configuration.WebConfigurationManager.AppSettings("emailRecipient")
Dim mail As New System.Net.Mail.MailMessage(strEmailUser, strEmailRecipient)
mail.Subject = "NGB Error"
mail.Body = strBody
Dim serv As New System.Net.Mail.SmtpClient(strEmailServer)
'serv.Credentials = New System.Net.NetworkCredential(strEmailUser, strEmailPassword)
serv.Send(mail)
Catch ex As Exception
'no error handling. we're already in an error loop. If this fails, we're just out of luck
End Try
End Sub
As always, your comments are welcome