为什么Ninject与拦截绑定返回接口代理?

时间:2013-10-13 14:47:49

标签: c# ninject fluorinefx ninject-interception

我试图了解Ninject.Extensions.Interception 3.0.0.8如何为我的类构建动态代理。我发现当我使用继承自InterceptAttribute的属性装饰我的具体类时,或者当我在绑定时使用Intercept()方法直接截取时,Ninject会返回装饰类的动态代理而不是正常类型。

我有一个IPolicySearchPresenter接口,我绑定到FlexPolicySearchPresenter具体类型,添加了一个异常记录器拦截器:

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

问题是当我检查该绑定的返回类型时:

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

我得到Castle.Proxies.IPolicySearchPresenterProxy而不是FlexPolicySearchPresenterProxy

的实例

这使我的FluorineFx远程应用程序出现问题。但是,如果我手动创建城堡代理:

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>();

返回的类型返回Castle.Proxies.FlexPolicySearchPresenterProxy,与我的远程实现完美配合。

问题是,如何让Ninject.Interception返回FlexPolicySearchPresenterProxy而不是IPolicySearchPresenterProxy的实例。 请注意,通过手动Castle方式,我以不同的方式绑定:

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

而不是ninject方式:

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

我是否需要更改我在Ninject中进行绑定的方式以获得正确的类型?

1 个答案:

答案 0 :(得分:1)

编辑:向Foo添加了属性注入。

我为你找到了一个有效的解决方案,但说实话,我并不是百分之百。无论如何,这有效:

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)";
    }
}

结果输出为:

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

类型是:

Castle.Proxies.FooProxy

似乎.Bind()。To() .Bind()。ToSelf()。拦截......没有相同的结果。我不知道为什么(还) - 但也许我会调查它。

构造函数参数更新: Ninject本身只支持&#34;基于继承的类代理&#34; - 类需要默认/空ctor和&#34;接口代理而没有目标&#34; - 这是你不想要的。

因此,您可以接受使用属性注入&#34;只需这一次&#34 ;? 否则你需要创建自己的拦截ninject-magic并使用&#34;类代理与目标&#34; (见http://docs.castleproject.org/Tools.Kinds-of-proxy-objects.ashx备注:即使&#34;类代理与目标&#34;支持你需要知道它们之前的构造函数参数(所以没有简单的DI支持)。 (在动态代理选择/创建代理的构造函数之后,我没有找到用于解析构造函数参数的钩子。)