1
votes

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 ?

1

1 Answers

2
votes

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).