How to Rethrow Innerexception Without Losing Stack Trace in C#

How to rethrow InnerException without losing stack trace in C#?

In .NET 4.5 there is now the ExceptionDispatchInfo class.

This lets you capture an exception and re-throw it without changing the stack-trace:

using ExceptionDispatchInfo = 
System.Runtime.ExceptionServices.ExceptionDispatchInfo;

try
{
task.Wait();
}
catch(AggregateException ex)
{
ExceptionDispatchInfo.Capture(ex.InnerException).Throw();
}

This works on any exception, not just AggregateException.

It was introduced due to the await C# language feature, which unwraps the inner exceptions from AggregateException instances in order to make the asynchronous language features more like the synchronous language features.

C#: Rethrow an exception from a variable while preserving stack trace

That's where ExceptionDispatchInfo comes into play.

It resides inside the System.Runtime.ExceptionServices namespace.

class Program
{
static void Main(string[] args)
{
ExceptionDispatchInfo edi = null;

try
{
// stuff
throw new Exception("A");
}
catch (Exception ex)
{
edi = ExceptionDispatchInfo.Capture(ex);
}

edi?.Throw();
}
}

The output:

Unhandled exception. System.Exception: A
at EDI_Demo.Program.Main(String[] args) in C:\Users\...\Program.cs:line 16
--- End of stack trace from previous location where exception was thrown ---
at EDI_Demo.Program.Main(String[] args) in C:\Users\...\Program.cs:line 24
  • Line 16 is where throw new Exception("A"); is called
  • Line 24 is where edi?.Throw(); is called

How can I rethrow an Inner Exception while maintaining the stack trace generated so far?

It is possible to preserve the stack trace before rethrowing without reflection:

static void PreserveStackTrace (Exception e)
{
var ctx = new StreamingContext (StreamingContextStates.CrossAppDomain) ;
var mgr = new ObjectManager (null, ctx) ;
var si = new SerializationInfo (e.GetType (), new FormatterConverter ()) ;

e.GetObjectData (si, ctx) ;
mgr.RegisterObject (e, 1, si) ; // prepare for SetObjectData
mgr.DoFixups () ; // ObjectManager calls SetObjectData

// voila, e is unmodified save for _remoteStackTraceString
}

This wastes a lot of cycles compared to InternalPreserveStackTrace, but has the advantage of relying only on public functionality. Here are a couple of common usage patterns for stack-trace preserving functions:

// usage (A): cross-thread invoke, messaging, custom task schedulers etc.
catch (Exception e)
{
PreserveStackTrace (e) ;

// store exception to be re-thrown later,
// possibly in a different thread
operationResult.Exception = e ;
}

// usage (B): after calling MethodInfo.Invoke() and the like
catch (TargetInvocationException tiex)
{
PreserveStackTrace (tiex.InnerException) ;

// unwrap TargetInvocationException, so that typed catch clauses
// in library/3rd-party code can work correctly;
// new stack trace is appended to existing one
throw tiex.InnerException ;
}

How to rethrow the inner exception of a TargetInvocationException without losing the stack trace

If you just want to re-throw an inner exception preserving its stack trace, you can do it with a method like this:

public static void Rethrow(this Exception ex)
{
typeof(Exception).GetMethod("PrepForRemoting",
BindingFlags.NonPublic | BindingFlags.Instance)
.Invoke(ex, new object[0]);
throw ex;
}

This technique is used by Rx (and is exposed by them as an extension method Exception.PrepareForRethrow) and is also used by the Async CTP by its automatic-unwrapping system (without a publicly-exposed API).

Note, however, that this technique is technically unsupported. Hopefully Microsoft will add an official API for this in the future. A suggestion has been opened on Microsoft Connect if you would like to vote for it.

Update: An official API has been added to .NET 4.5: ExceptionDispatchInfo.

C# How to rethrow an exception from an outer catch

There is no way to rethrow an exception from an outer catch block inside an inner catch block. The best way to achieve this pattern is to note whether or not the inner operation succeeded :

try {
something();
} catch (MyException e1) {
bool recovered=false;
try {
somethingElse();
recovered=true;
} catch {

}
if (!recovered) {
throw;
}
}

What is the proper way to rethrow an exception in C#?

You should always use the following syntax to rethrow an exception. Else you'll stomp the stack trace:

throw;

If you print the trace resulting from throw ex, you'll see that it ends on that statement and not at the real source of the exception.

Basically, it should be deemed a criminal offense to use throw ex.


If there is a need to rethrow an exception that comes from somewhere else (AggregateException, TargetInvocationException) or perhaps another thread, you also shouldn't rethrow it directly. Rather there is the ExceptionDispatchInfo that preserves all the necessary information.

try
{
methodInfo.Invoke(...);
}
catch (System.Reflection.TargetInvocationException e)
{
System.Runtime.ExceptionServices.ExceptionDispatchInfo.Capture(e.InnerException).Throw();
throw; // just to inform the compiler that the flow never leaves the block
}

Rethrow an Exception with correct line numbers in the stack trace

You do not lose original exception if you place it in an inner exception.

[WebMethod]
public void ExceptionTest()
{
try
{
throw new Exception("An Error Happened");
}
catch (Exception ex)
{
evlWebServiceLog.WriteEntry(ex.ToString(), EventLogEntryType.Error);
throw new Exception("Your message", ex);
}
}


Related Topics



Leave a reply



Submit