An inner exception is the exception that caused the current exception. It is used in cases when you want to surface a different exception than the one that your code caught but you don't want to throw away the original context.
When you're debugging and you get an exception, always, always, always click on the View Details link to open the View Details dialog. If the message in the dialog isn't expanded, expand it, then scan down to the Inner Exception entry.
An object that describes the error that caused the current exception. The InnerException property returns the same value as was passed into the Exception(String, Exception) constructor, or null if the inner exception value was not supplied to the constructor.
The StackTrace property returns the frames of the call stack that originate at the location where the exception was thrown. You can obtain information about additional frames in the call stack by creating a new instance of the System. Diagnostics. StackTrace class and using its StackTrace. ToString method.
You can simply print exception.ToString()
-- that will also include the full text for all the nested InnerException
s.
I usually do like this to remove most of the noise:
void LogException(Exception error) {
Exception realerror = error;
while (realerror.InnerException != null)
realerror = realerror.InnerException;
Console.WriteLine(realerror.ToString())
}
Edit: I forgot about this answer and is surprised no one pointed out that you can just do
void LogException(Exception error) {
Console.WriteLine(error.GetBaseException().ToString())
}
Just use exception.ToString()
https://docs.microsoft.com/en-us/dotnet/api/system.exception.tostring#remarks
The default implementation of ToString obtains the name of the class that threw the current exception, the message, the result of calling ToString on the inner exception, and the result of calling Environment.StackTrace. If any of these members is null, its value is not included in the returned string.
If there is no error message or if it is an empty string (""), then no error message is returned. The name of the inner exception and the stack trace are returned only if they are not null.
exception.ToString() will also call .ToString() on that exception's inner exception, and so on...
@Jon's answer is the best solution when you want full detail (all the messages and the stack trace) and the recommended one.
However, there might be cases when you just want the inner messages, and for these cases I use the following extension method:
public static class ExceptionExtensions
{
public static string GetFullMessage(this Exception ex)
{
return ex.InnerException == null
? ex.Message
: ex.Message + " --> " + ex.InnerException.GetFullMessage();
}
}
I often use this method when I have different listeners for tracing and logging and want to have different views on them. That way I can have one listener which sends the whole error with stack trace by email to the dev team for debugging using the .ToString()
method and one that writes a log on file with the history of all the errors that happened each day without the stack trace with the .GetFullMessage()
method.
To pretty print just the Message
s part of deep exceptions, you could do something like this:
public static string ToFormattedString(this Exception exception)
{
IEnumerable<string> messages = exception
.GetAllExceptions()
.Where(e => !String.IsNullOrWhiteSpace(e.Message))
.Select(e => e.Message.Trim());
string flattened = String.Join(Environment.NewLine, messages); // <-- the separator here
return flattened;
}
public static IEnumerable<Exception> GetAllExceptions(this Exception exception)
{
yield return exception;
if (exception is AggregateException aggrEx)
{
foreach (Exception innerEx in aggrEx.InnerExceptions.SelectMany(e => e.GetAllExceptions()))
{
yield return innerEx;
}
}
else if (exception.InnerException != null)
{
foreach (Exception innerEx in exception.InnerException.GetAllExceptions())
{
yield return innerEx;
}
}
}
This recursively goes through all inner exceptions (including the case of AggregateException
s) to print all Message
property contained in them, delimited by line break.
E.g.
var outerAggrEx = new AggregateException(
"Outer aggr ex occurred.",
new AggregateException("Inner aggr ex.", new FormatException("Number isn't in correct format.")),
new IOException("Unauthorized file access.", new SecurityException("Not administrator.")));
Console.WriteLine(outerAggrEx.ToFormattedString());
Outer aggr ex occurred.
Inner aggr ex.
Number isn't in correct format.
Unauthorized file access.
Not administrator.
You will need to listen to other Exception properties for more details. For e.g. Data
will have some information. You could do:
foreach (DictionaryEntry kvp in exception.Data)
To get all derived properties (not on base Exception
class), you could do:
exception
.GetType()
.GetProperties()
.Where(p => p.CanRead)
.Where(p => p.GetMethod.GetBaseDefinition().DeclaringType != typeof(Exception));
I do:
namespace System {
public static class ExtensionMethods {
public static string FullMessage(this Exception ex) {
if (ex is AggregateException aex) return aex.InnerExceptions.Aggregate("[ ", (total, next) => $"{total}[{next.FullMessage()}] ") + "]";
var msg = ex.Message.Replace(", see inner exception.", "").Trim();
var innerMsg = ex.InnerException?.FullMessage();
if (innerMsg is object && innerMsg!=msg) msg = $"{msg} [ {innerMsg} ]";
return msg;
}
}
}
This "pretty prints" all inner exceptions and also handles AggregateExceptions and cases where InnerException.Message is the same as Message
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With