Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using unity interception to solve exception handling as a crosscutting concern

I created my own behavior as follows:

public class BoundaryExceptionHandlingBehavior : IInterceptionBehavior
{


public IEnumerable<Type> GetRequiredInterfaces()
{
  return Type.EmptyTypes;
}

public IMethodReturn Invoke(IMethodInvocation input, GetNextInterceptionBehaviorDelegate getNext)
{
  try
  {
    return getNext()(input, getNext);
  }
  catch (Exception ex)
  {
    return null; //this would be something else...
  }
}

public bool WillExecute
{
  get { return true; }
}

}

I have it setup correctly so that my behavior gets hit as expected. However, if any exception happens in whatever getNext() does, it doesn't hit my catch block. Can anyone clarify why? I'm not really looking to solve the problem as there's many ways to deal with exceptions, it's more that I don't understand what's going on, and I'd like to.

like image 999
greyalien007 Avatar asked Mar 20 '12 03:03

greyalien007


3 Answers

You can't catch any exception, if an Exception occurs it will be part of the Exception property of IMethodReturn.

Like so:

public IMethodReturn Invoke(IMethodInvocation input,
                GetNextInterceptionBehaviorDelegate getNext)
{
   IMethodReturn ret = getNext()(input, getNext);
   if(ret.Exception != null)
   {//the method you intercepted caused an exception
    //check if it is really a method
    if (input.MethodBase.MemberType == MemberTypes.Method)
    {
       MethodInfo method = (MethodInfo)input.MethodBase;
       if (method.ReturnType == typeof(void))
       {//you should only return null if the method you intercept returns void
          return null;
       }
       //if the method is supposed to return a value type (like int) 
       //returning null causes an exception
    }
   }
  return ret;
}
like image 189
gideon Avatar answered Nov 02 '22 13:11

gideon


I think there is one more important point to make. Exception will not be handled and saved to IMethodReturn.Exception if it was thrown deeper within behaviors pipeline. Because Unity creates intercepted method wrapper, which is InvokeInterceptionBehaviorDelegate instance, by surrounding method invocation with try-catch block. But that is not the case for your interceptor method. You can check CreateDelegateImplementation() method and InterceptionBehaviorPipeline class to get more details about how this is done.

If you want to process exceptions that were thrown from other, deeper interceptors too you can use something like this:

public IMethodReturn Invoke(IMethodInvocation input,
                            GetNextInterceptionBehaviorDelegate getNext)
{
    try
    {
        return InvokeImpl(input, getNext);
    }
    catch (Exception exception)
    {
        // Process exception and return result
    }
}

private IMethodReturn InvokeImpl(IMethodInvocation input,
                                GetNextInterceptionBehaviorDelegate getNext)
{
    var methodReturn = getNext().Invoke(input, getNext);
    if (methodReturn.Exception != null)
        // Process exception and return result

    return methodReturn;
}
like image 24
Leonid Vasilev Avatar answered Nov 02 '22 13:11

Leonid Vasilev


I know it is an old post but the gideon's solution throw an Unity null reference Exception. And i want to handle the Exception in the caller and not in the Unity Interception.

Here is a working solution that throw the Exception on the caller and not into the Interception:

public IMethodReturn Invoke(IMethodInvocation input, GetNextInterceptionBehaviorDelegate getNext)
{
    IMethodReturn ret = getNext()(input, getNext);
    if (ret.Exception != null)
    {
        // Throw the Exception out of the Unity Interception
        ExceptionDispatchInfo.Capture(ret.Exception).Throw();
    }

    // Process return result
    return ret;
}

Then when you call your intercepted method you can get the Exception:

try
{
    // Method intercepted by Unity pipeline
    InterceptedMethod();
}
catch(Exception e)
{
    //Exception handling
}
like image 39
Ludovic Feltz Avatar answered Nov 02 '22 14:11

Ludovic Feltz