Michael Gillson

Share ideas, observations, expertise  
Using C# and the .NET Frame Work.

Error Handling

        When developing a new application, errors occur. Error handling is built into my apps from the beginning. Sometimes the error is not obvious where it was trigger from. The application may multiple threads or idle processing may be enabled. 

The .NET framework includes call stack information with every Exception but the formatting of the Exception is hard to read and has way too much information. Listed below is a small class that walks through all the exceptions and shows a formatted call stack with line numbers from the application. Also, the .NET Framework calls can be shown in the call stack.
 
public static class CallStackInformation
{
   public static string ConstructCallStack(Exception capturedException)
   {
      return ConstructCallStack(capturedException, true);
   }
 
   public static string ConstructCallStack(Exception capturedException,
      bool fileLineOnly)
   {
      // See System.Environment.StackTrace for explanation of the construction of the
      // StackTrace string.
      string result;
      System.Diagnostics.StackFrame callStack;
      bool done;
      int stackStart;
      result = Environment.NewLine + "Call Stack Trace";
 
      string exceptionFileName;
      foreach (Exception ex in ReverseExceptionList(capturedException))
      {
         exceptionFileName = ExtractFileFromStackTrace(ex.StackTrace, fileLineOnly);
         if (exceptionFileName != "")
            result = result + Environment.NewLine + exceptionFileName;
      }
 
      // Find the calling routines
     done = false;
      stackStart = 1;
      while (!done)
      {
         stackStart++;
         callStack = new System.Diagnostics.StackFrame(stackStart, true);
         if (callStack.GetMethod() == null)
            done = true;
         else
         {
            // Build the stack trace to appear the same as the one in the Exception
            string stackTrace = "   at " + callStack.GetMethod();
            if (callStack.GetFileName() != null)
               stackTrace = stackTrace + " in " + callStack.GetFileName();
            if (callStack.GetFileLineNumber() != 0)
               stackTrace = stackTrace + ":line " +
                  callStack.GetFileLineNumber().ToString();
 
            exceptionFileName = ExtractFileFromStackTrace(stackTrace, fileLineOnly);
            if (exceptionFileName != "")
               result = result + Environment.NewLine + exceptionFileName;
         }
      }
 
      return result;
   }
 
   private static List<Exception> ReverseExceptionList(Exception capturedException)
   {
      List<Exception> fifoExceptioList = new List<Exception>();
      Exception ex = capturedException;
      while (ex != null)
      {
         fifoExceptioList.Insert(0, ex);
         ex = ex.InnerException;
      }
 
      return fifoExceptioList;
   }
 
   private static string AppendResult(string textLine, string currentResult)
   {
      string result = currentResult;
      if (result == "")
         result = textLine;
      else
         result = result + Environment.NewLine + textLine;
 
     return result;
   }
 
   private static string ExtractFileFromStackTrace(string stackTrace, bool fileLineOnly)
   {
      // Find the line number that threw the error
      string result = "";
      if (stackTrace != null)
      {
         string[] stringSeparators = new string[] { "\r\n" }; // Carriage Return-Line Feed
         string[] splitStackTrace = stackTrace.Split(stringSeparators,
            StringSplitOptions.RemoveEmptyEntries);
 
         foreach (string split in splitStackTrace)
         {
            if (fileLineOnly)
            {
               int position = split.IndexOf(" in ");
               if ((position >= 0) && (position + 4 < split.Length))
               {
                  string fileLine = split.Substring(position + 4).Replace(":line", ", Line:");
                  if (fileLine != "")
                  {
                     fileLine = "   File: " + fileLine;
                     result = AppendResult(fileLine, result);
                  }
               }
            }
            else
               result = AppendResult(split, result);
         }
      }
 
      return result;
 
   }
}
 
The following sections show the two ways to execute the call stack methods.
 
 
      private void btnMyErrorOnly_Click(object sender, EventArgs e)
      {
         try
         {
            throw new ApplicationException("My Error Only Exception");
         }
         catch (Exception ex)
         {
            MessageBox.Show(ex.Message + Environment.NewLine +
               PaxArmonia.Error.CallStackInformation.ConstructCallStack(ex),
               "My Error",MessageBoxButtons.OK,MessageBoxIcon.Error);
         }
      }
 
      private void btnFullError_Click(object sender, EventArgs e)
      {
         try
         {
            throw new ApplicationException("Error with .NET Trace");
         }
         catch (Exception ex)
         {
            MessageBox.Show(ex.Message + Environment.NewLine +
               PaxArmonia.Error.CallStackInformation.ConstructCallStack(ex, false),
               "My Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
         }
      }
 
 
 
Notice the extra info from the second call. Rarely is there a need to see the .NET Framework calling methods.
 
 
 
 
 

Download source files - 11.8 Kb


Site Map Printable View powered by mojoPortal Content Management System Valid XHTML 1.0 Transitional Valid CSS Design by Pax Armonia