Intercepting subordinate Method calls from registered calling class

Nov 20, 2012 at 6:11 PM

Building on How to intercept an interface that inherits interfaces

I have a question on how to implement the interception onto self instantiated objects (and method calls).

For instance: I have Registered class A.FooA and class C.FooC.

C.FooC() instantiates its' own A and calls FooA, it also calls another local method FooCa; however neither are being intercepted....

In C.FooC, I want what it calls to be intercepted:

    public class C : IC

    {
        public virtual void FooCa()
        {
        }
        public virtual void FooC() 
        {
            FooCa(); //how do I configure the app to allow this to be intercepted
            IA a = new A();
            a.FooA();//and how do I configure the app to allow this to be intercepted
        }
    }

How can I intercept FooC call of FooCa & A.FooA?

Please advise, thanks in advance.

 

this is probably an easy one, below I've included the entire use-case:

Here is the XML

<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="ConsoleApplication2"/>
    <namespace name="ConsoleApplication2"/>

    <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="ConsoleApplication2" />
            </constructor>
          </matchingRule>
          <callHandler name="LogHandler" type="LoggingInterceptor" />
        </policy>
      </interception>
      
      <register type="IB" mapTo="B">
        <interceptor type="InterfaceInterceptor"/>
        <policyInjection />
        <addInterface type="IA"/>
      </register>
      
      <register type="IA" mapTo="A">
        <interceptor type="InterfaceInterceptor"/>
        <policyInjection />
      </register>

      <register type="IC" mapTo="C">
        <interceptor type="InterfaceInterceptor"/>
        <policyInjection />
        <addInterface type="IA"/>
      </register>

    </container>
  </unity>

</configuration>

And here is the Code:

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 ConsoleApplication2
{
    public interface IA { void FooA(); }
    public interface IB : IA { void FooB(); }
    public interface IC { void FooC(); void FooCa();}

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

    public class B : A, IB
    {
        public virtual void FooB() { base.FooA(); }
    }


    public class C : IC
    {
        public virtual void FooCa()
        {
        }
        public virtual void FooC() 
        {
            FooCa(); //how do I configure the app to allow this to be intercepted
            IA a = new A();
            a.FooA();//and how do I configure the app to allow this to be intercepted
        }
    }
    public class LoggingInterceptor : ICallHandler
    {
        IMethodReturn ICallHandler.Invoke(IMethodInvocation input, GetNextHandlerDelegate getNext)
        {
            Console.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>();
            var c = container.Resolve<IC>();
            b.FooA();
            b.FooB();
            c.FooC(); //how do I get FooC to have its' children (FooCa and the A.FooA call intercepted?)
            Console.ReadKey();
        }
    }
}

Nov 21, 2012 at 1:55 AM

Thanks for posting a thorough question complete with code and configuration -- it makes getting answers much easier & faster.

To sum up, you have two questions:

  • How to configure the app to allow the self-call FooCa() to be intercepted
  • How to configure the app to allow a.FooA() to be intercepted

In answer to the first question let me do a bit of exposition.  There are 3 interceptors in Unity: InterfaceInterceptor, TransparentProxyInterceptor, and VirtualMethodInterceptor.  The first 2 are instance interceptors while the latter is a type interceptor.  The main difference between the 2 approaches is that instance interceptors generate a proxy class to access the intercepted instance while type interceptors create a type that derives from the intercepted type.  Because instance interceptors act via a proxy class they cannot intercept self-calls.  However, since a type interceptor creates a new type it *can* intercept self-calls.

All of this is a long winded way of saying that to intercept self-calls you should use the VirtualMethodInterceptor.  The configuration would then look like:

      <register type="IC" mapTo="C">
        <interceptor type="VirtualMethodInterceptor"/>
        <policyInjection />
      </register>

In answer to the second question, you will not be able to intercept any methods on an object that was directly "newed-up".  You need to get the container involved.  (I assume that is what you were trying to do with addInterface.)  One way would be to pass the container into the object "C" or use a singleton to access the container and resolve the "A" instance.  This is using the container as a service locator which is considered an anti-pattern.  Since your object needs to use IA it has a dependency on IA so IA should be injected into C.  If A requires some data to be set only when FooC() is called then you could inject a factory or a Func<>.

So C will now look something like that:

    public class C : IC
    {
        private Func<IA> getA;

        public C(Func<IA> getA)
        {
            this.getA = getA;
        }

        public virtual void FooCa()
        {
        }
        public virtual void FooC()
        {
            FooCa(); // intercepted via VirtualMethodInterceptor
            IA a = getA();
            a.FooA(); //now FooA is intercepted 
        }
    }

And just configure the container:

      <register type="IA" mapTo="A">
        <interceptor type="InterfaceInterceptor"/>
        <policyInjection />
      </register>

      <register type="IC" mapTo="C">
        <interceptor type="VirtualMethodInterceptor"/>
        <policyInjection />
      </register>

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

Nov 21, 2012 at 12:54 PM

Thank you for the fantastic solution and the 'why' as well (teach a man to fish eh?).  this is, without doubt, the best answer I have ever received in an on-line forum!  Thanks!

Nov 22, 2012 at 5:46 AM

Thanks for the kind words -- they're very appreciated!

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