views:

744

answers:

5

I have a custom exception class which contains some additional fields. I want these to be written out in the ToString() method, but if I implement my own ToString(), I loose some other useful stuff (like writing the exception type name, the inner exception data and the stack trace).

What is the best way/pattern to implement your own ToString() method for such exceptions? Ideally it should reuse the existing mechanism, but be formatted in way similar to the default ToString() implementation.

UPDATE: prepending or appending my custom fields to the base.ToString() text isn't ideal IMHO, for example

PimTool.Utilities.OERestServiceUnavailableException: test ---> System.InvalidOperationException: inner message
   --- End of inner exception stack trace ---
   at PimTool.Tests.Services.OE.OERestClientTests.ExceptionsLogging() in D:\svn\NewPimTool\PimTool.Tests\Services\OE\OERestClientTests.cs:line 178, 
   StatusCode=0, message='test', requestId='535345'

means the custom fields are written at the end of the (potentially long) exception description. On the other hand, I want the exception type to be the first information written in the description.

UPDATE 2: I've implemented a solution for this, look for my own answer below.

+5  A: 

You could manually add the default data to the string returned by ToString, by looking at the exception properties. For example, the following will simulate the data returned by default by a exception's ToString method (assuming there are no inner exceptions):

string.Format("{0}: {1}\r\n{2}", this.GetType().Name, this.Message, this.StackTrace);

Or, you could simply append (or prepend) the data returned by base.ToString to the information you want to add.

Konamiman
This seems to be the closest solution to what I had in mind. Although you forgot to write out the InnerException ;)
Igor Brejc
A: 

Inside the override call base.ToString() and modify the resulting string to your needs...

Fried Hoeben
A: 

You can override the ToString() method to include your own custom information, and still call the default base Exception ToString() like this:

public class MyException : Exception
{
    public string CustomField { get; set; }
    public override string ToString()
    {
        return CustomField + Environment.NewLine + base.ToString();
    }
}
cxfx
+2  A: 

If you're primarily looking at them in the debugger, then you can use the [DebuggerDisplay] attribute to specify their formatting and not touch the existing ToString method.

Otherwise, just overload ToString and be sure to call the base class version base.ToString()

Andrew Rollings
Although not what I was looking for, +1 for mentioning it.
Igor Brejc
+3  A: 

OK, this is what I came up with. I've implemented an extension class which replicates the original mechanism for formatting exceptions, but with a twist: a custom Action delegate which provides a plug-in for formatting custom fields:

public static class ExceptionFormatterExtensions
{
    public static string ExceptionToString (
        this Exception ex, 
        Action<StringBuilder> customFieldsFormatterAction)
    {
        StringBuilder description = new StringBuilder();
        description.AppendFormat("{0}: {1}", ex.GetType().Name, ex.Message);

        if (customFieldsFormatterAction != null)
            customFieldsFormatterAction(description);

        if (ex.InnerException != null)
        {
            description.AppendFormat(" ---> {0}", ex.InnerException);
            description.AppendFormat(
                "{0}   --- End of inner exception stack trace ---{0}",
                Environment.NewLine);
        }

        description.Append(ex.StackTrace);

        return description.ToString();
    }
}

Now you can use this method in your own ToString() implementations without duplicating the formatting code:

    public override string ToString()
    {
        return this.ExceptionToString(
            description =>
            {
                description.AppendFormat(
                    ", HttpStatusCode={0}, RequestId='{1}'", 
                    httpStatusCode, 
                    RequestId);
            });
    }
Igor Brejc