");
html.AppendLine();
html.Append("
More information
");
html.AppendLine();
html.Append("
");
html.AppendLine();
html.Append("");
html.AppendLine();
html.Append("");
html.AppendLine();
html.Append(m_moreInfoTextMethod());
html.AppendLine();
html.Append("");
html.AppendLine();
html.Append(" | |
");
html.AppendLine();
html.Append("");
html.AppendLine();
html.Append("");
html.AppendLine();
html.Append("");
html.AppendLine();
// Display the exception information.
HttpContext.Current.Response.Clear();
HttpContext.Current.Response.Write(html.ToString());
HttpContext.Current.Response.Flush();
HttpContext.Current.Response.End();
HttpContext.Current.Server.ClearError();
}
///
/// Logs encountered to the .
///
/// that was encountered.
protected virtual void ExceptionToFile(Exception exception)
{
// Log if enabled.
if (m_logToFile)
{
m_logToFileOK = false;
if (!m_errorLog.IsOpen)
m_errorLog.Open();
m_errorLog.WriteTimestampedLine(GetExceptionInfo(exception, m_logUserInfo));
m_logToFileOK = true;
}
}
///
/// Logs encountered to an e-mail message.
///
/// that was encountered.
protected virtual void ExceptionToEmail(Exception exception)
{
// Log if enabled.
if (m_logToEmail && !string.IsNullOrEmpty(m_contactEmail) && !m_suppressInteractiveLogging)
{
m_logToEmailOK = false;
Mail email = new Mail(m_contactEmail, m_contactEmail);
email.Subject = string.Format("Exception in {0} at {1}", ApplicationName, DateTime.Now.ToString());
email.Body = GetExceptionInfo(exception, m_logUserInfo);
email.Attachments = GetScreenshotFileName();
email.SmtpServer = m_smtpServer;
email.Send();
m_logToEmailOK = true;
}
}
///
/// Logs encountered to the .
///
/// that was encountered.
protected virtual void ExceptionToEventLog(Exception exception)
{
// Log if enabled.
if (m_logToEventLog)
{
m_logToEventLogOK = false;
EventLog.WriteEntry(ApplicationName, GetExceptionInfo(exception, m_logUserInfo), EventLogEntryType.Error);
m_logToEventLogOK = true;
}
}
///
/// Logs encountered to the database.
///
/// that was encountered.
protected virtual void ExceptionToDatabase(Exception exception)
{
// Log if enabled.
if (m_logToDatabase)
{
m_logToDatabaseOK = false;
LogErrorToDatabase(exception.Source.ToNonNullNorEmptyString("No Source"),
exception.Message.ToNonNullNorEmptyString("No Message"),
GetExceptionInfo(exception, true),
exception.GetType().FullName);
m_logToDatabaseOK = true;
}
}
///
/// Takes a screenshot of the user's desktop when the is encountered.
///
/// that was encountered.
protected virtual void ExceptionToScreenshot(Exception exception)
{
// Log if enabled.
if (m_logToScreenshot &&
(ApplicationType == ApplicationType.WindowsCui || ApplicationType == ApplicationType.WindowsGui))
{
m_logToScreenshotOK = false;
using (Bitmap screenshot = ScreenArea.Capture(ImageFormat.Png))
{
screenshot.Save(GetScreenshotFileName());
}
m_logToScreenshotOK = true;
}
}
///
/// Raises the event.
///
/// to send to event.
protected virtual void OnLoggingException(Exception exception)
{
if ((object)LoggingException != null)
LoggingException(this, new EventArgs(exception));
}
///
/// Releases the unmanaged resources used by the object and optionally releases the
/// managed resources.
///
/// true to release both managed and unmanaged resources; false to release only unmanaged resources.
protected override void Dispose(bool disposing)
{
if (!m_disposed)
{
try
{
// This will be done regardless of whether the object is finalized or disposed.
Unregister();
if (disposing)
{
// This will be done only when the object is disposed by calling Dispose().
SaveSettings();
if ((object)m_errorLog != null)
m_errorLog.Dispose();
}
}
finally
{
m_enabled = false; // Mark as disabled.
m_disposed = true; // Prevent duplicate dispose.
base.Dispose(disposing); // Call base class Dispose().
}
}
}
///
/// Default for .
///
private string GetErrorText()
{
StringBuilder errorText = new StringBuilder();
errorText.AppendFormat("An unexpected exception has occurred in {0}. ", ApplicationName);
errorText.Append("This may be due to an inconsistent system state or a programming error.");
return errorText.ToString();
}
///
/// Default for .
///
private string GetScopeText()
{
StringBuilder scopeText = new StringBuilder();
switch (ApplicationType)
{
case ApplicationType.WindowsCui:
case ApplicationType.WindowsGui:
scopeText.Append("The action you requested was not performed.");
break;
case ApplicationType.Web:
scopeText.Append("The current page will not load.");
break;
}
return scopeText.ToString();
}
///
/// Default for .
///
private string GetActionText()
{
StringBuilder actionText = new StringBuilder();
switch (ApplicationType)
{
case ApplicationType.WindowsCui:
case ApplicationType.WindowsGui:
actionText.AppendFormat("Restart {0}, and try repeating your last action. ", ApplicationName);
break;
case ApplicationType.Web:
actionText.AppendFormat("Close your browser, navigate back to the {0} website, and try repeating you last action. ", ApplicationName);
break;
}
actionText.Append("Try alternative methods of performing the same action. ");
// Add information about the contact person if provided.
if (!string.IsNullOrEmpty(m_contactName) &&
(!string.IsNullOrEmpty(m_contactPhone) || !string.IsNullOrEmpty(m_contactPhone)))
{
actionText.AppendFormat("If you need immediate assistance, contact {0} ", m_contactName);
if (!string.IsNullOrEmpty(m_contactEmail))
{
actionText.AppendFormat("via email at {0}", m_contactEmail);
if (!string.IsNullOrEmpty(m_contactPhone))
{
actionText.Append(" or ");
}
}
if (!string.IsNullOrEmpty(m_contactPhone))
{
actionText.AppendFormat("via phone at {0}", m_contactPhone);
}
actionText.Append(".");
}
return actionText.ToString();
}
///
/// Default for .
///
private string GetMoreInfoText()
{
string bullet = string.Empty;
switch (ApplicationType)
{
case ApplicationType.WindowsCui:
bullet = "-";
break;
case ApplicationType.Web:
case ApplicationType.WindowsGui:
bullet = "•";
break;
}
StringBuilder moreInfoText = new StringBuilder();
moreInfoText.Append("The following information about the error was automatically captured:");
moreInfoText.AppendLine();
moreInfoText.AppendLine();
if (m_logToScreenshot)
{
moreInfoText.AppendFormat(" {0} ", bullet);
if (m_logToScreenshotOK)
{
moreInfoText.Append("a screenshot was taken of the desktop at:");
moreInfoText.AppendLine();
moreInfoText.Append(" ");
moreInfoText.Append(GetScreenshotFileName());
}
else
{
moreInfoText.Append("a screenshot could NOT be taken of the desktop.");
}
moreInfoText.AppendLine();
}
if (m_logToEventLog)
{
moreInfoText.AppendFormat(" {0} ", bullet);
if (m_logToEventLogOK)
{
moreInfoText.Append("an event was written to the application log");
}
else
{
moreInfoText.Append("an event could NOT be written to the application log");
}
moreInfoText.AppendLine();
}
if (m_logToFile)
{
moreInfoText.AppendFormat(" {0} ", bullet);
if (m_logToFileOK)
{
moreInfoText.Append("details were written to a text log at:");
}
else
{
moreInfoText.Append("details could NOT be written to the text log at:");
}
moreInfoText.AppendLine();
moreInfoText.Append(" ");
moreInfoText.Append(m_errorLog.Name);
moreInfoText.AppendLine();
}
if (m_logToDatabase)
{
moreInfoText.AppendFormat(" {0} ", bullet);
if (m_logToDatabaseOK)
{
moreInfoText.Append("details were written to the database log");
}
else
{
moreInfoText.Append("details could NOT be written to the database log");
}
moreInfoText.AppendLine();
}
if (m_logToEmail)
{
moreInfoText.AppendFormat(" {0} ", bullet);
if (m_logToEmailOK)
{
moreInfoText.Append("an email has been sent to:");
}
else
{
moreInfoText.Append("an email could NOT be sent to:");
}
moreInfoText.AppendLine();
moreInfoText.Append(" ");
moreInfoText.Append(m_contactEmail);
moreInfoText.AppendLine();
}
moreInfoText.AppendLine();
moreInfoText.AppendLine();
moreInfoText.Append("Detailed error information follows:");
moreInfoText.AppendLine();
moreInfoText.AppendLine();
moreInfoText.Append(GetExceptionInfo(m_lastException, m_logUserInfo));
return moreInfoText.ToString();
}
private string GetScreenshotFileName()
{
return FilePath.GetAbsolutePath(ApplicationName + ".ErrorState.png");
}
private void ThreadException(object sender, ThreadExceptionEventArgs e)
{
m_suppressInteractiveLogging = false;
Log(new Exception("ThreadException", e.Exception), m_exitOnUnhandledException);
}
private void UnhandledException(object sender, UnhandledExceptionEventArgs e)
{
// Almost always (starting .NET 2.0) when the AppDomain.UnhandledException event is raised, .NET CLR
// will terminate the application after all the handlers for the event have been processed. So, if
// .NET CLR is going to terminate the application, we terminate the application before .NET CLR does
// in order to prevent the .NET "Application has encountered a problem and needs to close" error.
// See: http://msdn.microsoft.com/en-us/library/system.unhandledexceptioneventargs.isterminating.aspx
m_suppressInteractiveLogging = false;
Log(new Exception("UnhandledException", (Exception)e.ExceptionObject), e.IsTerminating);
}
#endregion
#region [ Static ]
// Static Methods
///
/// Deletes old record from database.
///
/// to connection to database.
private static void RestoreLogSize(IDbConnection dbConnection)
{
string query = string.Empty;
int minIDToDelete = 0;
try
{
while (Convert.ToInt32(dbConnection.ExecuteScalar(string.Format("SELECT COUNT(*) FROM ErrorLog"))) >= DefaultExceptionLogSize)
{
minIDToDelete = Convert.ToInt32(dbConnection.ExecuteScalar(string.Format("SELECT MIN(ID) FROM ErrorLog")));
dbConnection.ExecuteNonQuery(string.Format("DELETE FROM ErrorLog WHERE ID = {0}", minIDToDelete));
}
}
catch
{
// Do nothing at this time.
}
}
///
/// Logs information about an encountered exception to the backend datastore.
///
/// Source of exception.
/// Message section of the exception.
/// Detailed description of exception.
/// Type of exception.
public static void LogErrorToDatabase(String source, String message, String detail, String type)
{
try
{
string parameterizedQueryString;
using (AdoDataConnection dbConnection = new AdoDataConnection("systemSettings"))
{
// Remove old entry for keeping table size limited to 2000.
RestoreLogSize(dbConnection.Connection);
parameterizedQueryString = dbConnection.ParameterizedQueryString("INSERT INTO ErrorLog (Source, Type, Message, Detail) VALUES ({0}, {1}, {2}, {3})", "source", "type", "message", "detail");
dbConnection.Connection.ExecuteNonQuery(parameterizedQueryString, source, type, message, detail);
}
}
catch
{
// Do nothing, if exceptions are raised during error logging.
}
}
///
/// Gets information about an complete with system and application information.
///
/// whose information is to be retrieved.
/// true if user information is to be include; otherwise false.
/// information in text.
public static string GetExceptionInfo(Exception ex, bool includeUserInfo)
{
StringBuilder info = new StringBuilder();
if ((object)ex.InnerException != null)
{
// Sometimes the original exception is wrapped in a more relevant outer exception
// the detail exception is the "inner" exception
// See: http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnbda/html/exceptdotnet.asp
info.Append("(Inner Exception)");
info.AppendLine();
info.Append(GetExceptionInfo(ex.InnerException, includeUserInfo));
info.AppendLine();
info.Append("(Outer Exception)");
info.AppendLine();
}
// Get general system information.
info.Append(GetSystemInfo(includeUserInfo));
info.AppendLine();
// Get general application information.
info.Append(GetApplicationInfo());
info.AppendLine();
// Get general exception information.
info.Append(GetExceptionGeneralInfo(ex));
info.AppendLine();
// Get the stack trace for the exception.
info.Append("---- Stack Trace ----");
info.AppendLine();
info.Append(GetExceptionStackTrace(ex));
info.AppendLine();
return info.ToString();
}
///
/// Gets information about the system where current application is executing.
///
/// true if user information is to be include; otherwise false.
/// System information in text.
private static string GetSystemInfo(bool includeUserInfo)
{
StringBuilder info = new StringBuilder();
info.AppendFormat("Date and Time: {0}", DateTime.Now);
info.AppendLine();
switch (Common.GetApplicationType())
{
case ApplicationType.WindowsCui:
case ApplicationType.WindowsGui:
info.AppendFormat("Machine Name: {0}", Environment.MachineName);
info.AppendLine();
info.AppendFormat("Machine IP: {0}", Dns.GetHostEntry(Environment.MachineName).AddressList[0]);
info.AppendLine();
info.AppendFormat("Machine OS: {0}", Environment.OSVersion.VersionString);
info.AppendLine();
if (includeUserInfo)
{
UserInfo currentUserInfo = UserInfo.CurrentUserInfo;
info.AppendFormat("Current User ID: {0}", currentUserInfo.LoginID);
info.AppendLine();
info.AppendFormat("Current User Name: {0}", currentUserInfo.FullName);
info.AppendLine();
info.AppendFormat("Current User Phone: {0}", currentUserInfo.Telephone);
info.AppendLine();
info.AppendFormat("Current User Email: {0}", currentUserInfo.Email);
info.AppendLine();
}
break;
case ApplicationType.Web:
info.AppendFormat("Server Name: {0}", Environment.MachineName);
info.AppendLine();
info.AppendFormat("Server IP: {0}", Dns.GetHostEntry(Environment.MachineName).AddressList[0]);
info.AppendLine();
info.AppendFormat("Server OS: {0}", Environment.OSVersion.VersionString);
info.AppendLine();
if (includeUserInfo)
{
UserInfo remoteUserInfo = UserInfo.RemoteUserInfo;
info.AppendFormat("Process User: {0}", UserInfo.CurrentUserID);
info.AppendLine();
info.AppendFormat("Remote User ID: {0}", remoteUserInfo.LoginID);
info.AppendLine();
info.AppendFormat("Remote User Name: {0}", remoteUserInfo.FullName);
info.AppendLine();
info.AppendFormat("Remote User Phone: {0}", remoteUserInfo.Telephone);
info.AppendLine();
info.AppendFormat("Remote User Email: {0}", remoteUserInfo.Email);
info.AppendLine();
}
info.AppendFormat("Remote Host: {0}", HttpContext.Current.Request.ServerVariables["REMOTE_HOST"]);
info.AppendLine();
info.AppendFormat("Remote Address: {0}", HttpContext.Current.Request.ServerVariables["REMOTE_ADDR"]);
info.AppendLine();
info.AppendFormat("HTTP Agent: {0}", HttpContext.Current.Request.ServerVariables["HTTP_USER_AGENT"]);
info.AppendLine();
info.AppendFormat("HTTP Referer: {0}", HttpContext.Current.Request.ServerVariables["HTTP_REFERER"]);
info.AppendLine();
info.AppendFormat("Web Page URL: {0}", HttpContext.Current.Request.Url);
info.AppendLine();
break;
}
return info.ToString();
}
///
/// Gets information about the current application.
///
/// Application information in text.
private static string GetApplicationInfo()
{
Assembly parentAssembly = null;
switch (Common.GetApplicationType())
{
case ApplicationType.WindowsCui:
case ApplicationType.WindowsGui:
// For a windows application the entry assembly will be the executable.
parentAssembly = Assembly.GetEntryAssembly();
break;
case ApplicationType.Web:
// For a web site in .Net 2.0 we don't have an entry assembly. However, at this point the
// calling assembly will be consumer of this function (i.e. one of the web site DLLs).
// See: http://msdn.microsoft.com/msdnmag/issues/06/01/ExtremeASPNET/
parentAssembly = Assembly.GetCallingAssembly();
break;
}
StringBuilder info = new StringBuilder();
AssemblyInfo parentAssemblyInfo = new AssemblyInfo(parentAssembly);
info.AppendFormat("Application Domain: {0}", AppDomain.CurrentDomain.FriendlyName);
info.AppendLine();
info.AppendFormat("Assembly Codebase: {0}", parentAssemblyInfo.CodeBase);
info.AppendLine();
info.AppendFormat("Assembly Full Name: {0}", parentAssemblyInfo.FullName);
info.AppendLine();
info.AppendFormat("Assembly Version: {0}", parentAssemblyInfo.Version);
info.AppendLine();
info.AppendFormat("Assembly Build Date: {0}", parentAssemblyInfo.BuildDate.ToString());
info.AppendLine();
info.AppendFormat(".Net Runtime Version: {0}", Environment.Version);
info.AppendLine();
return info.ToString();
}
///
/// Gets common information about an .
///
/// whose common information is to be retrieved.
/// Common information in text.
private static string GetExceptionGeneralInfo(Exception ex)
{
StringBuilder info = new StringBuilder();
info.AppendFormat("Exception Source: {0}", ex.Source);
info.AppendLine();
info.AppendFormat("Exception Type: {0}", ex.GetType().FullName);
info.AppendLine();
info.AppendFormat("Exception Message: {0}", ex.Message);
info.AppendLine();
if ((object)ex.TargetSite != null)
{
info.AppendFormat("Exception Target Site: {0}", ex.TargetSite.Name);
info.AppendLine();
}
return info.ToString();
}
///
/// Gets stack trace information about an .
///
/// whose stack trace information is to be retrieved.
/// stack trace in text.
private static string GetExceptionStackTrace(Exception ex)
{
StringBuilder trace = new StringBuilder();
StackTrace stack = new StackTrace(ex, true);
for (int i = 0; i < stack.FrameCount; i++)
{
StackFrame stackFrame = stack.GetFrame(i);
MemberInfo method = stackFrame.GetMethod();
string codeFileName = stackFrame.GetFileName();
// Build method name.
trace.AppendFormat(" {0}.{1}.{2}", method.DeclaringType.Namespace, method.DeclaringType.Name, method.Name);
// Build method params.
trace.Append("(");
int parameterCount = 0;
foreach (ParameterInfo parameter in stackFrame.GetMethod().GetParameters())
{
parameterCount++;
if (parameterCount > 1)
{
trace.Append(", ");
}
trace.AppendFormat("{0} As {1}", parameter.Name, parameter.ParameterType.Name);
}
trace.Append(")");
trace.AppendLine();
// If source code is available, append location info.
trace.Append(" ");
if (!string.IsNullOrEmpty(codeFileName))
{
trace.Append(FilePath.GetFileName(codeFileName));
trace.AppendFormat(": Ln {0:#0000}", stackFrame.GetFileLineNumber());
trace.AppendFormat(", Col {0:#00}", stackFrame.GetFileColumnNumber());
// If IL is available, append IL location info.
if (stackFrame.GetILOffset() != StackFrame.OFFSET_UNKNOWN)
{
trace.AppendFormat(", IL {0:#0000}", stackFrame.GetILOffset());
}
}
else
{
ApplicationType appType = Common.GetApplicationType();
if (appType == ApplicationType.WindowsCui || appType == ApplicationType.WindowsGui)
{
trace.Append(FilePath.GetFileName(Assembly.GetEntryAssembly().CodeBase));
}
else
{
trace.Append("(unknown file)");
}
// Native code offset is always available.
trace.AppendFormat(": N {0:#00000}", stackFrame.GetNativeOffset());
}
trace.AppendLine();
}
return trace.ToString();
}
#endregion
}
}