none
How to customize the stacktrace of a custom Exception? RRS feed

  • Question

  • The Exception.StackTrace propery is virtual and can be overridden to define something else, however as of .NET 4 Exception.ToString() ignores this and keeps on using the build in functionality.

    Small example to show the difference in behavior:

       class Program
       {
          static void Main(string[] args)
          {
             try
             {
                Test1();
             }
             catch (Exception e)
             {
                Console.WriteLine("Main() =>" + Environment.NewLine + "StackTrace: " + e.StackTrace + Environment.NewLine + "ToString: " + e.ToString() + Environment.NewLine);
             }
    
             Console.ReadKey();
          }
    
          private static void Test1()
          {
             try
             {
                Test2();
             }
             catch (Exception e)
             {
                Console.WriteLine("Test1() =>" + Environment.NewLine + "StackTrace: " + e.StackTrace + Environment.NewLine + "ToString: " + e.ToString() + Environment.NewLine);
                throw new Exception("Inner exception", e); // Throw with inner exception
             }
          }
    
          private static void Test2()
          {
             try
             {
                Test3();
             }
             catch (Exception e)
             {
    
                Console.WriteLine("Test2() =>" + Environment.NewLine + "StackTrace: " + e.StackTrace + Environment.NewLine + "ToString: " + e.ToString() + Environment.NewLine);
                throw; // Rethrow
             }
          }
    
          private static void Test3()
          {
             throw new MyException();
          }
       }
    
       public class MyException : Exception
       {
          public override string StackTrace
          {
             get
             {
                return "   at: My custom StackTrace...";
             }
          }
       }

    With .NET 4 produces:

    Test2() =>
    StackTrace:    at: My custom StackTrace...
    ToString: exception.MyException: Exception of type 'exception.MyException' was thrown.
       at exception.Program.Test3() in d:\Projects\exception\exception\Program.cs:line 53
       at exception.Program.Test2() in d:\Projects\exception\exception\Program.cs:line 41

    Test1() =>
    StackTrace:    at: My custom StackTrace...
    ToString: exception.MyException: Exception of type 'exception.MyException' was thrown.
       at exception.Program.Test3() in d:\Projects\exception\exception\Program.cs:line 53
       at exception.Program.Test2() in d:\Projects\exception\exception\Program.cs:line 47
       at exception.Program.Test1() in d:\Projects\exception\exception\Program.cs:line 28

    Main() =>
    StackTrace:    at exception.Program.Test1() in d:\Projects\exception\exception\Program.cs:line 33
       at exception.Program.Main(String[] args) in d:\Projects\exception\exception\Program.cs:line 14
    ToString: System.Exception: Inner exception ---> exception.MyException: Exception of type 'exception.MyException' was thrown.
       at exception.Program.Test3() in d:\Projects\exception\exception\Program.cs:line 53
       at exception.Program.Test2() in d:\Projects\exception\exception\Program.cs:line 47
       at exception.Program.Test1() in d:\Projects\exception\exception\Program.cs:line 28
       --- End of inner exception stack trace ---
       at exception.Program.Test1() in d:\Projects\exception\exception\Program.cs:line 33
       at exception.Program.Main(String[] args) in d:\Projects\exception\exception\Program.cs:line 14

    with .NET 3.5 produces:

    Test2() =>
    StackTrace:    at: My custom StackTrace...
    ToString: exception.MyException: Exception of type 'exception.MyException' was thrown.
       at: My custom StackTrace...

    Test1() =>
    StackTrace:    at: My custom StackTrace...
    ToString: exception.MyException: Exception of type 'exception.MyException' was thrown.
       at: My custom StackTrace...

    Main() =>
    StackTrace:    at exception.Program.Test1() in d:\Projects\ConsoleApplication3\ConsoleApplication3\Program.cs:line 33
       at exception.Program.Main(String[] args) in d:\Projects\ConsoleApplication3\ConsoleApplication3\Program.cs:line 14
    ToString: System.Exception: Inner exception ---> exception.MyException: Exception of type 'exception.MyException' was thrown.
       at: My custom StackTrace...
       --- End of inner exception stack trace ---
       at exception.Program.Test1() in d:\Projects\ConsoleApplication3\ConsoleApplication3\Program.cs:line 33
       at exception.Program.Main(String[] args) in d:\Projects\ConsoleApplication3\ConsoleApplication3\Program.cs:line 14

    .NET 3.5 behavior is according to how I interpreter the documentation.

    In an attempt to solve it I overridden the ToSting(), this only solves the problem partially. For the case without a inner exception the output is then ok, but when calling the ToString() on the outer exception the stack trace of the inner exception logged in the output of the ToString() is still wrong.

    Is there any other way to specify custom stack format/data?

    Monday, August 13, 2012 2:24 PM

Answers

All replies

  • Hi Hvleem,

    Welcome to the MSDN Forum.

    I have tried your code and get the same result of yours.

    From the result, you own stack trace works well. It always returns "at: My custom StackTrace...", doesn't it?

    The difference is the toString method. Based on the test, the toString method in .net 3.5 is different from 4.0's. So to achieve your goal, you also need to custom the toString method.

    Best regards,


    Mike Feng
    MSDN Community Support | Feedback to us
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.

    Tuesday, August 14, 2012 3:46 AM
    Moderator
  • Hi Mike,

    Yes calling the customized StackTrace property works well.

    Your suggestion to override the ToString() method will only work partially, at least when I tried it. Here is the code I used to test it:

    class Program { static void Main(string[] args) { try { Test1(); } catch (Exception e) { Console.WriteLine("Main() =>" + Environment.NewLine + "StackTrace: " + e.StackTrace + Environment.NewLine + "ToString: " + e.ToString() + Environment.NewLine); } Console.ReadKey(); } private static void Test1() { try { Test2(); } catch (Exception e) { Console.WriteLine("Test1() =>" + Environment.NewLine + "StackTrace: " + e.StackTrace + Environment.NewLine + "ToString: " + e.ToString() + Environment.NewLine); throw new Exception("Inner exception", e); // Throw with inner exception } } private static void Test2() { try { Test3(); } catch (Exception e) { Console.WriteLine("Test2() =>" + Environment.NewLine + "StackTrace: " + e.StackTrace + Environment.NewLine + "ToString: " + e.ToString() + Environment.NewLine); throw; // Rethrow } } private static void Test3() { throw new MyException(); } } public class MyException : Exception { public override string StackTrace { get { return " at: My custom StackTrace..."; } } public override String ToString() { String str = GetType().Name; String message = Message; if (message != null && message.Length > 0) { str = str + ": " + message; } Exception innerException = InnerException; if (innerException != null) { str = str + " ---> " + innerException.ToString() + Environment.NewLine + " --- End of inner exception stack trace ---" + Environment.NewLine; } string stackTrace = StackTrace; if (stackTrace != null) { str += Environment.NewLine + stackTrace; } return str; } }

    It results in (with .NET 4):

    Test2() =>
    StackTrace:    at: My custom StackTrace...
    ToString: MyException: Exception of type 'exception.MyException' was thrown.
       at: My custom StackTrace...

    Test1() =>
    StackTrace:    at: My custom StackTrace...
    ToString: MyException: Exception of type 'exception.MyException' was thrown.
       at: My custom StackTrace...

    Main() =>
    StackTrace:    at exception.Program.Test1() in d:\exception\exception\Program.cs:line 33
       at exception.Program.Main(String[] args) in d:\exception\exception\Program.cs:line 14
    ToString: System.Exception: Inner exception ---> exception.MyException: Exception of type 'exception.MyException' was thrown.
       at exception.Program.Test3() in d:\exception\exception\Program.cs:line 53
       at exception.Program.Test2() in d:\exception\exception\Program.cs:line 47
       at exception.Program.Test1() in d:\exception\exception\Program.cs:line 28
       --- End of inner exception stack trace ---
       at exception.Program.Test1() in d:\exception\exception\Program.cs:line 33
       at exception.Program.Main(String[] args) in d:\exception\exception\Program.cs:line 14

    As you can see the ToString() method is not called correctly in case my exception with modified stack is re thrown as an inner exception.

    The System.Exception does not seem to call the ToString() of the inner exception, it rather seems to get the inner exception data via private methods/properties.

    Any suggestion on how to get a consistent behavior in all these cases?

    Kind regards,

    Hans

    Tuesday, August 14, 2012 6:13 AM
  • Hi Hans,

    Yes, I reproduced it.

    You can submit this feedback here: http://connect.microsoft.com/VisualStudio/ 

    Microsoft will check it later.

    When you finish it, please post the link here so the other community members can also track this issue easily.

    Thank you.

    Best regards,


    Mike Feng
    MSDN Community Support | Feedback to us
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.

    Tuesday, August 14, 2012 8:38 AM
    Moderator
  • Issue submitted as: 75850

    The issue has been closed as "won't be fixed", for more details see the issue.

    Regards,

    Hans


    • Marked as answer by Mike FengModerator Monday, August 20, 2012 8:31 AM
    • Edited by hvleem Thursday, August 30, 2012 6:20 AM
    Friday, August 17, 2012 2:23 PM