How to intercept an interface that inherits interfaces

Aug 31, 2012 at 7:06 PM

If I have an interface that inherits from many other interfaces, how do I setup an interceptor in configuration that intercepts all of the inheretied interfaces as well as the top-level interface.

For example:

interface A : { void FooA(); }
interface B : A { void FooB(); }

I want to setup an interceptor that will intercept both FooA and FooB.  The InterfaceInterceptor does not seem to work when I just set an interceptor on a registered type mapped to interface B.  If I switch over to a transparent proxy I still don't get FooA intercepted because its implemented in a base A class that my derivced B class inherits from.

Any advice here would be great.

Thanks!

Sep 1, 2012 at 8:16 AM

Can you expand on the scenario by posting the concrete classes A & B as well as the configuration being used?

This seems to work for me:

    public interface IA { void FooA(); }
    public interface IB : IA { void FooB(); }

    public class A 
    {
        public void FooA()
        {
        }
    }

    public class B : A, IB
    {
        public void FooB()
        {
        }
    }

    IUnityContainer container = new UnityContainer().LoadConfiguration();
    var b = container.Resolve<IB>();
    b.FooA();
    b.FooB();

<?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">
    <assembly name="InterfaceInterception"/>
    <namespace name="InterfaceInterception"/>
    <sectionExtension type="Microsoft.Practices.Unity.InterceptionExtension.Configuration.InterceptionConfigurationExtension, Microsoft.Practices.Unity.Interception.Configuration" />

    <container>
      <extension type="Interception"/>
      <register type="IB" mapTo="B">
        <interceptor type="InterfaceInterceptor"/>
        <interceptionBehavior type="CustomBehavior"/>
      </register>
    </container>
  </unity>

</configuration>

Thanks,

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

Sep 4, 2012 at 2:48 PM

Hi Randy,

Thanks.  I took your sample's and updated converted it to my approach and found that your approach works, and mine doesn't.  The difference in approaches is that I am using policy injections with a call handler, rather than an interception behavior.  What's strange is that I am using the same interceptor type (interface interceptor), just a different mechanism for applying an interceptor.

Here is the code:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Practices.Unity.InterceptionExtension;

namespace TestApp
{
    public interface IA { void FooA(); }
    public interface IB : IA { void FooB(); }

    public class A
    {
        public virtual void FooA()
        {
        }
    }

    public class B : A, IB
    {
        public void FooB()
        {
        }
    }

    public class LoggingInterceptor :
        ICallHandler,
        IInterceptionBehavior
    {
        public LoggingInterceptor()
        {
        }

        public bool WillExecute
        {
            get { return true; }
        }

        public int Order
        {
            get;
            set;
        }

        public System.Collections.Generic.IEnumerable<Type> GetRequiredInterfaces()
        {
            return new Type[0];
        }

        public IMethodReturn Invoke(IMethodInvocation input, GetNextInterceptionBehaviorDelegate getNext)
        {
            System.Diagnostics.Debug.WriteLine(input.MethodBase.Name);
            return getNext()(input, getNext);
        }

        public IMethodReturn Invoke(IMethodInvocation input, GetNextHandlerDelegate getNext)
        {
            System.Diagnostics.Debug.WriteLine(input.MethodBase.Name);
            return getNext()(input, getNext);
        }
    }
}

Here is the configuration file:
  <unity xmlns="http://schemas.microsoft.com/practices/2010/unity">
    <sectionExtension type="Microsoft.Practices.Unity.InterceptionExtension.Configuration.InterceptionConfigurationExtension, Microsoft.Practices.Unity.Interception.Configuration" />
    <container>
      <extension type="Interception"/>
      <interception>
        <policy name="Policy">
          <matchingRule name="Match" type="NamespaceMatchingRule">
            <constructor>
              <param name="namespaceName" value="TestApp" />
            </constructor>
          </matchingRule>
          <callHandler name="LogHandler" type="LoggingInterceptor" />
        </policy>
      </interception>
      <register type="IB" mapTo="B">
        <interceptor type="InterfaceInterceptor"/>
        <!--<interceptionBehavior type="LoggingInterceptor"/>-->  <!--Works-->
        <policyInjection /> <!--Doesn't Work-->
      </register>
    </container>
    <assembly name="TestApp" />
    <namespace name="TestApp" />
  </unity>
Let me know what you think.
Thanks!
Sep 4, 2012 at 3:48 PM

It seems to be working OK for me; is it possible that the namespace matching rule is not succeeding?

Here is my entire program using a CallHandler (with no behavior):

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Practices.Unity.InterceptionExtension;
using Microsoft.Practices.Unity;
using Microsoft.Practices.Unity.Configuration;
using System.Reflection;

namespace UnityContainerExtensionInterfaceInterception
{
    public interface IA { void FooA(); }
    public interface IB : IA { void FooB(); }

    public class A
    {
        public virtual void FooA() { }
    }

    public class B : A, IB
    {
        public void FooB() { }
    }

    public class LoggingInterceptor : ICallHandler
    {
        IMethodReturn ICallHandler.Invoke(IMethodInvocation input, GetNextHandlerDelegate getNext)
        {
            System.Diagnostics.Debug.WriteLine(input.MethodBase.Name);
            return getNext()(input, getNext);
        }

        int ICallHandler.Order { get; set; }
    }

    class Program
    {
        static void Main(string[] args)
        {
            IUnityContainer container = new UnityContainer().LoadConfiguration();
            var b = container.Resolve<IB>();
            b.FooA();
            b.FooB();
        }
    }
}

<?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">
    
    <assembly name="UnityContainerExtensionInterfaceInterception"/>
    <namespace name="UnityContainerExtensionInterfaceInterception"/>

    <sectionExtension type="Microsoft.Practices.Unity.InterceptionExtension.Configuration.InterceptionConfigurationExtension, Microsoft.Practices.Unity.Interception.Configuration" />

    <container>
      <extension type="Interception"/>
      
      <interception>
        <policy name="Policy">
          <matchingRule name="Match" type="NamespaceMatchingRule">
            <constructor>
              <param name="namespaceName" value="UnityContainerExtensionInterfaceInterception" />
            </constructor>
          </matchingRule>
          <callHandler name="LogHandler" type="LoggingInterceptor" />
        </policy>
      </interception>
      
      <register type="IB" mapTo="B">
        <interceptor type="InterfaceInterceptor"/>
        <policyInjection />
      </register>
    
    </container>
  </unity>

</configuration>

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

Sep 4, 2012 at 4:10 PM

Just to sanity check here.  You're getting the following output?

Debug Output
FooA
FooB  <-- This is all I get with the call handler.

Thanks.

Sep 4, 2012 at 5:02 PM
Edited Sep 4, 2012 at 5:02 PM

Yes, I see:

FooA
FooB

I'm using Unity 2.1.505.0 with .NET Framework 4 Client Profile.

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

Sep 4, 2012 at 6:17 PM

Thanks.  I am currently using Unity 2.0.414.0.  Will try updating to 2.1 and seeing if that fixes the issue.

Sep 4, 2012 at 6:20 PM

Updating to 2.1 resolved my issue.

Thanks!