673 lines
27 KiB
C#
673 lines
27 KiB
C#
|
|
//===============================================================================
|
||
|
|
// Microsoft Exception Management Application Block for .NET
|
||
|
|
// http://msdn.microsoft.com/library/en-us/dnbda/html/emab-rm.asp
|
||
|
|
//
|
||
|
|
// ExceptionManager.cs
|
||
|
|
// This file contains the ExceptionManager class, which manages all publishing
|
||
|
|
// of exceptions, and the default publisher class, which publishes exception
|
||
|
|
// information to the Event Log.
|
||
|
|
//
|
||
|
|
// For more information see the Implementing the Exception Manager Component
|
||
|
|
// section of the Exception Management Application Block Implementation Overview.
|
||
|
|
//===============================================================================
|
||
|
|
// Copyright (C) 2000-2001 Microsoft Corporation
|
||
|
|
// All rights reserved.
|
||
|
|
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY
|
||
|
|
// OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT
|
||
|
|
// LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR
|
||
|
|
// FITNESS FOR A PARTICULAR PURPOSE.
|
||
|
|
//===============================================================================
|
||
|
|
|
||
|
|
using System;
|
||
|
|
using System.Collections.Specialized;
|
||
|
|
using System.Configuration;
|
||
|
|
using System.Reflection;
|
||
|
|
using System.Resources;
|
||
|
|
using System.Runtime.Serialization;
|
||
|
|
using System.Security;
|
||
|
|
using System.Security.Principal;
|
||
|
|
using System.Text;
|
||
|
|
using System.Threading;
|
||
|
|
using System.Xml;
|
||
|
|
|
||
|
|
namespace AyAEM.ExceptionManagement
|
||
|
|
{
|
||
|
|
#region ExceptionManager Class
|
||
|
|
/// <summary>
|
||
|
|
/// The Exception Manager class manages the publishing of exception information based on settings in the configuration file.
|
||
|
|
/// </summary>
|
||
|
|
public sealed class ExceptionManager
|
||
|
|
{
|
||
|
|
/// <summary>
|
||
|
|
/// Private constructor to restrict an instance of this class from being created.
|
||
|
|
/// </summary>
|
||
|
|
private ExceptionManager()
|
||
|
|
{
|
||
|
|
}
|
||
|
|
|
||
|
|
// Member variable declarations
|
||
|
|
private const string EXCEPTIONMANAGEMENT_CONFIG_SECTION = "exceptionManagement";
|
||
|
|
private readonly static string EXCEPTIONMANAGER_NAME = typeof(ExceptionManager).Name;
|
||
|
|
|
||
|
|
// Resource Manager for localized text.
|
||
|
|
// Stuff fixed when access is denied to write and when there is not way to send email
|
||
|
|
private static ResourceManager resourceManager = new ResourceManager("AyAEM.ExceptionManagerText", Assembly.GetExecutingAssembly());
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// Static method to publish the exception information.
|
||
|
|
/// </summary>
|
||
|
|
/// <param name="exception">The exception object whose information should be published.</param>
|
||
|
|
public static void Publish(Exception exception)
|
||
|
|
{
|
||
|
|
ExceptionManager.Publish(exception, null);
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// Static method to publish the exception information and any additional information.
|
||
|
|
/// </summary>
|
||
|
|
/// <param name="exception">The exception object whose information should be published.</param>
|
||
|
|
/// <param name="additionalInfo">A collection of additional data that should be published along with the exception information.</param>
|
||
|
|
public static void Publish(Exception exception, NameValueCollection additionalInfo)
|
||
|
|
{
|
||
|
|
try
|
||
|
|
{
|
||
|
|
#region Load the AdditionalInformation Collection with environment data.
|
||
|
|
// Create the Additional Information collection if it does not exist.
|
||
|
|
if (null == additionalInfo) additionalInfo = new NameValueCollection();
|
||
|
|
|
||
|
|
// Add environment information to the information collection.
|
||
|
|
try
|
||
|
|
{
|
||
|
|
additionalInfo.Add(EXCEPTIONMANAGER_NAME + ".MachineName", Environment.MachineName);
|
||
|
|
}
|
||
|
|
catch(SecurityException)
|
||
|
|
{
|
||
|
|
additionalInfo.Add(EXCEPTIONMANAGER_NAME + ".MachineName", resourceManager.GetString("RES_EXCEPTIONMANAGEMENT_PERMISSION_DENIED"));
|
||
|
|
}
|
||
|
|
catch
|
||
|
|
{
|
||
|
|
additionalInfo.Add(EXCEPTIONMANAGER_NAME + ".MachineName", resourceManager.GetString("RES_EXCEPTIONMANAGEMENT_INFOACCESS_EXCEPTION"));
|
||
|
|
}
|
||
|
|
|
||
|
|
try
|
||
|
|
{
|
||
|
|
additionalInfo.Add(EXCEPTIONMANAGER_NAME + ".TimeStamp", DateTime.Now.ToString());
|
||
|
|
}
|
||
|
|
catch(SecurityException)
|
||
|
|
{
|
||
|
|
additionalInfo.Add(EXCEPTIONMANAGER_NAME + ".TimeStamp",resourceManager.GetString("RES_EXCEPTIONMANAGEMENT_PERMISSION_DENIED"));
|
||
|
|
}
|
||
|
|
catch
|
||
|
|
{
|
||
|
|
additionalInfo.Add(EXCEPTIONMANAGER_NAME + ".TimeStamp", resourceManager.GetString("RES_EXCEPTIONMANAGEMENT_INFOACCESS_EXCEPTION"));
|
||
|
|
}
|
||
|
|
|
||
|
|
try
|
||
|
|
{
|
||
|
|
additionalInfo.Add(EXCEPTIONMANAGER_NAME + ".FullName", Assembly.GetExecutingAssembly().FullName);
|
||
|
|
}
|
||
|
|
catch(SecurityException)
|
||
|
|
{
|
||
|
|
additionalInfo.Add(EXCEPTIONMANAGER_NAME + ".FullName", resourceManager.GetString("RES_EXCEPTIONMANAGEMENT_PERMISSION_DENIED"));
|
||
|
|
}
|
||
|
|
catch
|
||
|
|
{
|
||
|
|
additionalInfo.Add(EXCEPTIONMANAGER_NAME + ".FullName", resourceManager.GetString("RES_EXCEPTIONMANAGEMENT_INFOACCESS_EXCEPTION"));
|
||
|
|
}
|
||
|
|
|
||
|
|
try
|
||
|
|
{
|
||
|
|
additionalInfo.Add(EXCEPTIONMANAGER_NAME + ".AppDomainName", AppDomain.CurrentDomain.FriendlyName);
|
||
|
|
}
|
||
|
|
catch(SecurityException)
|
||
|
|
{
|
||
|
|
additionalInfo.Add(EXCEPTIONMANAGER_NAME + ".AppDomainName", resourceManager.GetString("RES_EXCEPTIONMANAGEMENT_PERMISSION_DENIED"));
|
||
|
|
}
|
||
|
|
catch
|
||
|
|
{
|
||
|
|
additionalInfo.Add(EXCEPTIONMANAGER_NAME + ".AppDomainName", resourceManager.GetString("RES_EXCEPTIONMANAGEMENT_INFOACCESS_EXCEPTION"));
|
||
|
|
}
|
||
|
|
|
||
|
|
try
|
||
|
|
{
|
||
|
|
additionalInfo.Add(EXCEPTIONMANAGER_NAME + ".ThreadIdentity", Thread.CurrentPrincipal.Identity.Name);
|
||
|
|
}
|
||
|
|
catch(SecurityException)
|
||
|
|
{
|
||
|
|
additionalInfo.Add(EXCEPTIONMANAGER_NAME + ".ThreadIdentity", resourceManager.GetString("RES_EXCEPTIONMANAGEMENT_PERMISSION_DENIED"));
|
||
|
|
}
|
||
|
|
catch
|
||
|
|
{
|
||
|
|
additionalInfo.Add(EXCEPTIONMANAGER_NAME + ".ThreadIdentity", resourceManager.GetString("RES_EXCEPTIONMANAGEMENT_INFOACCESS_EXCEPTION"));
|
||
|
|
}
|
||
|
|
|
||
|
|
try
|
||
|
|
{
|
||
|
|
additionalInfo.Add(EXCEPTIONMANAGER_NAME + ".WindowsIdentity", WindowsIdentity.GetCurrent().Name);
|
||
|
|
}
|
||
|
|
catch(SecurityException)
|
||
|
|
{
|
||
|
|
additionalInfo.Add(EXCEPTIONMANAGER_NAME + ".WindowsIdentity", resourceManager.GetString("RES_EXCEPTIONMANAGEMENT_PERMISSION_DENIED"));
|
||
|
|
}
|
||
|
|
catch
|
||
|
|
{
|
||
|
|
additionalInfo.Add(EXCEPTIONMANAGER_NAME + ".WindowsIdentity", resourceManager.GetString("RES_EXCEPTIONMANAGEMENT_INFOACCESS_EXCEPTION"));
|
||
|
|
}
|
||
|
|
|
||
|
|
#endregion
|
||
|
|
|
||
|
|
#region Publish the exception based on Configuration Settings
|
||
|
|
// Check for any settings in config file.
|
||
|
|
|
||
|
|
if (ConfigurationManager.GetSection(EXCEPTIONMANAGEMENT_CONFIG_SECTION) == null)
|
||
|
|
{
|
||
|
|
// Publish the exception and additional information to the default publisher if no settings are present.
|
||
|
|
PublishToDefaultPublisher(exception, additionalInfo);
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
// Get settings from config file
|
||
|
|
ExceptionManagementSettings config = (ExceptionManagementSettings)ConfigurationManager.GetSection(EXCEPTIONMANAGEMENT_CONFIG_SECTION);
|
||
|
|
|
||
|
|
// If the mode is not equal to "off" call the Publishers, otherwise do nothing.
|
||
|
|
if (config.Mode == ExceptionManagementMode.On)
|
||
|
|
{
|
||
|
|
// If no publishers are specified, use the default publisher.
|
||
|
|
if (config.Publishers == null || config.Publishers.Count == 0)
|
||
|
|
{
|
||
|
|
// Publish the exception and additional information to the default publisher if no mode is specified.
|
||
|
|
PublishToDefaultPublisher(exception, additionalInfo);
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
#region Iterate through the publishers
|
||
|
|
// Loop through the publisher components specified in the config file.
|
||
|
|
foreach(PublisherSettings Publisher in config.Publishers)
|
||
|
|
{
|
||
|
|
// Call the Publisher component specified in the config file.
|
||
|
|
try
|
||
|
|
{
|
||
|
|
// Verify the publishers mode is not set to "OFF".
|
||
|
|
// This publisher will be called even if the mode is not specified.
|
||
|
|
// The mode must explicitly be set to OFF to not be called.
|
||
|
|
if (Publisher.Mode == PublisherMode.On)
|
||
|
|
{
|
||
|
|
//if (exception == null || !Publisher.IsExceptionFiltered(exception.GetType()))
|
||
|
|
if (exception != null)
|
||
|
|
{
|
||
|
|
// Publish the exception and any additional information
|
||
|
|
PublishToCustomPublisher(exception, additionalInfo, Publisher);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
// Catches any failure to call a custom publisher.
|
||
|
|
catch(Exception e)
|
||
|
|
{
|
||
|
|
// Publish the exception thrown when trying to call the custom publisher.
|
||
|
|
PublishInternalException(e,null);
|
||
|
|
|
||
|
|
// Publish the original exception and additional information to the default publisher.
|
||
|
|
PublishToDefaultPublisher(exception, additionalInfo);
|
||
|
|
|
||
|
|
} // End Catch block.
|
||
|
|
|
||
|
|
} // End foreach loop through publishers.
|
||
|
|
#endregion
|
||
|
|
} // End else statement when custom publishers are in the config settings.
|
||
|
|
|
||
|
|
} // End else statement where config settings are not set to "OFF"
|
||
|
|
|
||
|
|
} // End else statement when config settings are provided.
|
||
|
|
#endregion
|
||
|
|
}
|
||
|
|
catch(Exception e)
|
||
|
|
{
|
||
|
|
// Publish the exception thrown within the ExceptionManager.
|
||
|
|
PublishInternalException(e,null);
|
||
|
|
|
||
|
|
// Publish the original exception and additional information to the default publisher.
|
||
|
|
PublishToDefaultPublisher(exception, additionalInfo);
|
||
|
|
}
|
||
|
|
} // End Publish(Exception exception, NameValueCollection AdditionalInfo)
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// Private static helper method to publish the exception information to a custom publisher.
|
||
|
|
/// </summary>
|
||
|
|
/// <param name="exception">The exception object whose information should be published.</param>
|
||
|
|
/// <param name="additionalInfo">A collection of additional data that should be published along with the exception information.</param>
|
||
|
|
/// <param name="publisher">The PublisherSettings that contains the values of the publishers configuration.</param>
|
||
|
|
private static void PublishToCustomPublisher(Exception exception, NameValueCollection additionalInfo, PublisherSettings publisher)
|
||
|
|
{
|
||
|
|
try
|
||
|
|
{
|
||
|
|
// Check if the exception format is "xml".
|
||
|
|
if (publisher.ExceptionFormat == PublisherFormat.Xml)
|
||
|
|
{
|
||
|
|
// If it is load the IExceptionXmlPublisher interface on the custom publisher.
|
||
|
|
|
||
|
|
// Instantiate the class
|
||
|
|
IExceptionXmlPublisher XMLPublisher = (IExceptionXmlPublisher)Activate(publisher.AssemblyName, publisher.TypeName);
|
||
|
|
|
||
|
|
// Publish the exception and any additional information
|
||
|
|
//XMLPublisher.Publish(SerializeToXml(exception, additionalInfo),publisher.OtherAttributes);
|
||
|
|
}
|
||
|
|
// Otherwise load the IExceptionPublisher interface on the custom publisher.
|
||
|
|
else
|
||
|
|
{
|
||
|
|
// Instantiate the class
|
||
|
|
IExceptionPublisher Publisher = (IExceptionPublisher)Activate(publisher.AssemblyName, publisher.TypeName);
|
||
|
|
|
||
|
|
// Publish the exception and any additional information
|
||
|
|
Publisher.Publish(exception, additionalInfo, publisher.OtherAttributes);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
catch(Exception e)
|
||
|
|
{
|
||
|
|
CustomPublisherException publisherException = new CustomPublisherException(resourceManager.GetString("RES_CUSTOM_PUBLISHER_FAILURE_MESSAGE"), publisher.AssemblyName, publisher.TypeName, publisher.ExceptionFormat, e);
|
||
|
|
publisherException.AdditionalInformation.Add(publisher.OtherAttributes);
|
||
|
|
|
||
|
|
throw(publisherException);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// Private static helper method to publish the exception information to the default publisher.
|
||
|
|
/// </summary>
|
||
|
|
/// <param name="exception">The exception object whose information should be published.</param>
|
||
|
|
/// <param name="additionalInfo">A collection of additional data that should be published along with the exception information.</param>
|
||
|
|
private static void PublishToDefaultPublisher(Exception exception, NameValueCollection additionalInfo)
|
||
|
|
{
|
||
|
|
// Get the Default Publisher
|
||
|
|
DefaultPublisher Publisher = new DefaultPublisher();
|
||
|
|
|
||
|
|
// Publish the exception and any additional information
|
||
|
|
Publisher.Publish(exception, additionalInfo, null);
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// Private static helper method to publish the exception information to the default publisher.
|
||
|
|
/// </summary>
|
||
|
|
/// <param name="exception">The exception object whose information should be published.</param>
|
||
|
|
/// <param name="additionalInfo">A collection of additional data that should be published along with the exception information.</param>
|
||
|
|
internal static void PublishInternalException(Exception exception, NameValueCollection additionalInfo)
|
||
|
|
{
|
||
|
|
// Get the Default Publisher
|
||
|
|
DefaultPublisher Publisher = new DefaultPublisher("Application", resourceManager.GetString("RES_EXCEPTIONMANAGER_INTERNAL_EXCEPTIONS"));
|
||
|
|
|
||
|
|
// Publish the exception and any additional information
|
||
|
|
Publisher.Publish(exception, additionalInfo, null);
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// Private helper function to assist in run-time activations. Returns
|
||
|
|
/// an object from the specified assembly and type.
|
||
|
|
/// </summary>
|
||
|
|
/// <param name="assembly">Name of the assembly file (w/out extension)</param>
|
||
|
|
/// <param name="typeName">Name of the type to create</param>
|
||
|
|
/// <returns>Instance of the type specified in the input parameters.</returns>
|
||
|
|
private static object Activate(string assembly, string typeName)
|
||
|
|
{
|
||
|
|
return AppDomain.CurrentDomain.CreateInstanceAndUnwrap(assembly, typeName);
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// Public static helper method to serialize the exception information into XML.
|
||
|
|
/// </summary>
|
||
|
|
/// <param name="exception">The exception object whose information should be published.</param>
|
||
|
|
/// <param name="additionalInfo">A collection of additional data that should be published along with the exception information.</param>
|
||
|
|
public static XmlDocument SerializeToXml(Exception exception, NameValueCollection additionalInfo)
|
||
|
|
{
|
||
|
|
try
|
||
|
|
{
|
||
|
|
// Variables representing the XmlElement names.
|
||
|
|
|
||
|
|
string ROOT = resourceManager.GetString("RES_XML_ROOT");
|
||
|
|
string ADDITIONAL_INFORMATION = resourceManager.GetString("RES_XML_ADDITIONAL_INFORMATION");
|
||
|
|
string EXCEPTION = resourceManager.GetString("RES_XML_EXCEPTION");
|
||
|
|
string STACK_TRACE = resourceManager.GetString("RES_XML_STACK_TRACE");
|
||
|
|
|
||
|
|
// Create a new XmlDocument.
|
||
|
|
XmlDocument xmlDoc = new XmlDocument();
|
||
|
|
|
||
|
|
// Create the root node.
|
||
|
|
XmlElement root = xmlDoc.CreateElement(ROOT);
|
||
|
|
xmlDoc.AppendChild(root);
|
||
|
|
|
||
|
|
// Variables to hold values while looping through the exception chain.
|
||
|
|
XmlElement element;
|
||
|
|
XmlElement exceptionAddInfoElement;
|
||
|
|
XmlElement stackTraceElement;
|
||
|
|
XmlText stackTraceText;
|
||
|
|
XmlAttribute attribute;
|
||
|
|
|
||
|
|
#region Add values from AdditionalInfo to the XML Doc
|
||
|
|
// Check if the collection has values.
|
||
|
|
if (additionalInfo != null && additionalInfo.Count > 0)
|
||
|
|
{
|
||
|
|
// Create the element for the collection.
|
||
|
|
element = xmlDoc.CreateElement(ADDITIONAL_INFORMATION);
|
||
|
|
|
||
|
|
// Loop through the collection and add the values as attributes on the element.
|
||
|
|
foreach (string i in additionalInfo)
|
||
|
|
{
|
||
|
|
attribute = xmlDoc.CreateAttribute(i.Replace(" ", "_"));
|
||
|
|
attribute.Value = additionalInfo.Get(i);
|
||
|
|
element.Attributes.Append(attribute);
|
||
|
|
}
|
||
|
|
|
||
|
|
// Add the element to the root.
|
||
|
|
root.AppendChild(element);
|
||
|
|
}
|
||
|
|
#endregion
|
||
|
|
|
||
|
|
if (exception == null)
|
||
|
|
{
|
||
|
|
// Create an empty exception element.
|
||
|
|
element = xmlDoc.CreateElement(EXCEPTION);
|
||
|
|
|
||
|
|
// Append to the root node.
|
||
|
|
root.AppendChild(element);
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
#region Loop through each exception class in the chain of exception objects and record its information
|
||
|
|
// Loop through each exception class in the chain of exception objects.
|
||
|
|
Exception currentException = exception; // Temp variable to hold InnerException object during the loop.
|
||
|
|
XmlElement parentElement = null; // Temp variable to hold the parent exception node during the loop.
|
||
|
|
do
|
||
|
|
{
|
||
|
|
// Create the exception element.
|
||
|
|
element = xmlDoc.CreateElement(EXCEPTION);
|
||
|
|
|
||
|
|
// Add the exceptionType as an attribute.
|
||
|
|
attribute = xmlDoc.CreateAttribute("ExceptionType");
|
||
|
|
attribute.Value = currentException.GetType().FullName;
|
||
|
|
element.Attributes.Append(attribute);
|
||
|
|
|
||
|
|
#region Loop through the public properties of the exception object and record their value
|
||
|
|
// Loop through the public properties of the exception object and record their value.
|
||
|
|
PropertyInfo[] aryPublicProperties = currentException.GetType().GetProperties();
|
||
|
|
NameValueCollection currentAdditionalInfo;
|
||
|
|
foreach (PropertyInfo p in aryPublicProperties)
|
||
|
|
{
|
||
|
|
// Do not log information for the InnerException or StackTrace. This information is
|
||
|
|
// captured later in the process.
|
||
|
|
if (p.Name != "InnerException" && p.Name != "StackTrace")
|
||
|
|
{
|
||
|
|
// Only record properties whose value is not null.
|
||
|
|
if (p.GetValue(currentException,null) != null)
|
||
|
|
{
|
||
|
|
// Check if the property is AdditionalInformation and the exception type is a BaseApplicationException.
|
||
|
|
if (p.Name == "AdditionalInformation" && currentException is BaseApplicationException)
|
||
|
|
{
|
||
|
|
// Verify the collection is not null.
|
||
|
|
if (p.GetValue(currentException,null) != null)
|
||
|
|
{
|
||
|
|
// Cast the collection into a local variable.
|
||
|
|
currentAdditionalInfo = (NameValueCollection)p.GetValue(currentException,null);
|
||
|
|
|
||
|
|
// Verify the collection has values.
|
||
|
|
if (currentAdditionalInfo.Count > 0)
|
||
|
|
{
|
||
|
|
// Create element.
|
||
|
|
exceptionAddInfoElement = xmlDoc.CreateElement(ADDITIONAL_INFORMATION);
|
||
|
|
|
||
|
|
// Loop through the collection and add values as attributes.
|
||
|
|
foreach (string i in currentAdditionalInfo)
|
||
|
|
{
|
||
|
|
attribute = xmlDoc.CreateAttribute(i.Replace(" ", "_"));
|
||
|
|
attribute.Value = currentAdditionalInfo.Get(i);
|
||
|
|
exceptionAddInfoElement.Attributes.Append(attribute);
|
||
|
|
}
|
||
|
|
|
||
|
|
element.AppendChild(exceptionAddInfoElement);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
// Otherwise just add the ToString() value of the property as an attribute.
|
||
|
|
else
|
||
|
|
{
|
||
|
|
attribute = xmlDoc.CreateAttribute(p.Name);
|
||
|
|
attribute.Value = p.GetValue(currentException,null).ToString();
|
||
|
|
element.Attributes.Append(attribute);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
#endregion
|
||
|
|
|
||
|
|
#region Record the exception StackTrace
|
||
|
|
// Record the StackTrace within a separate element.
|
||
|
|
if (currentException.StackTrace != null)
|
||
|
|
{
|
||
|
|
// Create Stack Trace Element.
|
||
|
|
stackTraceElement = xmlDoc.CreateElement(STACK_TRACE);
|
||
|
|
|
||
|
|
stackTraceText = xmlDoc.CreateTextNode(currentException.StackTrace.ToString());
|
||
|
|
|
||
|
|
stackTraceElement.AppendChild(stackTraceText);
|
||
|
|
|
||
|
|
element.AppendChild(stackTraceElement);
|
||
|
|
}
|
||
|
|
#endregion
|
||
|
|
|
||
|
|
// Check if this is the first exception in the chain.
|
||
|
|
if (parentElement == null)
|
||
|
|
{
|
||
|
|
// Append to the root node.
|
||
|
|
root.AppendChild(element);
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
// Append to the parent exception object in the exception chain.
|
||
|
|
parentElement.AppendChild(element);
|
||
|
|
}
|
||
|
|
|
||
|
|
// Reset the temp variables.
|
||
|
|
parentElement = element;
|
||
|
|
currentException = currentException.InnerException;
|
||
|
|
|
||
|
|
// Continue looping until we reach the end of the exception chain.
|
||
|
|
} while (currentException != null);
|
||
|
|
#endregion
|
||
|
|
}
|
||
|
|
// Return the XmlDocument.
|
||
|
|
return xmlDoc;
|
||
|
|
}
|
||
|
|
catch(Exception e)
|
||
|
|
{
|
||
|
|
throw new SerializationException(resourceManager.GetString("RES_EXCEPTIONMANAGEMENT_XMLSERIALIZATION_EXCEPTION"),e);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
#endregion
|
||
|
|
|
||
|
|
#region DefaultPublisher Class
|
||
|
|
/// <summary>
|
||
|
|
/// Component used as the default publishing component if one is not specified in the config file.
|
||
|
|
/// </summary>
|
||
|
|
public sealed class DefaultPublisher : IExceptionPublisher
|
||
|
|
{
|
||
|
|
/// <summary>
|
||
|
|
/// Default Constructor.
|
||
|
|
/// </summary>
|
||
|
|
public DefaultPublisher()
|
||
|
|
{
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// Constructor allowing the log name and application names to be set.
|
||
|
|
/// </summary>
|
||
|
|
/// <param name="logName">The name of the log for the DefaultPublisher to use.</param>
|
||
|
|
/// <param name="applicationName">The name of the application. This is used as the Source name in the event log.</param>
|
||
|
|
public DefaultPublisher(string logName, string applicationName)
|
||
|
|
{
|
||
|
|
//this.logName = logName;
|
||
|
|
this.applicationName = applicationName;
|
||
|
|
}
|
||
|
|
|
||
|
|
// Resource Manager for localized text.
|
||
|
|
// Stuff fixed when access is denied to write and when there is not way to send email
|
||
|
|
private static ResourceManager resourceManager = new ResourceManager("AyAEM.ExceptionManagerText", Assembly.GetExecutingAssembly());
|
||
|
|
|
||
|
|
// Member variable declarations
|
||
|
|
//private string logName = "Application";
|
||
|
|
private string applicationName = resourceManager.GetString("RES_EXCEPTIONMANAGER_PUBLISHED_EXCEPTIONS");
|
||
|
|
private const string TEXT_SEPARATOR = "*********************************************";
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// Method used to publish exception information and additional information.
|
||
|
|
/// </summary>
|
||
|
|
/// <param name="exception">The exception object whose information should be published.</param>
|
||
|
|
/// <param name="additionalInfo">A collection of additional data that should be published along with the exception information.</param>
|
||
|
|
/// <param name="configSettings">A collection of any additional attributes provided in the config settings for the custom publisher.</param>
|
||
|
|
public void Publish(Exception exception, NameValueCollection additionalInfo, NameValueCollection configSettings)
|
||
|
|
{
|
||
|
|
// Load Config values if they are provided.
|
||
|
|
if (configSettings != null)
|
||
|
|
{
|
||
|
|
if (configSettings["applicationName"] != null && configSettings["applicationName"].Length > 0) applicationName = configSettings["applicationName"];
|
||
|
|
//if (configSettings["logName"] != null && configSettings["logName"].Length > 0) logName = configSettings["logName"];
|
||
|
|
}
|
||
|
|
|
||
|
|
// Verify that the Source exists before gathering exception information.
|
||
|
|
VerifyValidSource();
|
||
|
|
|
||
|
|
// Create StringBuilder to maintain publishing information.
|
||
|
|
StringBuilder strInfo = new StringBuilder();
|
||
|
|
|
||
|
|
#region Record the contents of the AdditionalInfo collection
|
||
|
|
// Record the contents of the AdditionalInfo collection.
|
||
|
|
if (additionalInfo != null)
|
||
|
|
{
|
||
|
|
// Record General information.
|
||
|
|
strInfo.AppendFormat("{0}General Information {0}{1}{0}Additional Info:", Environment.NewLine, TEXT_SEPARATOR);
|
||
|
|
|
||
|
|
foreach (string i in additionalInfo)
|
||
|
|
{
|
||
|
|
strInfo.AppendFormat("{0}{1}: {2}", Environment.NewLine, i, additionalInfo.Get(i));
|
||
|
|
}
|
||
|
|
}
|
||
|
|
#endregion
|
||
|
|
|
||
|
|
if (exception == null)
|
||
|
|
{
|
||
|
|
strInfo.AppendFormat("{0}{0}No Exception object has been provided.{0}", Environment.NewLine);
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
#region Loop through each exception class in the chain of exception objects
|
||
|
|
// Loop through each exception class in the chain of exception objects.
|
||
|
|
Exception currentException = exception; // Temp variable to hold InnerException object during the loop.
|
||
|
|
int intExceptionCount = 1; // Count variable to track the number of exceptions in the chain.
|
||
|
|
do
|
||
|
|
{
|
||
|
|
// Write title information for the exception object.
|
||
|
|
strInfo.AppendFormat("{0}{0}{1}) Exception Information{0}{2}", Environment.NewLine, intExceptionCount.ToString(), TEXT_SEPARATOR);
|
||
|
|
strInfo.AppendFormat("{0}Exception Type: {1}", Environment.NewLine, currentException.GetType().FullName);
|
||
|
|
strInfo.AppendFormat("{0}{0}---------------------{0}{1}", Environment.NewLine, " ");
|
||
|
|
|
||
|
|
#region Loop through the public properties of the exception object and record their value
|
||
|
|
// Loop through the public properties of the exception object and record their value.
|
||
|
|
PropertyInfo[] aryPublicProperties = currentException.GetType().GetProperties();
|
||
|
|
NameValueCollection currentAdditionalInfo;
|
||
|
|
foreach (PropertyInfo p in aryPublicProperties)
|
||
|
|
{
|
||
|
|
// Do not log information for the InnerException or StackTrace. This information is
|
||
|
|
// captured later in the process.
|
||
|
|
if (p.Name != "InnerException" && p.Name != "StackTrace")
|
||
|
|
{
|
||
|
|
if (p.GetValue(currentException,null) == null)
|
||
|
|
{
|
||
|
|
strInfo.AppendFormat("{0}{1}: NULL", Environment.NewLine, p.Name);
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
// Loop through the collection of AdditionalInformation if the exception type is a BaseApplicationException.
|
||
|
|
if (p.Name == "AdditionalInformation" && currentException is BaseApplicationException)
|
||
|
|
{
|
||
|
|
// Verify the collection is not null.
|
||
|
|
if (p.GetValue(currentException,null) != null)
|
||
|
|
{
|
||
|
|
// Cast the collection into a local variable.
|
||
|
|
currentAdditionalInfo = (NameValueCollection)p.GetValue(currentException,null);
|
||
|
|
|
||
|
|
// Check if the collection contains values.
|
||
|
|
if (currentAdditionalInfo.Count > 0)
|
||
|
|
{
|
||
|
|
strInfo.AppendFormat("{0}AdditionalInformation:", Environment.NewLine);
|
||
|
|
|
||
|
|
// Loop through the collection adding the information to the string builder.
|
||
|
|
for (int i = 0; i < currentAdditionalInfo.Count; i++)
|
||
|
|
{
|
||
|
|
strInfo.AppendFormat("{0}{1}: {2}", Environment.NewLine, currentAdditionalInfo.GetKey(i), currentAdditionalInfo[i]);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
// Otherwise just write the ToString() value of the property.
|
||
|
|
else
|
||
|
|
{
|
||
|
|
strInfo.AppendFormat("{0}{1}: {2}", Environment.NewLine, p.Name, p.GetValue(currentException,null));
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
#endregion
|
||
|
|
#region Record the Exception StackTrace
|
||
|
|
// Record the StackTrace with separate label.
|
||
|
|
if (currentException.StackTrace != null)
|
||
|
|
{
|
||
|
|
strInfo.AppendFormat("{0}{0}StackTrace Information{0}{1}", Environment.NewLine, TEXT_SEPARATOR);
|
||
|
|
strInfo.AppendFormat("{0}{1}", Environment.NewLine, currentException.StackTrace);
|
||
|
|
}
|
||
|
|
#endregion
|
||
|
|
|
||
|
|
// Reset the temp exception object and iterate the counter.
|
||
|
|
currentException = currentException.InnerException;
|
||
|
|
intExceptionCount++;
|
||
|
|
} while (currentException != null);
|
||
|
|
#endregion
|
||
|
|
}
|
||
|
|
|
||
|
|
// Write the entry to the event log.
|
||
|
|
//WriteToLog(strInfo.ToString(), EventLogEntryType.Error);
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// Helper function to write an entry to the Event Log.
|
||
|
|
/// </summary>
|
||
|
|
/// <param name="entry">The entry to enter into the Event Log.</param>
|
||
|
|
/// <param name="type">The EventLogEntryType to be used when the entry is logged to the Event Log.</param>
|
||
|
|
//private void WriteToLog(string entry, EventLogEntryType type)
|
||
|
|
//{
|
||
|
|
// try
|
||
|
|
// {
|
||
|
|
// // Write the entry to the Event Log.
|
||
|
|
// //EventLog.WriteEntry(applicationName,entry,type);
|
||
|
|
// }
|
||
|
|
// catch(SecurityException e)
|
||
|
|
// {
|
||
|
|
// throw new SecurityException(String.Format(resourceManager.GetString("RES_DEFAULTPUBLISHER_EVENTLOG_DENIED"), applicationName),e);
|
||
|
|
// }
|
||
|
|
//}
|
||
|
|
|
||
|
|
private void VerifyValidSource()
|
||
|
|
{
|
||
|
|
try
|
||
|
|
{
|
||
|
|
//Set permissions to ASPNET User in HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\EventLog
|
||
|
|
//if (!EventLog.SourceExists(applicationName))
|
||
|
|
//{
|
||
|
|
// EventLog.CreateEventSource(applicationName, logName);
|
||
|
|
//}
|
||
|
|
}
|
||
|
|
catch(SecurityException e)
|
||
|
|
{
|
||
|
|
throw new SecurityException(String.Format(resourceManager.GetString("RES_DEFAULTPUBLISHER_EVENTLOG_DENIED"), applicationName),e);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
#endregion
|
||
|
|
}
|