Related
Lets say I have this two functions:
private string otherString;
private void Error(string message) {
throw new Exception("Error: " + message);
}
private void Expected(string message) {
Error("Expected " + message + " got " + otherString);
}
Now I want to write code that looks like the this:
private int ReadInt() {
int result = 0;
if(int.TryParse(otherString, out result)) {
return result;
}
Expected("Int");
//return 0; is need to compile but it will be never reached
}
I understand that the compiler can not assume that by calling Expected the ReadInt function will end. Is there another way to do what I want to do without the need to write the throw statement in every place I want to exit with an Error?
throw new Exception("Error: Expected Digit got " + otherString);
Probably you are going to log/catch this exception later, here is the problem, With the current set up you will not know (directly) where the exception actually happened, from TargetSite you will only get information about method Error throwing exception and not the actual method ReadInt. (Although through Stack Trace you can see the call hierarchy and the ReadInt method).
Throw exception where ever you think it should be thrown, not from some generic method. Also instead of throwing base class exception, throw specific exceptions like InvalidArgumentException etc.
As a side note, if you are only concerned about parsing related exceptions then don't use TryParse group of methods and let the original exception bubble up.
Apart from what the other answers are saying (don't do that, it's not a good practice), you could simply "fool" the compiler by having the error-method return a fake value:
private string otherString;
private T Error<T>(string message) {
throw new Exception("Error: " + message);
return default(T);
}
private T Expected<T>(string message) {
return Error<T>("Expected " + message + " got " + otherString);
}
private int ReadInt() {
int result = 0;
if(int.TryParse(otherString, out result)) {
return result;
}
return Expected<int>("Int");
}
Another possibility (as suggested in the comments) is to return the exception and throw it in the method:
private string otherString;
private Exception Error(string message) {
return new Exception("Error: " + message);
}
private Expected(string message) {
return Error("Expected " + message + " got " + otherString);
}
private int ReadInt() {
int result = 0;
if(int.TryParse(otherString, out result)) {
return result;
}
throw Expected("Int");
}
Last, but not least, you can create your own exception and throw that one:
class ExpectedException : Exception
{
public ExpectedException(string message)
: base("Expected " + message + " got " + otherString)
{}
}
private int ReadInt() {
int result = 0;
if(int.TryParse(otherString, out result)) {
return result;
}
throw new ExpectedException("Int");
}
Is there any way to write a LINQ style "short hand" code for walking to all levels of InnerException(s) of Exception thrown? I would prefer to write it in place instead of calling an extension function (as below) or inheriting the Exception class.
static class Extensions
{
public static string GetaAllMessages(this Exception exp)
{
string message = string.Empty;
Exception innerException = exp;
do
{
message = message + (string.IsNullOrEmpty(innerException.Message) ? string.Empty : innerException.Message);
innerException = innerException.InnerException;
}
while (innerException != null);
return message;
}
};
Unfortunately LINQ doesn't offer methods that could process hierarchical structures, only collections.
I actually have some extension methods that could help do this. I don't have the exact code in hand but they're something like this:
// all error checking left out for brevity
// a.k.a., linked list style enumerator
public static IEnumerable<TSource> FromHierarchy<TSource>(
this TSource source,
Func<TSource, TSource> nextItem,
Func<TSource, bool> canContinue)
{
for (var current = source; canContinue(current); current = nextItem(current))
{
yield return current;
}
}
public static IEnumerable<TSource> FromHierarchy<TSource>(
this TSource source,
Func<TSource, TSource> nextItem)
where TSource : class
{
return FromHierarchy(source, nextItem, s => s != null);
}
Then in this case you could do this to enumerate through the exceptions:
public static string GetaAllMessages(this Exception exception)
{
var messages = exception.FromHierarchy(ex => ex.InnerException)
.Select(ex => ex.Message);
return String.Join(Environment.NewLine, messages);
}
You mean something like this?
public static class Extensions
{
public static IEnumerable<Exception> GetInnerExceptions(this Exception ex)
{
if (ex == null)
{
throw new ArgumentNullException("ex");
}
var innerException = ex;
do
{
yield return innerException;
innerException = innerException.InnerException;
}
while (innerException != null);
}
}
This way you could LINQ over your entire exceptions hierarchy, like this:
exception.GetInnerExceptions().Where(e => e.Message == "Oops!");
How about this code:
private static string GetExceptionMessages(this Exception e, string msgs = "")
{
if (e == null) return string.Empty;
if (msgs == "") msgs = e.Message;
if (e.InnerException != null)
msgs += "\r\nInnerException: " + GetExceptionMessages(e.InnerException);
return msgs;
}
Usage:
Console.WriteLine(e.GetExceptionMessages())
Example of output:
There was no endpoint listening at
http://nnn.mmm.kkk.ppp:8000/routingservice/router that could accept
the message. This is often caused by an incorrect address or SOAP
action. See InnerException, if present, for more details.
InnerException: Unable to connect to the remote server
InnerException: No connection could be made because the target machine
actively refused it 127.0.0.1:8000
For those, who are waiting for a one-liner.
exc.ToString();
This will go through all your inner exceptions and return all messages, the downside is that it will also contain stack traces, etc.
You don't need extension methods or recursive calls:
try {
// Code that throws exception
}
catch (Exception e)
{
var messages = new List<string>();
do
{
messages.Add(e.Message);
e = e.InnerException;
}
while (e != null) ;
var message = string.Join(" - ", messages);
}
LINQ is generally used to work with collections of objects. However, arguably, in your case there is no collection of objects (but a graph). So even though some LINQ code might be possible, IMHO it would be rather convoluted or artificial.
On the other hand, your example looks like a prime example where extension methods are actually reasonable. Not to speak of issues like reuse, encapsulation, etc.
I would stay with an extension method, although I might have implemented it that way:
public static string GetAllMessages(this Exception ex)
{
if (ex == null)
throw new ArgumentNullException("ex");
StringBuilder sb = new StringBuilder();
while (ex != null)
{
if (!string.IsNullOrEmpty(ex.Message))
{
if (sb.Length > 0)
sb.Append(" ");
sb.Append(ex.Message);
}
ex = ex.InnerException;
}
return sb.ToString();
}
But that is largely an issue of taste.
I don't think so, exception is not an IEnumerable so you can't perform a linq query against one on its own.
An extension method to return the inner exceptions would work like this
public static class ExceptionExtensions
{
public static IEnumerable<Exception> InnerExceptions(this Exception exception)
{
Exception ex = exception;
while (ex != null)
{
yield return ex;
ex = ex.InnerException;
}
}
}
you could then append all the messages using a linq query like this:
var allMessageText = string.Concat(exception.InnerExceptions().Select(e => e.Message + ","));
To add to others, you may want to let the user decide on how to separate the messages:
public static string GetAllMessages(this Exception ex, string separator = "\r\nInnerException: ")
{
if (ex.InnerException == null)
return ex.Message;
return ex.Message + separator + GetAllMessages(ex.InnerException, separator);
}
public static string GetExceptionMessage(Exception ex)
{
if (ex.InnerException == null)
{
return string.Concat(ex.Message, System.Environment.NewLine, ex.StackTrace);
}
else
{
// Retira a última mensagem da pilha que já foi retornada na recursividade anterior
// (senão a última exceção - que não tem InnerException - vai cair no último else, retornando a mesma mensagem já retornada na passagem anterior)
if (ex.InnerException.InnerException == null)
return ex.InnerException.Message;
else
return string.Concat(string.Concat(ex.InnerException.Message, System.Environment.NewLine, ex.StackTrace), System.Environment.NewLine, GetExceptionMessage(ex.InnerException));
}
}
Most solutions presended here have the following implementation errors:
handle null exceptions
handle the inner exceptions of AggregateException
define a max depth for recurse inner exceptions (ie. with circular dependencies)
A better implementation is this here:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
public static string AggregateMessages(this Exception ex) =>
ex.GetInnerExceptions()
.Aggregate(
new StringBuilder(),
(sb, e) => sb.AppendLine(e.Message),
sb => sb.ToString());
public static IEnumerable<Exception> GetInnerExceptions(this Exception ex, int maxDepth = 5)
{
if (ex == null || maxDepth <= 0)
{
yield break;
}
yield return ex;
if (ex is AggregateException ax)
{
foreach(var i in ax.InnerExceptions.SelectMany(ie => GetInnerExceptions(ie, maxDepth - 1)))
yield return i;
}
foreach (var i in GetInnerExceptions(ex.InnerException, maxDepth - 1))
yield return i;
}
Example usage:
try
{
// ...
}
catch(Exception e)
{
Log.Error(e, e.AggregateMessages());
}
I'm just going to leave the most concise version here:
public static class ExceptionExtensions
{
public static string GetMessageWithInner(this Exception ex) =>
string.Join($";{ Environment.NewLine }caused by: ",
GetInnerExceptions(ex).Select(e => $"'{ e.Message }'"));
public static IEnumerable<Exception> GetInnerExceptions(this Exception ex)
{
while (ex != null)
{
yield return ex;
ex = ex.InnerException;
}
}
}
public static class ExceptionExtensions
{
public static IEnumerable<Exception> GetAllExceptions(this Exception ex)
{
Exception currentEx = ex;
yield return currentEx;
while (currentEx.InnerException != null)
{
currentEx = currentEx.InnerException;
yield return currentEx;
}
}
public static IEnumerable<string> GetAllExceptionAsString(this Exception ex)
{
Exception currentEx = ex;
yield return currentEx.ToString();
while (currentEx.InnerException != null)
{
currentEx = currentEx.InnerException;
yield return currentEx.ToString();
}
}
public static IEnumerable<string> GetAllExceptionMessages(this Exception ex)
{
Exception currentEx = ex;
yield return currentEx.Message;
while (currentEx.InnerException != null)
{
currentEx = currentEx.InnerException;
yield return currentEx.Message;
}
}
}
With AggregateException
public static List<Exception> GetInnerExceptions(this Exception e)
{
List<Exception> eList = new List<Exception>();
if (e is AggregateException)
{
eList.AddRange((e as AggregateException).InnerExceptions);
}
else
{
eList.Add(e);
}
List<Exception> ieList = eList
.Where(i => i.InnerException != null)
.SelectMany(i => i.InnerException.GetInnerExceptions())
.ToList();
eList.AddRange(ieList);
return eList;
}
Just use the following code.
catch(Exception ex)
{
Exception currentEx = ex;
while (currentEx.InnerException != null)
{
currentEx = currentEx.InnerException;
}
return currentEx;
}
After 9+ years the original question still begs for an answer.
Not exactly short, but yes, it can be done LINQ-style in a single statement:
var ex1 = new NullReferenceException("EX1");
var ex2 = new InvalidCastException("EX2", ex1);
var ex3 = new InvalidOperationException("EX3", ex2);
const int maxDepth = 10;
var message = Enumerable.Range(1, maxDepth).Aggregate(
new { s = $"{ex3.GetType().Name} - {ex3.Message}", ex = ex3.InnerException },
(v, i) => v.ex != null
? new { s = v.s + $"\nInner exception {i}: {v.ex.GetType().Name} - {v.ex.Message}",
ex = v.ex.InnerException }
: new { s = v.s, ex = (Exception)null },
v => v.s);
/* message is:
InvalidOperationException - EX3
Inner exception 1: InvalidCastException - EX2
Inner exception 2: NullReferenceException - EX1
*/
The key is to use Enumerable.Range().Aggregate() for iteration and a value v of anonymous type (introduced in C# 3.0) holding both
the result v.s being built up, as well as
the current exception v.ex as we're walking down the list.
(StringBuilder left out to reduce clutter.)
I used combination of Select and Join:
Unit test:
[Test]
public void FirendlyErrorMessage_Tests()
{
// Arrange
Exception ex = new AggregateException(new Exception("MY_ERROR_MESSAGE_FROM_DCE_1"), new Exception("MY_ERROR_MESSAGE_FROM_DCE_2"), new Exception("MY_ERROR_MESSAGE_FROM_DCE_3"));
// Assert
var e = Assert.Throws<Exception>(() => ErrorHandler.RaiseFirendlyErrorMessage(ex));
Assert.AreEqual(e.Message, "One or more errors occurred. Possible reasons: MY_ERROR_MESSAGE_1, MY_ERROR_MESSAGE_2, MY_ERROR_MESSAGE_3");
}
ErrorHandler class:
public void RaiseFirendlyErrorMessage(Exception ex)
{
if (ex is AggregateException)
{
var aggrEx = ex as AggregateException;
string aggregateExcMessage = ex.Message + $" Possible reasons: { string.Join(", ", aggrEx.InnerExceptions.Select(s => s.Message)) }";
throw new Exception(aggregateExcMessage);
}
}
Final message will be:
"One or more errors occurred. Possible reasons: MY_ERROR_MESSAGE_1, MY_ERROR_MESSAGE_2, MY_ERROR_MESSAGE_3"
What is the proper way to show my full InnerException.
I found that some of my InnerExceptions has another InnerException and that go's on pretty deep.
Will InnerException.ToString() do the job for me or do I need to loop through the InnerExceptions and build up a String with StringBuilder?
You can simply print exception.ToString() -- that will also include the full text for all the nested InnerExceptions.
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://learn.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 Messages 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 AggregateExceptions) 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're using Entity Framework, exception.ToString() will not give you the details of DbEntityValidationException exceptions. You might want to use the same method to handle all your exceptions, like:
catch (Exception ex)
{
Log.Error(GetExceptionDetails(ex));
}
Where GetExceptionDetails contains something like this:
public static string GetExceptionDetails(Exception ex)
{
var stringBuilder = new StringBuilder();
while (ex != null)
{
switch (ex)
{
case DbEntityValidationException dbEx:
var errorMessages = dbEx.EntityValidationErrors.SelectMany(x => x.ValidationErrors).Select(x => x.ErrorMessage);
var fullErrorMessage = string.Join("; ", errorMessages);
var message = string.Concat(ex.Message, " The validation errors are: ", fullErrorMessage);
stringBuilder.Insert(0, dbEx.StackTrace);
stringBuilder.Insert(0, message);
break;
default:
stringBuilder.Insert(0, ex.StackTrace);
stringBuilder.Insert(0, ex.Message);
break;
}
ex = ex.InnerException;
}
return stringBuilder.ToString();
}
If you want information about all exceptions then use exception.ToString(). It will collect data from all inner exceptions.
If you want only the original exception then use exception.GetBaseException().ToString(). This will get you the first exception, e.g. the deepest inner exception or the current exception if there is no inner exception.
Example:
try {
Exception ex1 = new Exception( "Original" );
Exception ex2 = new Exception( "Second", ex1 );
Exception ex3 = new Exception( "Third", ex2 );
throw ex3;
} catch( Exception ex ) {
// ex => ex3
Exception baseEx = ex.GetBaseException(); // => ex1
}
buildup on nawfal 's answer.
when using his answer there was a missing variable aggrEx, I added it.
file ExceptionExtenstions.class:
// example usage:
// try{ ... } catch(Exception e) { MessageBox.Show(e.ToFormattedString()); }
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace YourNamespace
{
public static class ExceptionExtensions
{
public static IEnumerable<Exception> GetAllExceptions(this Exception exception)
{
yield return exception;
if (exception is AggregateException )
{
var aggrEx = exception as AggregateException;
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;
}
}
}
public static string ToFormattedString(this Exception exception)
{
IEnumerable<string> messages = exception
.GetAllExceptions()
.Where(e => !String.IsNullOrWhiteSpace(e.Message))
.Select(exceptionPart => exceptionPart.Message.Trim() + "\r\n" + (exceptionPart.StackTrace!=null? exceptionPart.StackTrace.Trim():"") );
string flattened = String.Join("\r\n\r\n", messages); // <-- the separator here
return flattened;
}
}
}
This one is better I think
public static string GetCompleteMessage(this Exception error)
{
System.Text.StringBuilder builder = new StringBuilder();
Exception realerror = error;
builder.AppendLine(error.Message);
while (realerror.InnerException != null)
{
builder.AppendLine(realerror.InnerException.Message);
realerror = realerror.InnerException;
}
return builder.ToString();
}
This code generates a formatted HTML representation of the exception:
const string _HTML_TAB = " ";
public static string ToHtmlString(this Exception ex, int level = 0)
{
string message = GetText("Message", ex.Message, level);
if (ex.InnerException != null && level < 30)
{
message += ToHtmlString(ex.InnerException, level + 1);
}
else
{
message += GetText("StackTrace", ex.StackTrace, level); ;
message += GetText("Source", ex.Source, level); ;
message += GetText("TargetSite", ex.TargetSite.ToString(), level);
}
return message;
}
private static string GetText(string headline, string text, int level)
{
var indentText = string.Join(_HTML_TAB, new string[level + 1]);
var newLine = $"<br />{indentText}{_HTML_TAB}";
return $"{indentText}<b>{headline}</b>{newLine}"
+ $"{text.Replace(Environment.NewLine, newLine)}<br /><br />";
}
I'd like to get a list of all the Azure Table errors and figure out a clean way to handle them in a try...catch block.
For example, I'd like to not have to directly code and compare the InnerException message to String.Contains("The specified entity already exists"). What is the right way to trap these errors?
You could try looking at the values in the Response, rather that the inner exception. This is an example of one of my try catch blocks:
try {
return query.FirstOrDefault();
}
catch (System.Data.Services.Client.DataServiceQueryException ex)
{
if (ex.Response.StatusCode == (int)System.Net.HttpStatusCode.NotFound) {
return null;
}
throw;
}
Obviously this is just for the item doesn't exist error, but I'm sure you can expand on this concept by looking at the list of Azure error codes.
To handle errors while adding objects to a table you can use the following code:
try {
_context.AddObject(TableName, entityObject);
_context.SaveCangesWithRetries();
}
catch(DataServiceRequestException ex) {
ex.Response.Any(r => r.StatusCode == (int)System.Net.HttpStatusCode.Conflict)
throw;
}
As said in other answer you can find a list of TableStorage errors at: http://msdn.microsoft.com/en-us/library/dd179438.aspx
See my code here: http://blog.smarx.com/posts/testing-existence-of-a-windows-azure-blob. The pattern is to catch a StorageClientException, and then use the .ErrorCode property to match against the constants in StorageErrorCode.
Here is code that is provided in the Azure Table Whitepaper, but I'm not sure if this gives any value over smark's reply.
/*
From Azure table whitepaper
When an exception occurs, you can extract the sequence number (highlighted above) of the command that caused the transaction to fail as follows:
try
{
// ... save changes
}
catch (InvalidOperationException e)
{
DataServiceClientException dsce = e.InnerException as DataServiceClientException;
int? commandIndex;
string errorMessage;
ParseErrorDetails(dsce, out commandIndex, out errorMessage);
}
*/
-
void ParseErrorDetails( DataServiceClientException e, out string errorCode, out int? commandIndex, out string errorMessage)
{
GetErrorInformation(e.Message, out errorCode, out errorMessage);
commandIndex = null;
int indexOfSeparator = errorMessage.IndexOf(':');
if (indexOfSeparator > 0)
{
int temp;
if (Int32.TryParse(errorMessage.Substring(0, indexOfSeparator), out temp))
{
commandIndex = temp;
errorMessage = errorMessage.Substring(indexOfSeparator + 1);
}
}
}
void GetErrorInformation( string xmlErrorMessage, out string errorCode, out string message)
{
message = null;
errorCode = null;
XName xnErrorCode = XName.Get("code", "http://schemas.microsoft.com/ado/2007/08/dataservices/metadata");
XName xnMessage = XName.Get ( "message", "http://schemas.microsoft.com/ado/2007/08/dataservices/metadata");
using (StringReader reader = new StringReader(xmlErrorMessage))
{
XDocument xDocument = null;
try
{
xDocument = XDocument.Load(reader);
}
catch (XmlException)
{
// The XML could not be parsed. This could happen either because the connection
// could not be made to the server, or if the response did not contain the
// error details (for example, if the response status code was neither a failure
// nor a success, but a 3XX code such as NotModified.
return;
}
XElement errorCodeElement = xDocument.Descendants(xnErrorCode).FirstOrDefault();
if (errorCodeElement == null)
{
return;
}
errorCode = errorCodeElement.Value;
XElement messageElement = xDocument.Descendants(xnMessage).FirstOrDefault();
if (messageElement != null)
{
message = messageElement.Value;
}
}
}
I know sometimes innerException is null
So the following might fail:
repEvent.InnerException = ex.InnerException.Message;
Is there a quick ternary way to check if innerException is null or not?
Great answers so far. On a similar, but different note, sometimes there is more than one level of nested exceptions. If you want to get the root exception that was originally thrown, no matter how deep, you might try this:
public static class ExceptionExtensions
{
public static Exception GetOriginalException(this Exception ex)
{
if (ex.InnerException == null) return ex;
return ex.InnerException.GetOriginalException();
}
}
And in use:
repEvent.InnerException = ex.GetOriginalException();
Is this what you are looking for?
String innerMessage = (ex.InnerException != null)
? ex.InnerException.Message
: "";
That's funny, I can't find anything wrong with Exception.GetBaseException()?
repEvent.InnerException = ex.GetBaseException().Message;
The simplest solution is to use a basic conditional expression:
repEvent.InnerException = ex.InnerException == null ?
null : ex.InnerException.Message;
Why so much recursion in these answers?
public static class ExceptionExtensions
{
public static Exception GetOriginalException(this Exception ex)
{
while(ex.InnerException != null)ex = ex.InnerException;
return ex;
}
}
Seems like a much more straight forward way to implement this.
Its an old question but for future readers:
In addition to the answers already posted I think the correct way to do this (when you can have more than one InnerException) is Exception.GetBaseException Method
If you want the exception instance you should do this:
repEvent.InnerException = ex.GetBaseException();
If you are only looking for the message this way:
repEvent.InnerException = ex.GetBaseException().Message;
With C# 6.0 you can use:
string message = exception.InnerException?.Message ?? "";
This line of code is similar to:
string message = exception.InnerException == null ? "" : exception.InnerException.Message.
https://msdn.microsoft.com/en-us/library/ty67wk28.aspx
http://blogs.msdn.com/b/jerrynixon/archive/2014/02/26/at-last-c-is-getting-sometimes-called-the-safe-navigation-operator.aspx
With C# 6.0 you can do it in one line.
repEvent.InnerException = ex.InnerException?.Message;
for other feature of C# 6.0 click here
With this code, you could be sure that you haven't lost any inner exception messages
catch (Exception exception)
{
Logger.Error(exception.Message);
while (exception.InnerException != null)
{
exception = exception.InnerException;
Logger.Error(exception);
}
}
Sometimes also InnerException has an InnerException, so you can use a recursive function for it:
public string GetInnerException(Exception ex)
{
if (ex.InnerException != null)
{
return string.Format("{0} > {1} ", ex.InnerException.Message, GetInnerException(ex.InnerException));
}
return string.Empty;
}
Yes:
if (ex.InnerException == null) {
// then it's null
}
Here is another possible implementation that appends the messages and stack traces so we get them full:
private static Tuple<string, string> GetFullExceptionMessageAndStackTrace(Exception exception)
{
if (exception.InnerException == null)
{
if (exception.GetType() != typeof(ArgumentException))
{
return new Tuple<string, string>(exception.Message, exception.StackTrace);
}
string argumentName = ((ArgumentException)exception).ParamName;
return new Tuple<string, string>(String.Format("{0} With null argument named '{1}'.", exception.Message, argumentName ), exception.StackTrace);
}
Tuple<string, string> innerExceptionInfo = GetFullExceptionMessageAndStackTrace(exception.InnerException);
return new Tuple<string, string>(
String.Format("{0}{1}{2}", innerExceptionInfo.Item1, Environment.NewLine, exception.Message),
String.Format("{0}{1}{2}", innerExceptionInfo.Item2, Environment.NewLine, exception.StackTrace));
}
[Fact]
public void RecursiveExtractingOfExceptionInformationOk()
{
// Arrange
Exception executionException = null;
var iExLevelTwo = new NullReferenceException("The test parameter is null");
var iExLevelOne = new ArgumentException("Some test meesage", "myStringParamName", iExLevelTwo);
var ex = new Exception("Some higher level message",iExLevelOne);
// Act
var exMsgAndStackTrace = new Tuple<string, string>("none","none");
try
{
exMsgAndStackTrace = GetFullExceptionMessageAndStackTrace(ex);
}
catch (Exception exception)
{
executionException = exception;
}
// Assert
Assert.Null(executionException);
Assert.True(exMsgAndStackTrace.Item1.Contains("The test parameter is null"));
Assert.True(exMsgAndStackTrace.Item1.Contains("Some test meesage"));
Assert.True(exMsgAndStackTrace.Item1.Contains("Some higher level message"));
Assert.True(exMsgAndStackTrace.Item1.Contains("myStringParamName"));
Assert.True(!string.IsNullOrEmpty(exMsgAndStackTrace.Item2));
Console.WriteLine(exMsgAndStackTrace.Item1);
Console.WriteLine(exMsgAndStackTrace.Item2);
}
class MyException : Exception
{
private const string AMP = "\r\nInnerException: ";
public override string Message
{
get
{
return this.InnerException != null ? base.Message + AMP + this.InnerException.Message : base.Message;
}
}
public override string StackTrace
{
get
{
return this.InnerException != null ? base.StackTrace + AMP + this.InnerException.StackTrace : base.StackTrace;
}
}
}
You may simply write like this:
repEvent.InnerException = ex.InnerException?.Message ?? string.Empty;
For get other type of error you may write like this:
string exception = $"\n{nameof(AccountViewModel)}.{nameof(AccountCommand)}. \nMessage: {ex.Message}. \nInnerException:{ex.InnerException}. \nStackTrace: {ex.StackTrace}";
It is possible to use an exception filter to get more precise aiming.
catch (Exception ex) when (ex.InnerException != null) {...}
Please find more details here
I know this is way old and maybe this has already been answered in a comment I didn't see, but I needed this for a retry policy recently, to catch any inner exception of a given type
public static class ExceptionExtensions
{
public static bool ThisOrInnerIs<T>(this Exception exception, out T casted) where T : Exception
{
casted = exception as T;
if (exception is T) return true;
if (exception.InnerException != null)
{
return ThisOrInnerIs(exception.InnerException, out casted);
}
return false;
}
}