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).
Related
I've read How to rethrow InnerException without losing stack trace in C#? and the answer here may be the same; on the other hand my situation is sufficiently different that someone might be able to suggest a better approach.
My simplified structure is
try {
something();
} catch (MyException e1) {
try {
somethingElse();
} catch (MyException e2) {
throw e1;
}
}
That is to say, calling somethingElse() is an attempt to recover from the original exception, and if the recovery attempt fails, I want to throw the original exception, not the one that arose from the recovery attempt.
I get a warning from the compiler about rethrowing exceptions losing the stack trace (and of course, I don't like leaving my code with warning conditions). But what should I do about it? My IDE (Rider) suggests changing the throw e1; to throw;, but that would presumably rethrow e2.
Are there any solutions short of the convoluted ideas proposed in the cited question for inner exceptions?
To be honest, I don't really care about the imperfect stack trace - I just want to get rid of the warnings.
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;
}
}
There is the ExceptionDispatchInfo class.
This lets you capture an exception and re-throw it without changing the stack-trace:
public static void Method()
{
try
{
Something();
}
catch (MyException e1)
{
try
{
SomethingElse();
}
catch (MyException)
{
//throw e1;
ExceptionDispatchInfo.Capture(e1).Throw();
throw;
}
}
}
A regular throw; after the .Throw() line is because the compiler won't know that .Throw() always throws an exception. throw; will never be called as a result, but at least the compiler won't complain if your method requires a return object or is an async function.
Original post Link
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'm trying to log with Elmah exceptions handled in try...catch blocks.
I have added a global handle error filter on Global.axax:
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new ElmahHandledErrorLoggerFilter());
filters.Add(new HandleErrorAttribute());
}
This is my ElmahHandledErrorLoggerFilter:
public class ElmahHandledErrorLoggerFilter : IExceptionFilter
{
public void OnException(ExceptionContext context)
{
if (context.ExceptionHandled)
ErrorSignal.FromCurrentContext().Raise(context.Exception);
}
}
It will only log the Exception as in try{ ... }catch{ throw new Exception(); }. But that's not the problem, the problem is that I have a method with a try-catch called from the code already inside another try-catch. In this case although I put throw new Exception() inside the catch of the inner-method it doesn't log the exception, it goes back to the catch in the first method without logging the Exception. For example:
public void MainMethod()
{
try
{
SecondMethod();
}
catch
{
....second method jump here.....
}
}
public void SecondMethod()
{
try
{
int a =0;
int b =;
int result = b/a;
}
catch
{
throw new Exception();
}
}
The exception thrown by SecondMethod is not being logged by Elmah. It goes back to the main method catch. If the main method catch also has a throw new Exception() code then it logs the exception. However it will be logged with the stack trace pointing to MainMethod and not to the SecondMethod.
What I wanted what was that every time it reaches a catch without rethrowing a new Exception, Elmah would log the exception. This is because I have many try-catch blocks in my application and I want to log these exceptions without manually logging on each try-catch. However if you tell me how can I log the exception from SecondMethod that would be fine.
Are you using ASP MVC?
The filters will only execute for unhandled exceptions thrown from the controller methods. (The context.ExceptionHandled property tells you if it has been handled by another filter, not in a try-catch block). So if you swallow the exceptions in try-catch blocks inside your methods then they will not be handled by the error filters.
You need to decide when you want to manually handle the exceptions inside your code using try-catch blocks (and in that case manually log the exceptions with the aid of a base controller class or a helper class) or let the exception bubble and be handled by your filters. (You probably will want a mixture of the two, depending on each particular use case)
When you decide to rethrow the exceptions, take a look at this SO question. Basically you can rethrow an exception preserving the stack trace with:
try
{
//code
}
catch (Exception ex)
{
//...some error handling code here...
//Otherwise why the try-catch at all?
throw;
}
You could do that in your sample MainMethod and the exception logged would preserve the stack trace.
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)
What is the difference between
try { }
catch
{ throw; }
and
try { }
catch(Exception e)
{ throw e;}
?
And when should I use one or the other?
The constructions
try { ... }
catch () { ... } /* You can even omit the () here */
try { ... }
catch (Exception e) { ... }
are similar in that both will catch every exception thrown inside the try block (and, unless you are simply using this to log the exceptions, should be avoided). Now look at these:
try { ... }
catch ()
{
/* ... */
throw;
}
try { ... }
catch (Exception e)
{
/* ... */
throw;
}
try { ... }
catch (Exception e)
{
/* ... */
throw e;
}
The first and second try-catch blocks are EXACTLY the same thing, they simply rethrow the current exception, and that exception will keep its "source" and the stack trace.
The third try-catch block is different. When it throws the exception, it will change the source and the stack trace, so that it will appear that the exception has been thrown from this method, from that very line throw e on the method containing that try-catch block.
Which one should you use? It really depends on each case.
Let's say you have a Person class with a .Save() method that will persist it into a database. Let's say that your application executes the Person.Save() method somewhere. If your DB refuses to save the Person, then .Save() will throw an exception. Should you use throw or throw e in this case? Well, it depends.
What I prefer is doing:
try {
/* ... */
person.Save();
}
catch(DBException e) {
throw new InvalidPersonException(
"The person has an invalid state and could not be saved!",
e);
}
This should put the DBException as the "Inner Exception" of the newer exception being throw. So when you inspect this InvalidPersonException, the stack trace will contain info back to the Save method (that might be sufficient for you to solve the problem), but you still have access to the original exception if you need it.
As a final remark, when you are expecting an exception, you should really catch that one specific exception, and not a general Exception, ie, if you are expecting an InvalidPersonException you should prefer:
try { ... }
catch (InvalidPersonException e) { ... }
to
try { ... }
catch (Exception e) { ... }
The first preserves the stack trace while the second resets it. This means that if you use the second approach the stack trace of the exception will always start from this method and you will lose the original exception trace which could be disastrous for someone reading exception logs as he will never find out the original cause of the exception.
The second approach might be useful when you want to add additional information to the stack trace but it is used like this:
try
{
// do something
}
catch (Exception ex)
{
throw new Exception("Additional information...", ex);
}
There's a blog post discussing the differences.
You should use
try { }
catch(Exception e)
{ throw }
if you want to do something with the exception before re-throwing it (logging for example). The lonely throw preserves stack trace.
The difference between a parameterless catch and a catch(Exception e) is that you get a reference to the exception. From framework version 2 unmanaged exceptions are wrapped in a managed exception, so the parameterless exception is no longer useful for anything.
The difference between throw; and throw e; is that the first one is used to rethrow exceptions and the second one is used to throw a newly created exception. If you use the second one to rethrow an exception, it will treat it like a new exception and replace all stack information from where it was originally thrown.
So, you shold not use either of the alternatives in the question. You should not use the parameterless catch, and you should use throw; to rethrow an exception.
Also, in most cases you should use a more specific exception class than the base class for all exceptions. You should only catch the exceptions that you anticipate.
try {
...
} catch (IOException e) {
...
throw;
}
If you want to add any information when rethrowing the exception, you create a new exception with the original exception as an inner exception to preservere all information:
try {
...
} catch (IOException e) {
...
throw new ApplicationException("Some informative error message", e);
}