Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / programming / exceptions

A Quick and Dirty Extension Method to Get the Full Exception Details, Including Inner Exceptions

5.00/5 (11 votes)
1 Apr 2017CPOL2 min read 33.6K   155  
This tip presents an easy way of verbosely converting an exception and its inner exceptions to a string in order to get access to all details.

Introduction

While exception messages are often clear enough, many times the sole error is "An error occurred while updating the entries. See the inner exception for details." - Everyone who's worked with the entity framework probably stumbled upon this one before - See this post on StackOverflow.com, for example.

Background

This code snippet is intended as an easy way of improving the logged details if the logging framework doesn't support a verbose way of logging inner exceptions. Since it is basically boilerplate code which can be used in any .NET project, I decided to put it up here, for further reference to me (and others) - I can't see why everyone should be writing the same piece of code over and over again. Feel free to adapt it to your individual needs.

Mind you, if you have any other way to get the full exception details, you should probably use that way.

Using the Code

The code itself basically consists of a single static class holding an extension method ToFullBlownString. If you're not familiar with extensions methods, read it up here.

C#
public static class ExceptionExtension
        {
            public static string ToFullBlownString(this System.Exception e, int level = int.MaxValue)
            {
                var sb = new StringBuilder();
                var exception = e;
                var counter = 1;
                while (exception != null && counter <= level)
                { 
                  sb.AppendLine($"{counter}-> Level: {counter}");
                  sb.AppendLine($"{counter}-> Message: {exception.Message}");
                  sb.AppendLine($"{counter}-> Source: {exception.Source}");
                  sb.AppendLine($"{counter}-> Target Site: {exception.TargetSite}");
                  sb.AppendLine($"{counter}-> Stack Trace: {exception.StackTrace}");

                  exception = exception.InnerException;
                  counter++;
                }

            return sb.ToString();
            }
        }

The exception extension basically does the following:

As long as the exception is not null, and counter is below level:

-- print exception level (level is increased for every inner exception)
-- print exception message
-- print exception source
-- print exception target site
-- print exception stack trace

-- - > exception is set to exception.inner exception
-- - > counter is increased by one
-- - > evaluate start condition As long as the exception is not null, and counter is below level again and start over.

Example Output

I've written a little test program which generates an exception containing an inner exception. I called ToFullBlownString twice, once without specifying the level parameter and once with the level parameter set to "1":

Image 1

The test program (which is also included in the source code download) looks like this:

C#
static void Main(string[] args)
        {
            try
            {
                var exception = new Exception("This is an exception. 
                                Please see inner exception for details", GetInnerException());
                throw exception;
            }
            catch (Exception e)
            {
                Console.WriteLine(e.ToFullBlownString());
                Console.WriteLine("\n\n\nand now with level = 1:");
                Console.WriteLine(e.ToFullBlownString(1));
            }

            Console.WriteLine("Press any key to exit");
            Console.ReadKey();
        }

        private static Exception GetInnerException()
        {
            try
            {
                throw new Exception("This is the inner exception. 
                               If this was production code, 
                               you'de be presented with details here.");
            }
            catch (Exception e)
            {
                return e;
            }
        }

Further Considerations

Please bear in mind that exception objects sometimes do contain information not meant for everyone to see, for example connection strings and the like. Be careful of what you put into your logfile or display to the end user.

History

  • March 30th, 2017: Initial release
  • April 1st, 2017: Replaced screenshot, added chapter "Further considerations"

License

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