How to swallow Exception by IInterceptionBehavior?

Oct 27, 2011 at 8:31 AM

I have a IInterceptionBehavior like blow:

public class TraceBehavior : IInterceptionBehavior
    {
        public IEnumerable<Type> GetRequiredInterfaces()
        {
            return Type.EmptyTypes;
        }

        public IMethodReturn Invoke(IMethodInvocation input, GetNextInterceptionBehaviorDelegate getNext)
        {
            Console.WriteLine(string.Format("Invoke method:{0}",input.MethodBase.ToString()));
            IMethodReturn result = getNext()(input, getNext);
            if (result.Exception == null)
            {
                Console.WriteLine("Invoke successful!");
            }
            else 
            {
                Console.WriteLine(string.Format("Invoke faild, error: {0}", result.Exception.Message));
                result.Exception = null;
            }
            return result;
        }

        public bool WillExecute { get { return true; } }
    }

 

Whether I put it on method or not, exception throw always. Anyone can help me?

Oct 30, 2011 at 1:48 AM

What exception are you getting?  Can you post how you register the interceptor?

It seems to work fine in this example:

public interface ISpeak
{
    void Speak();
}

public class Dog : ISpeak
{
    public void Speak()
    {
        Console.WriteLine("WOOF!");
    }
}

class Program
{
    static void Main(string[] args)
    {
        IUnityContainer container = new UnityContainer();
        container.AddNewExtension<Interception>();

        container.RegisterType<ISpeak, Dog>(
            "",    
            new Interceptor(new InterfaceInterceptor()),
            new InterceptionBehavior(new TraceBehavior())
            );

        var speaker = container.Resolve<ISpeak>();

        speaker.Speak();
    }
}

--
Randy Levy
Enterprise Library support engineer
entlib.support@live.com

Nov 2, 2011 at 9:24 AM
Edited Nov 2, 2011 at 9:24 AM
static void Main(string[] args)
{
      IUnityContainer container = new UnityContainer();
      UnityConfigurationSection section = (UnityConfigurationSection)ConfigurationManager.GetSection("unity");
      section.Configure(container,"ContainerOne");

      ICalc calc = container.Resolve<ICalc>();
      calc.Add(1,1);
      calc.Divide(2,0);
}
<containers>
  <container name="ContainerOne">
    <extension type="Interception" />
    <register type="ICalc" mapTo="Calc">
      <interceptor type="InterfaceInterceptor" />
      <interceptionBehavior type="BehaviorInterception.AOP.TraceBehavior,BehaviorInterception" />
    </register>
  </container>
</containers>
public class Calc:ICalc
{
    public int Add(int oprandA, int oprandB)
    {
        return oprandA + oprandB;
    }

    public int Divide(int dividend, int divisor)
    {
         return dividend / divisor;
    }
}
Nov 4, 2011 at 2:43 AM

I think your configuration is not working as intended.  Try this:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <configSections>
    <section name="unity"
        type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection, Microsoft.Practices.Unity.Configuration"/>
  </configSections>
  <unity xmlns="http://schemas.microsoft.com/practices/2010/unity">
    <alias alias="ICalc" type="IInterception.ICalc, IInterception" />
    <alias alias="Calc" type="IInterception.Calc, IInterception" />
    <sectionExtension type="Microsoft.Practices.Unity.InterceptionExtension.Configuration.InterceptionConfigurationExtension, Microsoft.Practices.Unity.Interception.Configuration"/>
    <container name="ContainerOne">
      <extension type="Interception" />
      <register type="ICalc" mapTo="Calc">
        <interceptor type="InterfaceInterceptor"/>
        <interceptionBehavior type="IInterception.TraceBehavior, IInterception" />
      </register>
    </container>
  </unity>
</configuration>

 

N.b. in this case the assembly is called IInterception -- replace with your assembly information.

--
Randy Levy
Enterprise Library support engineer
entlib.support@live.com

Nov 7, 2011 at 11:36 AM

My demo can run as expect, and your configuration just replace name of assembly(or namespace).

I'm focus on why it throw exception even though I set result.Exception=null manually.

Nov 7, 2011 at 11:41 AM

Someone on stackoverflow.com gave me an answer:

"That's not how it works. Don't set result.Exception, instead return input.CreateMethodReturn(newReturnValues)."

Is't right? However, I have tried this , not effect.

Nov 8, 2011 at 1:26 AM
Edited Nov 10, 2011 at 1:57 AM

The issue is that the Divide method is returning an int but you are handling the exception and not setting a return value so the result.ReturnValue is null.  

You can't return a null return value for a value type (such as an int).  (A NullReferenceException is being thrown by what looks to be generated Unity code.)

If you want to prove it to yourself change your interface to return a reference type (such as string):

    public interface ICalc
    {
        int Add(int oprandA, int oprandB);
        string Divide(int dividend, int divisor);
    }

    public class Calc : ICalc
    {
        public int Add(int oprandA, int oprandB)
        {
            return oprandA + oprandB;
        }

        public string Divide(int dividend, int divisor)
        {
            return (dividend / divisor).ToString();
        }
    }

If you run this code then the exception will be swallowed and null returned.

You could create a new method return but what will the default value be?  If it's null then you are in the same situation.  
One way to avoid returning null is to return the default value for the type in question:

result.Exception = null;
Type type = ((MethodInfo)input.MethodBase).ReturnType;

if (type.IsValueType)
{
    result.ReturnValue = Activator.CreateInstance(type);
}

If you add that code to the TraceBehavior then you will avoid the exception being thrown.

Also, it's usually not a good idea to swallow exceptions.   Especially exceptions thrown from the target method.  I can see swallowing exceptions that occur in the course
of performing the interception.  For example if the interception is performing logging and the logging fails then you might want to swallow it so the application can continue even though
the logging failed -- this is what Enterprise Library does.

--
Randy Levy
Enterprise Library support engineer
entlib.support@live.com

Nov 10, 2011 at 12:21 AM

A very nice answer, thanks!

Feb 20, 2012 at 5:35 AM

Try using 

IMethodReturn result = getNext().Invoke(input, getNext);
instead of
IMethodReturn result = getNext()(input, getNext);