Leave current function via exception in called function - c#

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");
}

Related

Adding more information to InvalidOperationException line

I am trying to learn how to throw exceptions.
Currently when I do the following
try
{
throw new InvalidOperationException("TEST");
}
catch
{
throw;
}
When I look into AI the exception comes like this:#
InvalidOperationException
with a message "Test"
How do I get it to throw something like the below?
System.InvalidOperationException: TEST at test.Program.Main
As moreON said in the comment, you could get where the exception thrown from with Exception.StackTrace property.
try
{
throw new InvalidOperationException("TEST");
}
catch(InvalidOperationException e)
{
throw new InvalidOperationException(e.Message + e.StackTrace);
}
Or you can get the current project name/file name/method name/line number. And it throws like this: System.InvalidOperationException: ProjetName.FileName.MethodName(LineNumber): TEXT.
private static string Log(string text,
[CallerFilePath] string file = "",
[CallerMemberName] string member = "",
[CallerLineNumber] int line = 0)
{
return Assembly.GetCallingAssembly().GetName().Name+"."+Path.GetFileName(file)+"."+member+"("+line + "): " + text;
}
// throw exception
try
{
throw new InvalidOperationException(Log("Test"));
}
catch(InvalidOperationException e)
{
throw;
}

System.Web.Http.HttpResponseException in catch block while exception handling

I am intentionally making a violation of a unique constraint in my database, and trying to handle an exception.
This among else is in my form:
HttpResponseMessage response = KorisniciService.PostResponse(k);
if (response.IsSuccessStatusCode)
{
MessageBox.Show(Messages.add_usr_succ);
DialogResult = DialogResult.OK;
Close();
}
else
{
string message = response.ReasonPhrase;
if (string.IsNullOrEmpty(Messages.ResourceManager.GetString(response.ReasonPhrase)))
message = Messages.ResourceManager.GetString(response.ReasonPhrase);
MessageBox.Show("Error code: " + response.StatusCode + " Message: " + message);
}
My controller:
public IHttpActionResult PostKorisnici(Korisnici obj)
{
if (!ModelState.IsValid)
return BadRequest();
try
{
obj.KorisnikId = Convert.ToInt32(dm.esp_Korisnici_Insert(obj.Ime, obj.Prezime, obj.Email, obj.Telefon, obj.KorisnickoIme, obj.LozinkaSalt, obj.LozinkaHash, obj.Status, obj.Adresa, obj.GradId).FirstOrDefault());
}
catch (EntityException ex)
{
throw CreateHttpResponseException(Util.ExceptionHandler.HandleException(ex), HttpStatusCode.Conflict);
}
foreach (var item in obj.Uloge)
{
dm.esp_KorisniciUloge_Insert(obj.KorisnikId, item.UlogaId);
}
return CreatedAtRoute("DefaultApi", new { id = obj.KorisnikId }, obj);
}
HttpResponseException making function:
private HttpResponseException CreateHttpResponseException(string reason, HttpStatusCode code)
{
HttpResponseMessage msg = new HttpResponseMessage()
{
StatusCode = code,
ReasonPhrase = reason,
Content = new StringContent(reason)
};
return new HttpResponseException(Request.CreateResponse(msg));
}
Exception handler class:
public class ExceptionHandler
{
public static string HandleException(EntityException error)
{
SqlException ex = error.InnerException as SqlException;
switch (ex.Number)
{
case 2627:
{
return GetConstraintExceptionMessage(ex);
}
default:
return error.Message + "(" + error +")";
}
}
/*Message "Violation of UNIQUE KEY constraint 'CS_KorisnickoIme'. Cannot insert duplicate key in object 'dbo.Korisnici'. The duplicate key value is (farish).\r\nThe statement has been terminated." string*/
private static string GetConstraintExceptionMessage(SqlException error)
{
string newMessage = error.Message;
int startIndex = newMessage.IndexOf("'");
int endIndex = newMessage.IndexOf("'", startIndex + 1);
if (startIndex>0 && endIndex>0)
{
string constraintName = newMessage.Substring(startIndex + 1, endIndex - startIndex - 1);
if (constraintName == "CS_KorisnickoIme")
newMessage = "username_con";
else if (constraintName == "CS_Email")
newMessage = "email_con";
}
return newMessage;
}
So when I produce an error, instead of a popup window (which shows up fine in a tutorial video) I get a System.Web.Http.HttpResponseException in a first catch block of my post method and nothing passed back to my form.
I think because the exception is being thrown and not inside a try/catch block, or the catch block receiving the CreateHttpResponseException, is absorbing it and not providing a response object.
EDIT
Can you post the code for KorisniciService.PostResponse?
and nothing passed back to my form
And what is the eventual result? From the form code you have posted it should either popup message box with success message, or popup message box with fail message. What actually happens?
2nd EDIT
Following further information, use this in your form code...
try
{
HttpResponseMessage response = KorisniciService.PostResponse(k);
if (response.IsSuccessStatusCode)
{
MessageBox.Show(Messages.add_usr_succ);
DialogResult = DialogResult.OK;
Close();
}
}
catch(HttpResponseException ex)
{
string message = ex.ReasonPhrase;
if (string.IsNullOrEmpty(Messages.ResourceManager.GetString(ex.ReasonPhrase)))
message = Messages.ResourceManager.GetString(ex.ReasonPhrase);
MessageBox.Show("Error code: " + ex.StatusCode + " Message: " + message);
}

Getting all messages from InnerException(s)?

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 display the full InnerException?

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 />";
}

Best way to check for inner exception?

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;
}
}

Categories

Resources