Click here to Skip to main content
15,896,557 members
Articles / Web Development / ASP.NET

Automatic Error Handling

Rate me:
Please Sign up or sign in to vote.
4.78/5 (10 votes)
17 Mar 2008CPOL3 min read 57.3K   1.1K   74  
Handle web and WinForms exceptions automatically.
using System;
using System.Collections.Generic;
using System.Text;

using System.Collections.Specialized;
using System.Data.SqlClient;
using System.Diagnostics;
using System.IO;
using System.Net;
using System.Net.Mail;
using System.Reflection;

namespace ErrorHandler
{
	public abstract class HandlerBase
	{
		#region Handler State
		protected const string _defaultLogName = "UnhandledExceptionLog.txt";
		protected const string _rootException = "System.Web.HttpUnhandledException";
		protected const string _rootWsException = "System.Web.Services.Protocols.SoapException";

		protected string _logFilePath = Config.GetPath( "PathLogFile" );

		protected string _exceptionType = string.Empty;
		protected string _exceptionText = string.Empty;

		protected bool _logToDatabaseOK = false;
		protected bool _logToFileOK = false;
		protected bool _logToEventLogOK = false;

		protected NameValueCollection _results = new NameValueCollection();

		protected static Assembly _parentAssembly = null;
		#endregion

		#region Inputs
		protected static string ApplicationPath
		{
			get { return AppDomain.CurrentDomain.BaseDirectory; }
		}

		protected static DateTime GetAssemblyBuildDate( Assembly a )
		{
			return GetAssemblyBuildDate( a, false );
		}

		protected static DateTime GetAssemblyBuildDate( Assembly asm, bool forceFileDate )
		{
			Version ver = asm.GetName().Version;
			DateTime result;

			if( forceFileDate )
				result = GetAssemblyFileTime( asm );
			else
			{
				result = new DateTime( 2000, 1, 1 ).AddDays( ver.Build ).AddSeconds( ver.Revision * 2 );

				if( TimeZone.IsDaylightSavingTime( result, TimeZone.CurrentTimeZone.GetDaylightChanges( result.Year ) ) )
					result = result.AddHours( 1 );

				if( result > DateTime.Now || ver.Build < 730 || ver.Revision == 0 )
					result = GetAssemblyFileTime( asm );

			}

			return result;
		}

		//
		// exception-safe file attrib retrieval; we don't care if this fails
		//
		protected static DateTime GetAssemblyFileTime( Assembly asm )
		{
			try
			{
				return System.IO.File.GetLastWriteTime( asm.Location );
			}
			catch( Exception )
			{
				return DateTime.MaxValue;
			}
		}

		/// <summary>
		/// exception-safe WindowsIdentity.GetCurrent retrieval; returns "domain\username"
		/// </summary>
		/// <remarks>
		/// per MS, this can sometimes randomly fail with "Access Denied" on NT4
		/// </remarks>
		protected static string CurrentWindowsIdentity()
		{
			try
			{
				return System.Security.Principal.WindowsIdentity.GetCurrent().Name;
			}
			catch( Exception )
			{
				return string.Empty;
			}
		}

		/// <summary>
		/// exception-safe System.Environment "domain\username" retrieval
		/// </summary>
		protected static string CurrentEnvironmentIdentity()
		{
			try
			{
				return System.Environment.UserDomainName + "\\" + System.Environment.UserName;
			}
			catch( Exception )
			{
				return string.Empty;
			}
		}

		/// <summary>
		/// retrieve Process identity with fallback on error to safer method
		/// </summary>
		protected static string ProcessIdentity()
		{
			string strTemp = CurrentWindowsIdentity();

			if( string.IsNullOrEmpty( strTemp ) )
				strTemp = CurrentEnvironmentIdentity();

			return strTemp;
		}
		#endregion

		#region Outputs
		protected bool Write( string source, string prefix, string[] attachmentFiles, Dictionary<string, Stream> attachmentStreams )
		{
			bool result = false;

			if( !WriteToDatabase() )
			{
				result = WriteToEventLog( source );
			}

			result &= WriteToFile();
			result &= WriteToEmail( prefix, attachmentFiles, attachmentStreams );

			return result;
		}

		/// <summary>
		/// write current exception info to a text file; 
		/// requires write permissions for the target folder
		/// </summary>
		protected bool WriteToFile()
		{
			if( string.IsNullOrEmpty( Path.GetFileName( _logFilePath ) ) )
				_logFilePath = Path.Combine( _logFilePath, _defaultLogName );

			StreamWriter sw = null;

			try
			{
				using( sw = new StreamWriter( _logFilePath, true ) )
				{
					sw.WriteLine( "**** - " + DateTime.Now.ToString( "s" ) );
					sw.Write( _exceptionType );
					sw.WriteLine();
					sw.Write( _exceptionText );
					sw.WriteLine();
					sw.Close();
				}

				_logToFileOK = true;
			}
			catch( Exception ex )
			{
				_results.Add( "LogToFile", ex.Message );
			}
			finally
			{
				if( sw != null )
					sw.Close();
			}
			return _logToFileOK;
		}

		/// <summary>
		/// send current exception info via email
		/// </summary>
		protected bool WriteToEmail( string subjectPrefix, string[] attachmentFiles, Dictionary<string,Stream> attachmentStreams )
		{
			string to = Config.GetString( "EmailTo", "" );

			if( string.IsNullOrEmpty( to ) )
			{
				// don't bother mailing if we don't have anyone to mail to..
				//_blnLogToEmail = false;
				return true;
			}

			try
			{
				string host = Config.GetString( "SmtpServer", string.Empty );
				int port = Config.GetInteger( "SmtpPort", 21 );
				string userName = Config.GetString( "SmtpUser", string.Empty );
				string password = Config.GetString( "SmtpPwd", string.Empty );
				string domain = Config.GetString( "SmtpDefaultDomain", string.Empty );
				bool enableSsl = Config.GetBoolean( "SmtpUseSsl", true );

				string from = Config.GetString( "SmtpFromAddress", string.Empty );

				using( MailMessage msg = new MailMessage() )
				{
					msg.From = new MailAddress( from );
					msg.Subject = subjectPrefix + _exceptionType; // "ERROR: " + _exceptionType;
					msg.Body = _exceptionText;
					msg.BodyEncoding = System.Text.Encoding.UTF8;
					msg.IsBodyHtml = false;

					string[] recipients = to.Split( '|', ';', ',' );
					foreach( string recip in recipients )
					{
						if( !string.IsNullOrEmpty( recip.Trim() ) )
						{
							msg.To.Add( recip.Trim() );
						}
					}

					NetworkCredential auth = CredentialCache.DefaultNetworkCredentials;

					if( !string.IsNullOrEmpty( userName ) )
					{
						if( string.IsNullOrEmpty( domain ) )
							auth = new NetworkCredential( userName, password );
						else
							auth = new NetworkCredential( userName, password, domain );
					}

					SmtpClient smtpClient = new SmtpClient( host, port );

					smtpClient.EnableSsl = enableSsl;
					smtpClient.Credentials = auth;
					smtpClient.DeliveryMethod = SmtpDeliveryMethod.Network;

					foreach( string file in attachmentFiles )
					{
						msg.Attachments.Add( new Attachment( file ) );
					}

					foreach( string name in attachmentStreams.Keys )
					{
						msg.Attachments.Add( new Attachment( attachmentStreams[name], name ) );
					}

					smtpClient.Send( msg );

					return true;
				}
			}
			catch( Exception ex )
			{
				_results.Add( "LogToEmail", ex.Message );
				// we're in an unhandled exception handler
			}

			return false;
		}

		protected bool WriteToEventLog( string source )
		{
			try
			{
				EventLog.WriteEntry( source, Environment.NewLine + _exceptionText, EventLogEntryType.Error );

				_logToEventLogOK = true;
			}
			catch( Exception ex )
			{
				_results.Add( "LogToEventLog", ex.Message );
			}
			return _logToEventLogOK;
		}

		public delegate void DatabaseWriteEventHandler( string type, string text );
		public static event DatabaseWriteEventHandler OnWriteToDatabase;

		protected bool WriteToDatabase()
		{
			_logToDatabaseOK = false;

			if( OnWriteToDatabase != null )
			{
				try
				{
					OnWriteToDatabase( _exceptionType, _exceptionText );
					_logToDatabaseOK = true;
				}
				catch( Exception ex )
				{
					_results.Add( "LogToDatabase", ex.ToString() );
				}
			}
			else
			{
				_results.Add( "LogToDatabase", "No subscriptions to OnWriteToDatabase event" );
			}

			return _logToDatabaseOK;
		}
		#endregion

		#region String Conversions
		/// <summary>
		/// turns a single stack frame object into an informative string
		/// </summary>
		/// <param name="sf"></param>
		/// <returns></returns>
		protected string StackFrameToString( StackFrame sf )
		{
			StringBuilder sb = new StringBuilder();
			int intParam;
			MemberInfo mi = sf.GetMethod();

			// build method name
			sb.Append( "	" );
			sb.Append( mi.DeclaringType.Namespace );
			sb.Append( "." );
			sb.Append( mi.DeclaringType.Name );
			sb.Append( "." );
			sb.Append( mi.Name );

			// build method params
			ParameterInfo[] objParameters = sf.GetMethod().GetParameters();

			sb.Append( "( " );
			intParam = 0;
			foreach( ParameterInfo objParameter in objParameters )
			{
				intParam += 1;
				if( intParam > 1 ) sb.Append( ", " );

				sb.Append( objParameter.ParameterType.Name );
				sb.Append( " " );
				sb.Append( objParameter.Name );
			}
			sb.Append( " )" );
			sb.Append( Environment.NewLine );

			// if source code is available, append location info
			sb.Append( "		" );
			if( string.IsNullOrEmpty( sf.GetFileName() ) )
			{
				if( _parentAssembly != null )
					sb.Append( System.IO.Path.GetFileName( _parentAssembly.CodeBase ) );
				else
					sb.Append( "(unknown file)" );

				// native code offset is always available
				sb.Append( ": N " );
				sb.Append( String.Format( "{0:#00000}", sf.GetNativeOffset() ) );
			}
			else
			{
				sb.Append( System.IO.Path.GetFileName( sf.GetFileName() ) );
				sb.Append( ": line " );
				sb.Append( String.Format( "{0:#0000}", sf.GetFileLineNumber() ) );
				sb.Append( ", col " );
				sb.Append( String.Format( "{0:#00}", sf.GetFileColumnNumber() ) );
				// if IL is available, append IL location info
				if( sf.GetILOffset() != System.Diagnostics.StackFrame.OFFSET_UNKNOWN )
				{
					sb.Append( ", IL " );
					sb.Append( String.Format( "{0:#0000}", sf.GetILOffset() ) );
				}
			}
			sb.Append( Environment.NewLine );

			return sb.ToString();
		}

		protected abstract string SysInfoToString();

		/// <summary>
		/// translate exception object to string, with additional system info
		/// </summary>
		/// <param name="exceptn">Exception to be converted</param>
		/// <returns></returns>
		protected string ExceptionToString( Exception ex, bool includeSysInfo )
		{
			StringBuilder builder = new StringBuilder();

			// Inner exceptions are handled recursively
			if( !( 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

			// don't return the outer root ASP exception; it is redundant.
				if( ex.GetType().ToString() == _rootException || ex.GetType().ToString() == _rootWsException )
					return ExceptionToString( ex.InnerException, true );
				else
				{
					builder.Append( "(Inner Exception)" );
					builder.Append( Environment.NewLine );
					builder.Append( ExceptionToString( ex.InnerException, false ) );
					builder.Append( Environment.NewLine );
					builder.Append( "(Outer Exception)" );
					builder.Append( Environment.NewLine );
				}
			}

			// get general system and app information
			// we only really want to do this on the outermost exception in the stack
			if( includeSysInfo )
			{
				builder.Append( SysInfoToString() );
				builder.Append( AssemblyInfoToString( ex ) );
				builder.Append( Environment.NewLine );
			}

			// get exception-specific information
			builder.Append( "Exception Source:      " );
			try
			{
				builder.Append( ex.Source );
			}
			catch( Exception e )
			{
				builder.Append( "* Exception Source Error: " + e.ToString() );
			}

			builder.Append( Environment.NewLine );

			builder.Append( "Exception Type:        " );
			try
			{
				builder.Append( ex.GetType().FullName );
			}
			catch( Exception e )
			{
				builder.Append( "* Exception Type Error: " + e.ToString() );
			}

			builder.Append( Environment.NewLine );
			builder.Append( "Exception Message:     " );

			try
			{
				builder.Append( ex.Message );
			}
			catch( Exception e )
			{
				builder.Append( "* Exception Message Error: " + e.ToString() );
			}

			builder.Append( Environment.NewLine );
			builder.Append( "Exception Target Site: " );

			try
			{
				builder.Append( ex.TargetSite.Name );
			}
			catch( Exception e )
			{
				builder.Append( "* Exception Target Site Error: " + e.ToString() );
			}

			builder.Append( Environment.NewLine );

			// Check for specific exception types (and output specific details if known)
			if( ex is SqlException )
			{
				SqlExceptionToString( builder, ex );
			}

			try
			{
				string x = EnhancedStackTrace( ex );
				builder.Append( x );
			}
			catch( Exception e )
			{
				builder.Append( "* Exception Stack Trace Error: " + e.ToString() );
			}

			builder.Append( Environment.NewLine );

			return builder.ToString();
		}

		private void SqlExceptionToString( StringBuilder builder, Exception exceptn )
		{
			SqlException se = exceptn as SqlException;

			builder.Append( Environment.NewLine );
			builder.Append( "SQL Procedure:         " );
			try
			{
				builder.Append( se.Procedure );
			}
			catch( Exception e )
			{
				builder.Append( e.Message );
			}
			builder.Append( Environment.NewLine );

			builder.Append( "SQL Server:            " );
			try
			{
				builder.Append( se.Server );
			}
			catch( Exception e )
			{
				builder.Append( e.Message );
			}
			builder.Append( Environment.NewLine );

			builder.Append( "SQL State:             " );
			try
			{
				builder.Append( se.State );
			}
			catch( Exception e )
			{
				builder.Append( e.Message );
			}
			builder.Append( Environment.NewLine );

			builder.Append( "SQL Source:            " );
			try
			{
				builder.Append( se.Source );
			}
			catch( Exception e )
			{
				builder.Append( e.Message );
			}
			builder.Append( Environment.NewLine );

			builder.Append( "SQL Error Number:      " );
			try
			{
				builder.Append( se.Number );
			}
			catch( Exception e )
			{
				builder.Append( e.Message );
			}
			builder.Append( Environment.NewLine );

			builder.Append( "SQL Line Number:       " );
			try
			{
				builder.Append( se.LineNumber );
			}
			catch( Exception e )
			{
				builder.Append( e.Message );
			}
			builder.Append( Environment.NewLine );

			foreach( SqlError error in se.Errors )
			{
				builder.Append( "SQL Error Class:       " );
				try
				{
					builder.Append( error.Class );
				}
				catch( Exception e )
				{
					builder.Append( e.Message );
				}
				builder.Append( Environment.NewLine );

				builder.Append( "SQL Error Line Number: " );
				try
				{
					builder.Append( error.LineNumber );
				}
				catch( Exception e )
				{
					builder.Append( e.Message );
				}
				builder.Append( Environment.NewLine );

				builder.Append( "SQL Error Message:     " );
				try
				{
					builder.Append( error.Message );
				}
				catch( Exception e )
				{
					builder.Append( e.Message );
				}
				builder.Append( Environment.NewLine );

				builder.Append( "SQL Error Number:      " );
				try
				{
					builder.Append( error.Number );
				}
				catch( Exception e )
				{
					builder.Append( e.Message );
				}
				builder.Append( Environment.NewLine );

				builder.Append( "SQL Error Procedure:   " );
				try
				{
					builder.Append( error.Procedure );
				}
				catch( Exception e )
				{
					builder.Append( e.Message );
				}
				builder.Append( Environment.NewLine );

				builder.Append( "SQL Error Server:      " );
				try
				{
					builder.Append( error.Server );
				}
				catch( Exception e )
				{
					builder.Append( e.Message );
				}
				builder.Append( Environment.NewLine );

				builder.Append( "SQL Error Source:      " );
				try
				{
					builder.Append( error.Source );
				}
				catch( Exception e )
				{
					builder.Append( e.Message );
				}
				builder.Append( Environment.NewLine );

				builder.Append( "SQL Error State:       " );
				try
				{
					builder.Append( error.State );
				}
				catch( Exception e )
				{
					builder.Append( e.Message );
				}
				builder.Append( Environment.NewLine );
				builder.Append( Environment.NewLine );
			}
		}

		/// <summary>
		/// retrieve relevant assembly details for this exception, if possible
		/// </summary>
		private string AssemblyInfoToString( Exception ex )
		{
			// ex.source USUALLY contains the name of the assembly that generated the exception
			// at least, according to the MSDN documentation..
			Assembly a = GetAssemblyFromName( ex.Source );

			if( a == null )
				return AllAssemblyDetailsToString();
			else
				return AssemblyDetailsToString( a );
		}

		/// <summary>
		/// matches assembly by Assembly.GetName.Name; returns nothing if no match
		/// </summary>
		private Assembly GetAssemblyFromName( string assemblyName )
		{
			foreach( Assembly a in AppDomain.CurrentDomain.GetAssemblies() )
			{
				if( a.GetName().Name == assemblyName )
					return a;
			}
			return null;
		}

		/// <summary>
		/// returns brief summary info for all assemblies in the current AppDomain
		/// </summary>
		private string AllAssemblyDetailsToString()
		{
			StringBuilder sb = new StringBuilder();
			const string strLineFormat = "    {0, -30} {1, -15} {2}";

			sb.Append( Environment.NewLine );
			sb.Append( String.Format( strLineFormat, "Assembly", "Version", "BuildDate" ) );
			sb.Append( Environment.NewLine );
			sb.Append( String.Format( strLineFormat, "--------", "-------", "---------" ) );
			sb.Append( Environment.NewLine );

			foreach( Assembly a in AppDomain.CurrentDomain.GetAssemblies() )
			{
				NameValueCollection nvc = AssemblyAttribs( a );
				// assemblies without versions are weird (dynamic?)
				if( nvc["Version"] != "0.0.0.0" )
				{
					sb.Append( String.Format( strLineFormat,
						System.IO.Path.GetFileName( nvc["CodeBase"] ), nvc["Version"], nvc["BuildDate"] ) );
					sb.Append( Environment.NewLine );
				}
			}

			return sb.ToString();
		}

		/// <summary>
		/// returns string name / string value pair of all attribs for the specified assembly
		/// </summary>
		/// <remarks>
		/// note that Assembly* values are pulled from AssemblyInfo file in project folder
		///
		/// Trademark       = AssemblyTrademark string
		/// Debuggable      = True
		/// GUID            = 7FDF68D5-8C6F-44C9-B391-117B5AFB5467
		/// CLSCompliant    = True
		/// Product         = AssemblyProduct string
		/// Copyright       = AssemblyCopyright string
		/// Company         = AssemblyCompany string
		/// Description     = AssemblyDescription string
		/// Title           = AssemblyTitle string
		/// </remarks>
		private NameValueCollection AssemblyAttribs( Assembly a )
		{
			string Name;
			string Value;
			NameValueCollection nvc = new NameValueCollection();

			foreach( object attrib in a.GetCustomAttributes( false ) )
			{
				Name = attrib.GetType().ToString();
				Value = "";

				switch( Name )
				{
				case "System.Diagnostics.DebuggableAttribute":
					Name = "Debuggable";
					Value = ( (System.Diagnostics.DebuggableAttribute)attrib ).IsJITTrackingEnabled.ToString();
					break;

				case "System.CLSCompliantAttribute":
					Name = "CLSCompliant";
					Value = ( (System.CLSCompliantAttribute)attrib ).IsCompliant.ToString();
					break;

				case "System.Runtime.InteropServices.GuidAttribute":
					Name = "GUID";
					Value = ( (System.Runtime.InteropServices.GuidAttribute)attrib ).Value.ToString();
					break;

				case "System.Reflection.AssemblyTrademarkAttribute":
					Name = "Trademark";
					Value = ( (AssemblyTrademarkAttribute)attrib ).Trademark.ToString();
					break;

				case "System.Reflection.AssemblyProductAttribute":
					Name = "Product";
					Value = ( (AssemblyProductAttribute)attrib ).Product.ToString();
					break;

				case "System.Reflection.AssemblyCopyrightAttribute":
					Name = "Copyright";
					Value = ( (AssemblyCopyrightAttribute)attrib ).Copyright.ToString();
					break;

				case "System.Reflection.AssemblyCompanyAttribute":
					Name = "Company";
					Value = ( (AssemblyCompanyAttribute)attrib ).Company.ToString();
					break;

				case "System.Reflection.AssemblyTitleAttribute":
					Name = "Title";
					Value = ( (AssemblyTitleAttribute)attrib ).Title.ToString();
					break;

				case "System.Reflection.AssemblyDescriptionAttribute":
					Name = "Description";
					Value = ( (AssemblyDescriptionAttribute)attrib ).Description.ToString();
					break;

				default:
					Console.WriteLine( Name );
					break;
				}

				if( !string.IsNullOrEmpty( Value ) )
				{
					if( string.IsNullOrEmpty( nvc[Name] ) )
						nvc.Add( Name, Value );
				}
			}

			// add some extra values that are not in the AssemblyInfo, but nice to have
			nvc.Add( "CodeBase", a.CodeBase.Replace( "file:///", "" ) );
			nvc.Add( "BuildDate", GetAssemblyBuildDate( a ).ToString() );
			nvc.Add( "Version", a.GetName().Version.ToString() );
			nvc.Add( "FullName", a.FullName );

			return nvc;
		}

		/// <summary>
		/// returns more detailed information for a single assembly
		/// </summary>
		private string AssemblyDetailsToString( Assembly a )
		{
			StringBuilder sb = new StringBuilder();
			NameValueCollection nvc = AssemblyAttribs( a );

			sb.Append( "Assembly Codebase:     " );

			try
			{
				sb.Append( nvc["CodeBase"] );
			}
			catch( Exception e )
			{
				sb.Append( e.Message );
			}

			sb.Append( Environment.NewLine );
			sb.Append( "Assembly Full Name:    " );

			try
			{
				sb.Append( nvc["FullName"] );
			}
			catch( Exception e )
			{
				sb.Append( e.Message );
			}

			sb.Append( Environment.NewLine );

			sb.Append( "Assembly Version:      " );
			try
			{
				sb.Append( nvc["Version"] );
			}
			catch( Exception e )
			{
				sb.Append( e.Message );
			}
			sb.Append( Environment.NewLine );

			sb.Append( "Assembly Build Date:   " );
			try
			{
				sb.Append( nvc["BuildDate"] );
			}
			catch( Exception e )
			{
				sb.Append( e.Message );
			}
			sb.Append( Environment.NewLine );

			return sb.ToString();
		}

		/// <summary>
		/// attempts to coerce the value object using the .ToString method if possible, 
		/// then appends a formatted key/value string pair to a StringBuilder. 
		/// will display the type name if the object cannot be coerced.
		/// </summary>
		protected void AppendLine( StringBuilder sb, string Key, object Value )
		{
			string strValue = "(NULL)";

			if( Value != null )
			{
				try
				{
					strValue = Value.ToString();
				}
				catch( Exception )
				{
					strValue = "(" + Value.GetType().ToString() + ")";
				}
			}

			AppendLine( sb, Key, strValue );
		}

		/// <summary>
		/// appends a formatted key/value string pair to a StringBuilder
		/// </summary>
		protected void AppendLine( StringBuilder sb, string Key, string strValue )
		{
			sb.Append( String.Format( "    {0, -30}{1}", Key, strValue ) );
			sb.Append( Environment.NewLine );
		}

		#region Enhanced Stack Trace
		/// <summary>
		/// enhanced stack trace generator, using current execution as start point
		/// </summary>
		protected string EnhancedStackTrace()
		{
			return EnhancedStackTrace( new StackTrace( true ), "ASPUnhandledException" );
		}

		/// <summary>
		/// enhanced stack trace generator, using existing exception as start point
		/// </summary>
		protected string EnhancedStackTrace( Exception ex )
		{
			return EnhancedStackTrace( new StackTrace( ex ), null );
		}

		/// <summary>
		/// enhanced stack trace generator (prebuilt stack trace, class name to skip)
		/// </summary>
		/// <param name="objStackTrace"></param>
		/// <param name="strSkipClassName"></param>
		/// <returns></returns>
		protected string EnhancedStackTrace( StackTrace objStackTrace, string strSkipClassName )
		{
			System.Text.StringBuilder sb = new StringBuilder();

			sb.Append( Environment.NewLine );
			sb.Append( "---- Stack Trace ----" );
			sb.Append( Environment.NewLine );

			for( int intFrame = 0; intFrame < objStackTrace.FrameCount; intFrame++ )
			{
				StackFrame sf = objStackTrace.GetFrame( intFrame );
				MemberInfo mi = sf.GetMethod();

				if( !string.IsNullOrEmpty( strSkipClassName) && ( mi.DeclaringType.Name.IndexOf( strSkipClassName ) > -1 ) )
				{
					// don't include frames with this name
				}
				else
					sb.Append( StackFrameToString( sf ) );
			}
			sb.Append( Environment.NewLine );

			return sb.ToString();
		}
		#endregion
		#endregion
	}
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior) Belami
United States United States
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions