【问题标题】:Why is Ninject Bind with Interception returning an interface proxy?为什么 Ninject Bind with Interception 返回接口代理?
【发布时间】:2013-10-21 04:58:22
【问题描述】:

我试图了解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 远程处理应用程序带来了问题。但是,如果我手动创建我的 Castle 代理:

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 中进行绑定的方式才能获得正确的类型?

【问题讨论】:

  • 您是否尝试过创建从 IPolicy.. 到 FlexPolicy and 的绑定,然后绑定 FlexPolicy .ToSelf().Intercept().With... ? (旁注:ninject instanciaties 拦截器每个类型一次,而不是每个代理实例一次)。
  • 不,我没试过。今天早上我会试一试。感谢您的建议
  • 我这样做了:Bind&lt;IPolicySearchPresenter&gt;().To&lt;FlexPolicySearchPresenter&gt;(); Bind&lt;FlexPolicySearchPresenter&gt;().ToSelf().Intercept().With&lt;IExceptionInterceptor&gt;(); var proxy = Kernel.Get&lt;IPolicySearchPresenter&gt;(); 但是代理返回为 FlexPolicySearchPresenter 类型而不是 FlexPolicySearchPresenterProxy 并且拦截没有启动:(
  • 奇怪。 @FlexPolicySearchPresenter 有没有虚方法?顺便说一句,这里是动态代理实例化的 ninject 扩展代码:github.com/ninject/ninject.extensions.interception/blob/master/…(注意 if(targetType.IsInterface))
  • 是的,我的演示者中有一个虚拟方法,我在其中抛出异常,以便我的拦截器管理它。我从 NuGet 下载了我正在使用的版本的 Ninject.Extensions.Interception 源代码,但无法将调试器附加到它,这将使事情变得更加清晰......

标签: c# ninject fluorinefx ninject-interception


【解决方案1】:

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

我为你找到了一个可行的解决方案,但老实说,我对此并不是 100% 满意。无论如何,这行得通:

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().Intercept... 没有相同的结果。我不知道为什么(现在)——但也许我会调查一下。

构造函数参数更新: Ninject 本身仅支持“基于继承的类代理”——类需要默认/空 ctor 和“没有目标的接口代理”——这是你不想要的。

因此,您是否可以接受“仅此一次”使用属性注入? 否则,您将需要创建自己的拦截 ninject-magic 并使用“带目标的类代理”(请参阅​​http://docs.castleproject.org/Tools.Kinds-of-proxy-objects.ashx备注:即使“带目标的类代理”支持构造函数参数,您也需要事先知道它们是什么(因此没有简单的 DI 支持)。 (在动态代理为代理选择/创建构造函数后,我没有找到用于解析构造函数参数的钩子。)

【讨论】:

  • 我会在我的 Visual Studio 恢复正常后立即尝试。感谢您的帮助!
  • 对我不起作用。我收到此错误:“找不到无参数构造函数。”我的 FlexPolicySearchPresenter 有点复杂,有构造函数注入:public FlexPolicySearchPresenter(IPolicySearchService policySearchServiceService, IUserAuthorizationService iUserAuthorizationService) : base(iUserAuthorizationService) { _policySearchService = policySearchServiceService; }
  • 是的,它来自 Castle.DynamicProxy:在 Castle.DynamicProxy.ProxyGenerator.CreateClassProxyInstance(Type proxyType, List`1 proxyArguments, Type classToProxy, Object[] constructorArguments) at Castle.DynamicProxy.ProxyGenerator.CreateClassProxy(在 Castle.DynamicProxy.ProxyGenerator.CreateClassProxy(Type classToProxy, ProxyGenerationOptions options, Object[] constructorArguments, IInterceptor[] 拦截器) 处键入 classToProxy, Type[] additionalInterfacesToProxy, ProxyGenerationOptions options, Object[] constructorArguments, IInterceptor[] 拦截器)
  • 有关“空构造函数”问题的更多详细信息,请参阅更新答案的底部。
  • 感谢@BatteryBackupUnit。在这一点上,我不认为属性注入是一种选择,我们正试图远离它。我通过 Castle 库手动创建类代理的方式目前运行良好。但我想通过 Ninject 扩展包装器来完成这项工作。
猜你喜欢
  • 2012-01-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-09-18
  • 2017-08-08
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多