Click here to Skip to main content
15,867,453 members
Articles / General Programming / Exceptions
Tip/Trick

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

Rate me:
Please Sign up or sign in to vote.
5.00/5 (11 votes)
1 Apr 2017CPOL2 min read 30.9K   155   15   13
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)


Written By
Switzerland Switzerland
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
SuggestionEF System.Data.Entity.Validation.DbEntityValidationException Pin
martinrj303-Apr-17 15:49
martinrj303-Apr-17 15:49 
As you mentioned EntityFramework, I'll show you this special Catch I had to write to extend your concept, as it doesn't get added to the innerexception to get the reason for the error:

catch (System.Data.Entity.Validation.DbEntityValidationException ex)
{
var error = ex.EntityValidationErrors.First().ValidationErrors.First();
throw new Exception($"Validation Error: Property:{error.PropertyName}, Message:{error.ErrorMessage}");
}
GeneralRe: EF System.Data.Entity.Validation.DbEntityValidationException Pin
Marco Bertschi3-Apr-17 22:26
protectorMarco Bertschi3-Apr-17 22:26 
GeneralNot very good Pin
SteveTheThread1-Apr-17 12:37
SteveTheThread1-Apr-17 12:37 
GeneralRe: Not very good Pin
Marco Bertschi2-Apr-17 20:45
protectorMarco Bertschi2-Apr-17 20:45 
GeneralMy vote of 5 Pin
BillWoodruff31-Mar-17 17:19
professionalBillWoodruff31-Mar-17 17:19 
GeneralRe: My vote of 5 Pin
Marco Bertschi1-Apr-17 6:19
protectorMarco Bertschi1-Apr-17 6:19 
GeneralMy vote of 5 Pin
Member 787034531-Mar-17 1:30
professionalMember 787034531-Mar-17 1:30 
GeneralRe: My vote of 5 Pin
Marco Bertschi31-Mar-17 2:44
protectorMarco Bertschi31-Mar-17 2:44 
Questionsuggest you post this as a 'Tip' rather than article Pin
BillWoodruff31-Mar-17 0:07
professionalBillWoodruff31-Mar-17 0:07 
AnswerRe: suggest you post this as a 'Tip' rather than article Pin
Marco Bertschi31-Mar-17 2:43
protectorMarco Bertschi31-Mar-17 2:43 
GeneralMy vote of 5 Pin
User 1106097930-Mar-17 6:50
User 1106097930-Mar-17 6:50 
GeneralRe: My vote of 5 Pin
Marco Bertschi30-Mar-17 11:37
protectorMarco Bertschi30-Mar-17 11:37 
GeneralRe: My vote of 5 Pin
User 110609791-Apr-17 2:36
User 110609791-Apr-17 2:36 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.