Why is Ninject Bind with Interception returning an interface proxy?

1.8k Views Asked by At

I'm trying to understand how Ninject.Extensions.Interception 3.0.0.8 is building dynamic proxies for my classes. I've found that when I decorate my concrete classes with an attribute that inherits from InterceptAttribute or when I directly Intercept at binding time with Intercept() method then Ninject returns a Dynamic Proxy of the decorated class instead of the normal type.

I have a IPolicySearchPresenter interface which I'm binding to FlexPolicySearchPresenter concrete type adding an Exception logger interceptor:

Bind<IExceptionInterceptor>().To<ExceptionInterceptor>();
Bind<IPolicySearchPresenter>().To<FlexPolicySearchPresenter>().Intercept().With<IExceptionInterceptor>();

The problem is that when I inspect the returning type for that binding:

var proxy = Kernel.Get<IPolicySearchPresenter>();

I get an instance of Castle.Proxies.IPolicySearchPresenterProxy instead of FlexPolicySearchPresenterProxy

This is giving me problems with my FluorineFx remoting app. However, if I create my Castle Proxy manually:

ProxyGenerator generator = new ProxyGenerator();
    //My presenter type
    Type type = typeof(FlexPolicySearchPresenter);
    //My presenter interface
    var interfaceType = type.GetInterfaces().Single();
    //Get my Interceptor from container. Notice that i had to 
    //change my Interceptor to implement IInterceptor from Castle libs,
    // instead of Ninject IInterceptor
    var excepInt = Kernel.Get<ExceptionInterceptor>();
    //Manually get all my instances required by my presenter type Constructor
    //ideally passed through Constructor Injection
    var presenterSearchService = Kernel.Get<IPolicySearchService>();
    var userAuthService = Kernel.Get<IUserAuthorizationService>();
    //Create proxy, passing interceptor(s) and constructor arguments
    var proxy = generator.CreateClassProxy(type, new object[] { presenterSearchService, userAuthService },
            new IInterceptor[]
        {
            excepInt
        });
    //Ninject.Extensions.Interception.DynamicProxyModule
    // I'm using directive ToConstant(..), and not To(..)
    //Bind my interface to the new proxy
    Bind(interfaceType).ToConstant(proxy).InThreadScope();

var proxy = Kernel.Get<IPolicySearchPresenter>();

The returning types come back as Castle.Proxies.FlexPolicySearchPresenterProxy which work perfectly with my remoting implementation.

The question is, how can I get Ninject.Interception return me instances of FlexPolicySearchPresenterProxy instead of IPolicySearchPresenterProxy. Notice that by doing the manual Castle way I am binding in a different way:

        Bind(interfaceType).ToConstant(proxy).InThreadScope();

Instead of the ninject way:

Bind<IPolicySearchPresenter>().To<FlexPolicySearchPresenter>().Intercept().With<IExceptionInterceptor>();

Do I need to change the way I'm doing the Binding in Ninject to get the right type?

1

There are 1 best solutions below

5
BatteryBackupUnit On

Edit: added property injection to Foo.

I've got a working solution for you, but to be honest, i'm not 100% happy about it. Anyway, this works:

class Program
{
    static void Main(string[] args)
    {
        var kernel = new StandardKernel();
        kernel.Bind<IFoo>().ToMethod(ctx => ctx.Kernel.Get<Foo>());

        kernel.Bind<Foo>().ToSelf().Intercept().With<SomeInterceptor>();

        var foo = kernel.Get<IFoo>();

        foo.DoSomething();

        Console.WriteLine(foo.GetType());

        Console.Read();
    }
}

public interface IFoo
{
    void DoSomething();
}

public class Foo : IFoo
{
    [Inject]
    public Bar Dependency { get; set; }

    public virtual void DoSomething()
    {
        Console.WriteLine("doing something with {0}", this.Dependency);
    }
}

public class SomeInterceptor : IInterceptor
{
    public SomeInterceptor()
    {
        Console.WriteLine("interceptor created");
    }

    public void Intercept(IInvocation invocation)
    {
        Console.WriteLine("before");
        invocation.Proceed();
        Console.WriteLine("after");
    }
}

public class Bar
{
    public override string ToString()
    {
        return "Bar (injected dependency)";
    }
}

The resulting output is:

interceptor created
before
doing something with Bar (injected dependency)
after

And the type is:

Castle.Proxies.FooProxy

It seems that .Bind().To() and .Bind().ToSelf().Intercept... do not have the same result. I don't know why (yet) - but maybe i'm going to investigate it.

Update on constructor arguments: Ninject by itself only supports "inheritance based class proxy" - where the class needs a default / empty ctor and "interface proxy without target" - which is what you don't want.

Therefore, would it be acceptable for you to use property injection "just this once"? Otherwise you will need to create your own interception ninject-magic and use "class proxy with target" (see http://docs.castleproject.org/Tools.Kinds-of-proxy-objects.ashx) Remark: Even though "class proxy with target" supports constructor arguments you need to know which they are beforehand (so no easy DI support). (I did not find a hook for resolving constructor arguments after dynamic proxy chooses/creates the constructor for the proxy.)