Related
I want to be able to catch exception with the Postsharp OnMethodBoundary.OnException. But only once. Let me explain.
I have these method :
public void FooV1(){
throw new NotYetImplementedException();
}
public void FooV2(){
try{
throw new NotYetImplementedException();
} catch(Exception) {
Console.Writeline("Exception has be caught by catch block.");
}
}
And this OnException :
public void OnException(MethodExecutionArgs args){
Console.Writeline("Exception has be caught by Postsharp.");
}
When an exception occurs, the exception is beeing caught, I do some work (save the context) but I don't want to interfere with the program workflow. So if the exception is raised in a try catch block, it will be caught , if not, then it will raise the exception.
If in the OnException(...) I use args.FlowBehavior = FlowBehavior.Default;
I get :
In Foov1:
Exception has be caught by Postsharp.
Exception has be caught by Postsharp.
Because when the exception in rethrown Postsharp recatch it (but only one time ? I expected it to loop). I would like to get OnException to be called only once and if the exception is not caught higher in the callstack then the program should stop.
And in FooV2:
Exception has be caught by Postsharp.
Exception has be caught by catch block.
There I get the expected result.
I can't use FlowBehavior.Continue or FlowBehavior.Return because the catch block would not be reached.
And I don't see the difference between FlowBehavior.Throw and FlowBehavior.Rethrow
How can I fix that ?
I don't know what your actual code is but you're probably applying your OnException aspect to two or more methods: both the method that throws the original exception and the method that catches the exception. That would explain why you are seeing the OnException message twice.
When you do
[YourPostSharpOnExceptionAspect]
void A()
{
// code
}
It's translated into something roughly like:
void A()
{
try {
// code
} catch (Exception e) {
yourPostSharpOnExceptionAspectInstance.OnException(e);
throw;
}
}
Since each PostSharp aspect keeps rethrowing the same exception, you'll get to catch it multiple times.
You may need to add code of your own to handle each exception only once. You could do something like this:
public void OnException(MethodExecutionArgs args){
if (args.Exception.Data["Handled"]) {
// do nothing, already saved
args.FlowBehavior = FlowBehavior.Rethrow;
}
else
{
// first time seeing this exception, do stuff....
args.Exception.Data["Handled"] = true; // and mark the exception as processed
args.FlowBehavior = FlowBehavior.Throw;
}
}
The difference between Throw and Rethrow is that Throw adds something like throw args.Exception to the code while Rethrow adds merely throw; rethrowing the exception that was originally caught (and keeping the original stack trace).
What are the best practices to consider when catching exceptions and re-throwing them? I want to make sure that the Exception object's InnerException and stack trace are preserved. Is there a difference between the following code blocks in the way they handle this?
try
{
//some code
}
catch (Exception ex)
{
throw ex;
}
Vs:
try
{
//some code
}
catch
{
throw;
}
The way to preserve the stack trace is through the use of the throw; This is valid as well
try {
// something that bombs here
} catch (Exception ex)
{
throw;
}
throw ex; is basically like throwing an exception from that point, so the stack trace would only go to where you are issuing the throw ex; statement.
Mike is also correct, assuming the exception allows you to pass an exception (which is recommended).
Karl Seguin has a great write up on exception handling in his foundations of programming e-book as well, which is a great read.
Edit: Working link to Foundations of Programming pdf. Just search the text for "exception".
If you throw a new exception with the initial exception you will preserve the initial stack trace too..
try{
}
catch(Exception ex){
throw new MoreDescriptiveException("here is what was happening", ex);
}
Actually, there are some situations which the throw statment will not preserve the StackTrace information. For example, in the code below:
try
{
int i = 0;
int j = 12 / i; // Line 47
int k = j + 1;
}
catch
{
// do something
// ...
throw; // Line 54
}
The StackTrace will indicate that line 54 raised the exception, although it was raised at line 47.
Unhandled Exception: System.DivideByZeroException: Attempted to divide by zero.
at Program.WithThrowIncomplete() in Program.cs:line 54
at Program.Main(String[] args) in Program.cs:line 106
In situations like the one described above, there are two options to preseve the original StackTrace:
Calling the Exception.InternalPreserveStackTrace
As it is a private method, it has to be invoked by using reflection:
private static void PreserveStackTrace(Exception exception)
{
MethodInfo preserveStackTrace = typeof(Exception).GetMethod("InternalPreserveStackTrace",
BindingFlags.Instance | BindingFlags.NonPublic);
preserveStackTrace.Invoke(exception, null);
}
I has a disadvantage of relying on a private method to preserve the StackTrace information. It can be changed in future versions of .NET Framework. The code example above and proposed solution below was extracted from Fabrice MARGUERIE weblog.
Calling Exception.SetObjectData
The technique below was suggested by Anton Tykhyy as answer to In C#, how can I rethrow InnerException without losing stack trace question.
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
}
Although, it has the advantage of relying in public methods only it also depends on the following exception constructor (which some exceptions developed by 3rd parties do not implement):
protected Exception(
SerializationInfo info,
StreamingContext context
)
In my situation, I had to choose the first approach, because the exceptions raised by a 3rd-party library I was using didn't implement this constructor.
When you throw ex, you're essentially throwing a new exception, and will miss out on the original stack trace information. throw is the preferred method.
The rule of thumb is to avoid Catching and Throwing the basic Exception object. This forces you to be a little smarter about exceptions; in other words you should have an explicit catch for a SqlException so that your handling code doesn't do something wrong with a NullReferenceException.
In the real world though, catching and logging the base exception is also a good practice, but don't forget to walk the whole thing to get any InnerExceptions it might have.
Nobody has explained the difference between ExceptionDispatchInfo.Capture( ex ).Throw() and a plain throw, so here it is. However, some people have noticed the problem with throw.
The complete way to rethrow a caught exception is to use ExceptionDispatchInfo.Capture( ex ).Throw() (only available from .Net 4.5).
Below there are the cases necessary to test this:
1.
void CallingMethod()
{
//try
{
throw new Exception( "TEST" );
}
//catch
{
// throw;
}
}
2.
void CallingMethod()
{
try
{
throw new Exception( "TEST" );
}
catch( Exception ex )
{
ExceptionDispatchInfo.Capture( ex ).Throw();
throw; // So the compiler doesn't complain about methods which don't either return or throw.
}
}
3.
void CallingMethod()
{
try
{
throw new Exception( "TEST" );
}
catch
{
throw;
}
}
4.
void CallingMethod()
{
try
{
throw new Exception( "TEST" );
}
catch( Exception ex )
{
throw new Exception( "RETHROW", ex );
}
}
Case 1 and case 2 will give you a stack trace where the source code line number for the CallingMethod method is the line number of the throw new Exception( "TEST" ) line.
However, case 3 will give you a stack trace where the source code line number for the CallingMethod method is the line number of the throw call. This means that if the throw new Exception( "TEST" ) line is surrounded by other operations, you have no idea at which line number the exception was actually thrown.
Case 4 is similar with case 2 because the line number of the original exception is preserved, but is not a real rethrow because it changes the type of the original exception.
You should always use "throw;" to rethrow the exceptions in .NET,
Refer this,
http://weblogs.asp.net/bhouse/archive/2004/11/30/272297.aspx
Basically MSIL (CIL) has two instructions - "throw" and "rethrow":
C#'s "throw ex;" gets compiled into MSIL's "throw"
C#'s "throw;" - into MSIL "rethrow"!
Basically I can see the reason why "throw ex" overrides the stack trace.
A few people actually missed a very important point - 'throw' and 'throw ex' may do the same thing but they don't give you a crucial piece of imformation which is the line where the exception happened.
Consider the following code:
static void Main(string[] args)
{
try
{
TestMe();
}
catch (Exception ex)
{
string ss = ex.ToString();
}
}
static void TestMe()
{
try
{
//here's some code that will generate an exception - line #17
}
catch (Exception ex)
{
//throw new ApplicationException(ex.ToString());
throw ex; // line# 22
}
}
When you do either a 'throw' or 'throw ex' you get the stack trace but the line# is going to be #22 so you can't figure out which line exactly was throwing the exception (unless you have only 1 or few lines of code in the try block). To get the expected line #17 in your exception you'll have to throw a new exception with the original exception stack trace.
You may also use:
try
{
// Dangerous code
}
finally
{
// clean up, or do nothing
}
And any exceptions thrown will bubble up to the next level that handles them.
I would definitely use:
try
{
//some code
}
catch
{
//you should totally do something here, but feel free to rethrow
//if you need to send the exception up the stack.
throw;
}
That will preserve your stack.
FYI I just tested this and the stack trace reported by 'throw;' is not an entirely correct stack trace. Example:
private void foo()
{
try
{
bar(3);
bar(2);
bar(1);
bar(0);
}
catch(DivideByZeroException)
{
//log message and rethrow...
throw;
}
}
private void bar(int b)
{
int a = 1;
int c = a/b; // Generate divide by zero exception.
}
The stack trace points to the origin of the exception correctly (reported line number) but the line number reported for foo() is the line of the throw; statement, hence you cannot tell which of the calls to bar() caused the exception.
I have the following code:
try
{
retval = axNTLXRemote.IsUnitPresent(_servers[0].IPAddress, 1, _servers[0].RemotePort, _servers[0].CommFailDelay * 1000);
}
catch (COMException ce)
{
throw ce;
}
Which gives me the followig warning which I want to get rid of:
CA2200 : Microsoft.Usage : 'Connect()' rethrows a caught exception and specifies it explicitly as an argument. Use 'throw' without an argument instead, in order to preserve the stack location where the exception was initially raised.
I have read the following The difference between try/catch/throw and try/catch(e)/throw e and I understand that the 'throw ce; will reset the stack trace and make it appear as if the exception was thrown from that function.
I want to simply change it to a 'throw' instead of a 'throw ce' which will get rid of the warning.
What is the difference in the following catches:
catch (COMException ce)
{
throw;
}
and
catch (COMException)
{
throw;
}
Do I only need to have 'COMException ce' if I wish to somehow use the ce variable?
Also, when I perform a 'throw' or 'throw ce', is it the calling function that will handle or catch it?? I'm a little unclear about this.
The only difference is that with catch (COMException ce), you are assigning the exception to a variable, thereby letting you access it within the catch block. Other than that, it is in every way identical.
I'm not sure what the question is here. If you want to access the exception object, you must give it a variable name in the catch clause.
No matter how or where an exception is thrown, the exception will bubble up through the call stack to the closest catch block that matches.
Here's an example.
void Method1()
{
try
{
Method2();
}
catch // this will catch *any* exception
{
}
}
void Method2()
{
try
{
Method3();
}
catch (COMException ex) // this will catch only COMExceptions and exceptions that derive from COMException
{
}
}
void Method3()
{
// if this code were here, it would be caught in Method2
throw new COMException();
// if this code were here, it would be caught in Method1
throw new ApplicationException();
}
I'm sure someone will jump in with an uber-technical answer, but in my experience the answer to your first two questions is that there is no difference, and as you stated you'd only include ce if you intended to use it to write the stack trace to a log or display the message to the user or similar.
The throw will send the exception up the chain. That may be the calling method or, if your method has several nested try/catch blocks, it will send the exception to the next try/catch block that the current try/catch block is nested within.
Here are a couple good resources to check out if you want to read further on the subject:
Exception Handling
Design Guidelines for Exceptions
There is no difference in both cases, but only when exception variable should be used for stack/message etc.
So:
catch(ComException);
and
catch(ComException ex);
statements will produce similar MSIL, except local variable for ComException object:
.locals init ([0] class [mscorlib]System.Exception ex)
I rethrow an exception with "throw;", but the stacktrace is incorrect:
static void Main(string[] args) {
try {
try {
throw new Exception("Test"); //Line 12
}
catch (Exception ex) {
throw; //Line 15
}
}
catch (Exception ex) {
System.Diagnostics.Debug.Write(ex.ToString());
}
Console.ReadKey();
}
The right stacktrace should be:
System.Exception: Test
at ConsoleApplication1.Program.Main(String[] args) in Program.cs:Line 12
But I get:
System.Exception: Test
at ConsoleApplication1.Program.Main(String[] args) in Program.cs:Line 15
But line 15 is the position of the "throw;". I have tested this with .NET 3.5.
Throwing twice in the same method is probably a special case - I've not been able to create a stack trace where different lines in the same method follow each other. As the word says, a "stack trace" shows you the stack frames that an exception traversed. And there is only one stack frame per method call!
If you throw from another method, throw; will not remove the entry for Foo(), as expected:
static void Main(string[] args)
{
try
{
Rethrower();
}
catch (Exception ex)
{
Console.Write(ex.ToString());
}
Console.ReadKey();
}
static void Rethrower()
{
try
{
Foo();
}
catch (Exception ex)
{
throw;
}
}
static void Foo()
{
throw new Exception("Test");
}
If you modify Rethrower() and replace throw; by throw ex;, the Foo() entry in the stack trace disappears. Again, that's the expected behavior.
It's something that can be considered as expected.
Modifying stack trace is usual case if you specify throw ex;, FxCop will than notify you that stack is modified. In case you make throw;, no warning is generated, but still, the trace will be modified.
So unfortunately for now it's the best not to catch the ex or throw it as an inner one.
I think it should be considered as a Windows impact or smth like that - edited.
Jeff Richter describes this situation in more detail in his "CLR via C#":
The following code throws the same
exception object that it caught and
causes the CLR to reset its starting
point for the exception:
private void SomeMethod() {
try { ... }
catch (Exception e) {
...
throw e; // CLR thinks this is where exception originated.
// FxCop reports this as an error
}
}
In contrast, if you re-throw an
exception object by using the throw
keyword by itself, the CLR doesn’t
reset the stack’s starting point. The
following code re-throws the same
exception object that it caught,
causing the CLR to not reset its
starting point for the exception:
private void SomeMethod() {
try { ... }
catch (Exception e) {
...
throw; // This has no effect on where the CLR thinks the exception
// originated. FxCop does NOT report this as an error
}
}
In fact, the only difference between
these two code fragments is what the
CLR thinks is the original location
where the exception was thrown.
Unfortunately, when you throw or
rethrow an exception, Windows does
reset the stack’s starting point. So
if the exception becomes unhandled,
the stack location that gets reported
to Windows Error Reporting is the
location of the last throw or
re-throw, even though the CLR knows
the stack location where the original
exception was thrown. This is
unfortunate because it makes debugging
applications that have failed in the
field much more difficult. Some
developers have found this so
intolerable that they have chosen a
different way to implement their code
to ensure that the stack trace truly
reflects the location where an
exception was originally thrown:
private void SomeMethod() {
Boolean trySucceeds = false;
try {
...
trySucceeds = true;
}
finally {
if (!trySucceeds) { /* catch code goes in here */ }
}
}
This is a well known limitation in the Windows version of the CLR. It uses Windows' built-in support for exception handling (SEH). Problem is, it is stack frame based and a method has only one stack frame. You can easily solve the problem by moving the inner try/catch block into another helper method, thus creating another stack frame. Another consequence of this limitation is that the JIT compiler won't inline any method that contains a try statement.
How can I preserve the REAL stacktrace?
You throw a new exception, and include the original exception as the inner exception.
but that's Ugly... Longer... Makes you choice the rigth exception to throw....
You are wrong about the ugly but right about the other two points. The rule of thumb is: don't catch unless you are going to do something with it, like wrap it, modify it, swallow it, or log it. If you decide to catch and then throw again, make sure you are doing something with it, otherwise just let it bubble up.
You may also be tempted to put a catch simply so you can breakpoint within the catch, but the Visual Studio debugger has enough options to make that practice unnecessary, try using first chance exceptions or conditional breakpoints instead.
Edit/Replace
The behavior is actually different, but subtilely so. As for why the behavior if different, I'll need to defer to a CLR expert.
EDIT: AlexD's answer seems to indicate that this is by design.
Throwing the exception in the same method that catches it confuses the situation a little, so let's throw an exception from another method:
class Program
{
static void Main(string[] args)
{
try
{
Throw();
}
catch (Exception ex)
{
throw ex;
}
}
public static void Throw()
{
int a = 0;
int b = 10 / a;
}
}
If throw; is used, the callstack is (line numbers replaced with code):
at Throw():line (int b = 10 / a;)
at Main():line (throw;) // This has been modified
If throw ex; is used, the callstack is:
at Main():line (throw ex;)
If exception is not caught, the callstack is:
at Throw():line (int b = 10 / a;)
at Main():line (Throw())
Tested in .NET 4 / VS 2010
There is a duplicate question here.
As I understand it - throw; is compiled into 'rethrow' MSIL instruction and it modifies the last frame of the stack-trace.
I would expect it to keep the original stack-trace and add the line where it has been re-thrown, but apparently there can only be one stack frame per method call.
Conclusion: avoid using throw; and wrap your exception in a new one on re-throwing - it's not ugly, it's best practice.
You can preserve stack trace using
ExceptionDispatchInfo.Capture(ex);
Here is code sample:
static void CallAndThrow()
{
throw new ApplicationException("Test app ex", new Exception("Test inner ex"));
}
static void Main(string[] args)
{
try
{
try
{
try
{
CallAndThrow();
}
catch (Exception ex)
{
var dispatchException = ExceptionDispatchInfo.Capture(ex);
// rollback tran, etc
dispatchException.Throw();
}
}
catch (Exception ex)
{
var dispatchException = ExceptionDispatchInfo.Capture(ex);
// other rollbacks
dispatchException.Throw();
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
Console.WriteLine(ex.InnerException.Message);
Console.WriteLine(ex.StackTrace);
}
Console.ReadLine();
}
The output will be something like:
Test app ex
Test inner ex
at TestApp.Program.CallAndThrow() in D:\Projects\TestApp\TestApp\Program.cs:line 19
at TestApp.Program.Main(String[] args) in D:\Projects\TestApp\TestApp\Program.cs:line 30
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at TestApp.Program.Main(String[] args) in D:\Projects\TestApp\TestApp\Program.cs:line 38
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at TestApp.Program.Main(String[] args) in D:\Projects\TestApp\TestApp\Program.cs:line 47
OK, there seems to be a bug in the .NET Framework, if you throw an exception, and rethrow it in the same method, the original line number is lost (it will be the last line of the method).
Fortunatelly, a clever guy named Fabrice MARGUERIE found a solution to this bug. Below is my version, which you can test in this .NET Fiddle.
private static void RethrowExceptionButPreserveStackTrace(Exception exception)
{
System.Reflection.MethodInfo preserveStackTrace = typeof(Exception).GetMethod("InternalPreserveStackTrace",
System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic);
preserveStackTrace.Invoke(exception, null);
throw exception;
}
Now catch the exception as usually, but instead of throw; just call this method, and voila, the original line number will be preserved!
Not sure whether this is by design, but I think it has always been like that.
If the original throw new Exception is in a separate method, then the result for throw should have the original method name and line number and then the line number in main where the exception is re-thrown.
If you use throw ex, then the result will just be the line in main where the exception is rethrow.
In other words, throw ex loses all the stacktrace, whereas throw preserves the stack trace history (ie details of the lower level methods). But if your exception is generated by the same method as your rethrow, then you can lose some information.
NB. If you write a very simple and small test program, the Framework can sometimes optimise things and change a method to be inline code which means the results may differ from a 'real' program.
Do you want your right line number? Just use one try/catch per method. In systems, well... just in the UI layer, not in logic or data access, this is very annoying, because if you need database transactions, well, they shouldn't be in the UI layer, and you won't have the right line number, but if you don't need them, don't rethrow with nor without an exception in catch...
5 minutes sample code:
Menu File -> New Project, place three buttons, and call the following code in each one:
private void button1_Click(object sender, EventArgs e)
{
try
{
Class1.testWithoutTC();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message + Environment.NewLine + ex.StackTrace + Environment.NewLine + Environment.NewLine + "In. Ex.: " + ex.InnerException);
}
}
private void button2_Click(object sender, EventArgs e)
{
try
{
Class1.testWithTC1();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message + Environment.NewLine + ex.StackTrace + Environment.NewLine + Environment.NewLine + "In. Ex.: " + ex.InnerException);
}
}
private void button3_Click(object sender, EventArgs e)
{
try
{
Class1.testWithTC2();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message + Environment.NewLine + ex.StackTrace + Environment.NewLine + Environment.NewLine + "In. Ex.: " + ex.InnerException);
}
}
Now, create a new Class:
class Class1
{
public int a;
public static void testWithoutTC()
{
Class1 obj = null;
obj.a = 1;
}
public static void testWithTC1()
{
try
{
Class1 obj = null;
obj.a = 1;
}
catch
{
throw;
}
}
public static void testWithTC2()
{
try
{
Class1 obj = null;
obj.a = 1;
}
catch (Exception ex)
{
throw ex;
}
}
}
Run... the first button is beautiful!
I think this is less a case of stack trace changing and more to do with the way the line number for the stack trace is determined. Trying it out in Visual Studio 2010, the behaviour is similar to what you would expect from the MSDN documentation: "throw ex;" rebuilds the stack trace from the point of this statement, "throw;" leaves the stack trace as it as, except that where ever the exception is rethrown, the line number is the location of the rethrow and not the call the exception came through.
So with "throw;" the method call tree is left unaltered, but the line numbers may change.
I've come across this a few times, and it may be by design and just not documented fully. I can understand why they may have done this as the rethrow location is very useful to know, and if your methods are simple enough the original source would usually be obvious anyway.
As many other people have said, it usually best to not catch the exception unless you really have to, and/or you are going to deal with it at that point.
Interesting side note: Visual Studio 2010 won't even let me build the code as presented in the question as it picks up the divide by zero error at compile time.
That is because you catched the Exception from Line 12 and have rethrown it on Line 15, so the Stack Trace takes it as cash, that the Exception was thrown from there.
To better handle exceptions, you should simply use try...finally, and let the unhandled Exception bubble up.
I rethrow an exception with "throw;", but the stacktrace is incorrect:
static void Main(string[] args) {
try {
try {
throw new Exception("Test"); //Line 12
}
catch (Exception ex) {
throw; //Line 15
}
}
catch (Exception ex) {
System.Diagnostics.Debug.Write(ex.ToString());
}
Console.ReadKey();
}
The right stacktrace should be:
System.Exception: Test
at ConsoleApplication1.Program.Main(String[] args) in Program.cs:Line 12
But I get:
System.Exception: Test
at ConsoleApplication1.Program.Main(String[] args) in Program.cs:Line 15
But line 15 is the position of the "throw;". I have tested this with .NET 3.5.
Throwing twice in the same method is probably a special case - I've not been able to create a stack trace where different lines in the same method follow each other. As the word says, a "stack trace" shows you the stack frames that an exception traversed. And there is only one stack frame per method call!
If you throw from another method, throw; will not remove the entry for Foo(), as expected:
static void Main(string[] args)
{
try
{
Rethrower();
}
catch (Exception ex)
{
Console.Write(ex.ToString());
}
Console.ReadKey();
}
static void Rethrower()
{
try
{
Foo();
}
catch (Exception ex)
{
throw;
}
}
static void Foo()
{
throw new Exception("Test");
}
If you modify Rethrower() and replace throw; by throw ex;, the Foo() entry in the stack trace disappears. Again, that's the expected behavior.
It's something that can be considered as expected.
Modifying stack trace is usual case if you specify throw ex;, FxCop will than notify you that stack is modified. In case you make throw;, no warning is generated, but still, the trace will be modified.
So unfortunately for now it's the best not to catch the ex or throw it as an inner one.
I think it should be considered as a Windows impact or smth like that - edited.
Jeff Richter describes this situation in more detail in his "CLR via C#":
The following code throws the same
exception object that it caught and
causes the CLR to reset its starting
point for the exception:
private void SomeMethod() {
try { ... }
catch (Exception e) {
...
throw e; // CLR thinks this is where exception originated.
// FxCop reports this as an error
}
}
In contrast, if you re-throw an
exception object by using the throw
keyword by itself, the CLR doesn’t
reset the stack’s starting point. The
following code re-throws the same
exception object that it caught,
causing the CLR to not reset its
starting point for the exception:
private void SomeMethod() {
try { ... }
catch (Exception e) {
...
throw; // This has no effect on where the CLR thinks the exception
// originated. FxCop does NOT report this as an error
}
}
In fact, the only difference between
these two code fragments is what the
CLR thinks is the original location
where the exception was thrown.
Unfortunately, when you throw or
rethrow an exception, Windows does
reset the stack’s starting point. So
if the exception becomes unhandled,
the stack location that gets reported
to Windows Error Reporting is the
location of the last throw or
re-throw, even though the CLR knows
the stack location where the original
exception was thrown. This is
unfortunate because it makes debugging
applications that have failed in the
field much more difficult. Some
developers have found this so
intolerable that they have chosen a
different way to implement their code
to ensure that the stack trace truly
reflects the location where an
exception was originally thrown:
private void SomeMethod() {
Boolean trySucceeds = false;
try {
...
trySucceeds = true;
}
finally {
if (!trySucceeds) { /* catch code goes in here */ }
}
}
This is a well known limitation in the Windows version of the CLR. It uses Windows' built-in support for exception handling (SEH). Problem is, it is stack frame based and a method has only one stack frame. You can easily solve the problem by moving the inner try/catch block into another helper method, thus creating another stack frame. Another consequence of this limitation is that the JIT compiler won't inline any method that contains a try statement.
How can I preserve the REAL stacktrace?
You throw a new exception, and include the original exception as the inner exception.
but that's Ugly... Longer... Makes you choice the rigth exception to throw....
You are wrong about the ugly but right about the other two points. The rule of thumb is: don't catch unless you are going to do something with it, like wrap it, modify it, swallow it, or log it. If you decide to catch and then throw again, make sure you are doing something with it, otherwise just let it bubble up.
You may also be tempted to put a catch simply so you can breakpoint within the catch, but the Visual Studio debugger has enough options to make that practice unnecessary, try using first chance exceptions or conditional breakpoints instead.
Edit/Replace
The behavior is actually different, but subtilely so. As for why the behavior if different, I'll need to defer to a CLR expert.
EDIT: AlexD's answer seems to indicate that this is by design.
Throwing the exception in the same method that catches it confuses the situation a little, so let's throw an exception from another method:
class Program
{
static void Main(string[] args)
{
try
{
Throw();
}
catch (Exception ex)
{
throw ex;
}
}
public static void Throw()
{
int a = 0;
int b = 10 / a;
}
}
If throw; is used, the callstack is (line numbers replaced with code):
at Throw():line (int b = 10 / a;)
at Main():line (throw;) // This has been modified
If throw ex; is used, the callstack is:
at Main():line (throw ex;)
If exception is not caught, the callstack is:
at Throw():line (int b = 10 / a;)
at Main():line (Throw())
Tested in .NET 4 / VS 2010
There is a duplicate question here.
As I understand it - throw; is compiled into 'rethrow' MSIL instruction and it modifies the last frame of the stack-trace.
I would expect it to keep the original stack-trace and add the line where it has been re-thrown, but apparently there can only be one stack frame per method call.
Conclusion: avoid using throw; and wrap your exception in a new one on re-throwing - it's not ugly, it's best practice.
You can preserve stack trace using
ExceptionDispatchInfo.Capture(ex);
Here is code sample:
static void CallAndThrow()
{
throw new ApplicationException("Test app ex", new Exception("Test inner ex"));
}
static void Main(string[] args)
{
try
{
try
{
try
{
CallAndThrow();
}
catch (Exception ex)
{
var dispatchException = ExceptionDispatchInfo.Capture(ex);
// rollback tran, etc
dispatchException.Throw();
}
}
catch (Exception ex)
{
var dispatchException = ExceptionDispatchInfo.Capture(ex);
// other rollbacks
dispatchException.Throw();
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
Console.WriteLine(ex.InnerException.Message);
Console.WriteLine(ex.StackTrace);
}
Console.ReadLine();
}
The output will be something like:
Test app ex
Test inner ex
at TestApp.Program.CallAndThrow() in D:\Projects\TestApp\TestApp\Program.cs:line 19
at TestApp.Program.Main(String[] args) in D:\Projects\TestApp\TestApp\Program.cs:line 30
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at TestApp.Program.Main(String[] args) in D:\Projects\TestApp\TestApp\Program.cs:line 38
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at TestApp.Program.Main(String[] args) in D:\Projects\TestApp\TestApp\Program.cs:line 47
OK, there seems to be a bug in the .NET Framework, if you throw an exception, and rethrow it in the same method, the original line number is lost (it will be the last line of the method).
Fortunatelly, a clever guy named Fabrice MARGUERIE found a solution to this bug. Below is my version, which you can test in this .NET Fiddle.
private static void RethrowExceptionButPreserveStackTrace(Exception exception)
{
System.Reflection.MethodInfo preserveStackTrace = typeof(Exception).GetMethod("InternalPreserveStackTrace",
System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic);
preserveStackTrace.Invoke(exception, null);
throw exception;
}
Now catch the exception as usually, but instead of throw; just call this method, and voila, the original line number will be preserved!
Not sure whether this is by design, but I think it has always been like that.
If the original throw new Exception is in a separate method, then the result for throw should have the original method name and line number and then the line number in main where the exception is re-thrown.
If you use throw ex, then the result will just be the line in main where the exception is rethrow.
In other words, throw ex loses all the stacktrace, whereas throw preserves the stack trace history (ie details of the lower level methods). But if your exception is generated by the same method as your rethrow, then you can lose some information.
NB. If you write a very simple and small test program, the Framework can sometimes optimise things and change a method to be inline code which means the results may differ from a 'real' program.
Do you want your right line number? Just use one try/catch per method. In systems, well... just in the UI layer, not in logic or data access, this is very annoying, because if you need database transactions, well, they shouldn't be in the UI layer, and you won't have the right line number, but if you don't need them, don't rethrow with nor without an exception in catch...
5 minutes sample code:
Menu File -> New Project, place three buttons, and call the following code in each one:
private void button1_Click(object sender, EventArgs e)
{
try
{
Class1.testWithoutTC();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message + Environment.NewLine + ex.StackTrace + Environment.NewLine + Environment.NewLine + "In. Ex.: " + ex.InnerException);
}
}
private void button2_Click(object sender, EventArgs e)
{
try
{
Class1.testWithTC1();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message + Environment.NewLine + ex.StackTrace + Environment.NewLine + Environment.NewLine + "In. Ex.: " + ex.InnerException);
}
}
private void button3_Click(object sender, EventArgs e)
{
try
{
Class1.testWithTC2();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message + Environment.NewLine + ex.StackTrace + Environment.NewLine + Environment.NewLine + "In. Ex.: " + ex.InnerException);
}
}
Now, create a new Class:
class Class1
{
public int a;
public static void testWithoutTC()
{
Class1 obj = null;
obj.a = 1;
}
public static void testWithTC1()
{
try
{
Class1 obj = null;
obj.a = 1;
}
catch
{
throw;
}
}
public static void testWithTC2()
{
try
{
Class1 obj = null;
obj.a = 1;
}
catch (Exception ex)
{
throw ex;
}
}
}
Run... the first button is beautiful!
I think this is less a case of stack trace changing and more to do with the way the line number for the stack trace is determined. Trying it out in Visual Studio 2010, the behaviour is similar to what you would expect from the MSDN documentation: "throw ex;" rebuilds the stack trace from the point of this statement, "throw;" leaves the stack trace as it as, except that where ever the exception is rethrown, the line number is the location of the rethrow and not the call the exception came through.
So with "throw;" the method call tree is left unaltered, but the line numbers may change.
I've come across this a few times, and it may be by design and just not documented fully. I can understand why they may have done this as the rethrow location is very useful to know, and if your methods are simple enough the original source would usually be obvious anyway.
As many other people have said, it usually best to not catch the exception unless you really have to, and/or you are going to deal with it at that point.
Interesting side note: Visual Studio 2010 won't even let me build the code as presented in the question as it picks up the divide by zero error at compile time.
That is because you catched the Exception from Line 12 and have rethrown it on Line 15, so the Stack Trace takes it as cash, that the Exception was thrown from there.
To better handle exceptions, you should simply use try...finally, and let the unhandled Exception bubble up.