I have many methods which are calling using Delegate.DynamicInvoke
. Some of these methods make database calls and I would like to have the ability to catch a SqlException
and not catch the TargetInvocationException
and hunt through its inners to find what's actually gone wrong.
I was using this method to rethrow but it clears the stack trace:
try
{
return myDelegate.DynamicInvoke(args);
}
catch(TargetInvocationException ex)
{
Func<TargetInvocationException, Exception> getInner = null;
getInner =
delegate(TargetInvocationException e)
{
if (e.InnerException is TargetInvocationException)
return getInner((TargetInvocationException) e.InnerException);
return e.InnerException;
};
Exception inner = getInner(ex);
inner.PreserveStackTrace();
throw inner;
}
The PreserveStackTrace
method is an extension method I fixed up thanks to another post (I don't know what it actually does). However, this doesn't appear to preserve the trace either:
public static void PreserveStackTrace(this 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);
mgr.DoFixups();
}
If a catch block cannot handle the particular exception it has caught, you can rethrow the exception. The rethrow expression ( throw without assignment_expression) causes the originally thrown object to be rethrown.
To keep the original stack trace information with the exception, use the throw statement without specifying the exception.
The InnerException is a property of an exception. When there are series of exceptions, the most current exception can obtain the prior exception in the InnerException property. Let us say we have an exception inside a try block throwing an ArgumentException and the catch clause catches it and writes it to a file.
In c#, the throw is a keyword and it is useful to throw an exception manually during the execution of the program and we can handle those thrown exceptions using try−catch blocks based on our requirements. By using throw keyword in the catch block, we can re-throw an exception that is handled in the catch block.
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
.
You need to keep in mind why .NET wraps the exception with a TargetInvocationException instead of just letting the original exception through. There's a really good reason for that, it isn't obvious where the real reason for the exception came from. Was it because the DynamicInvoke() call is borked? Not unlikely, there's nothing that the compiler can do to ensure that the correct arguments were passed. Or did the invoked target method throw all by itself?
You need to know both to judge the real reason for the exception. Intentionally hiding the TargetInvocationException is going to give you a hard time to diagnose the source of the trouble if it was indeed a problem with the DynamicInvoke() call. Avoid doing this.
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