当绑定到多个接口时,防止Ninject多次调用Initialize

当绑定到多个接口时,防止Ninject多次调用Initialize,ninject,Ninject,我们有一个具体的单例服务,它实现了Ninject.IInitializable和2个接口。问题是,当只需要一个服务时,服务会被调用两次。我们正在使用.NET3.5和Ninject 2.0.0.0 Ninject中是否有防止这种情况发生的模式。这两个接口都没有实现Ninject.IInitializable。服务类别为: public class ConcreteService : IService1, IService2, Ninject.IInitializable { public

我们有一个具体的单例服务,它实现了
Ninject.IInitializable
和2个接口。问题是,当只需要一个服务时,服务会被调用两次。我们正在使用.NET3.5和Ninject 2.0.0.0

Ninject中是否有防止这种情况发生的模式。这两个接口都没有实现
Ninject.IInitializable
。服务类别为:

public class ConcreteService : IService1, IService2, Ninject.IInitializable
{
    public void Initialize()
    {
        // This is called twice!
    }
}
模块如下所示:

public class ServiceModule : NinjectModule
{
    public override void Load()
    {
        this.Singleton<Iservice1, Iservice2, ConcreteService>();
    }
}
    public static void Singleton<K, T>(this NinjectModule module) where T : K
    {
        module.Bind<K>().To<T>().InSingletonScope();
    }

    public static void Singleton<K, L, T>(this NinjectModule module) 
        where T : K, L
    {
        Singleton<K, T>(module);
        module.Bind<L>().ToMethod(n => n.Kernel.Get<T>());
    }
公共类服务模块:Ninject模块
{
公共覆盖无效负载()
{
这个。Singleton();
}
}
其中Singleton是这样定义的扩展方法:

public class ServiceModule : NinjectModule
{
    public override void Load()
    {
        this.Singleton<Iservice1, Iservice2, ConcreteService>();
    }
}
    public static void Singleton<K, T>(this NinjectModule module) where T : K
    {
        module.Bind<K>().To<T>().InSingletonScope();
    }

    public static void Singleton<K, L, T>(this NinjectModule module) 
        where T : K, L
    {
        Singleton<K, T>(module);
        module.Bind<L>().ToMethod(n => n.Kernel.Get<T>());
    }
publicstaticvoidsingleton(这个模块),其中T:K
{
module.Bind().To().InSingletonScope();
}
公共静态void单例(此模块)
其中T:K,L
{
单件(模块);
module.Bind().ToMethod(n=>n.Kernel.Get());
}
当然,我们可以将bool initialized成员添加到ConcreteService中,并仅在它为false时进行初始化,但这似乎有点像黑客。而且它需要在实现两个或多个接口的每个服务中重复相同的逻辑


谢谢你的回答!我从他们身上学到了一些东西!(我很难决定哪一个分数正确)


我们最终创建了IActivable接口并扩展了ninject内核(它还很好地消除了对ninject的代码级依赖,尽管属性仍然存在)

更新:非常确定使用将解决这个问题;看


好问题

从源代码看,初始化位发生在每次
激活之后。您的
Bind…ToMethod
也算作一个。该策略的应用相当一致——在特定情况下无法选择退出

您的解决方案是在
Bind
中使用显式的
OnActivation
,它将有条件地执行此操作(但以一般方式执行此操作将需要维护一组初始化对象(未查看是否有针对激活对象隐藏标志的机制)),或者通过任何对你来说最干净的方法使你的初始化幂等元

编辑:


我认为其中一个选项是,在模块中创建自己的对象,并将对象绑定到每个接口

顺便说一句,尽量不要在生产代码中使用任何特定于容器的代码。如果必须这样做,请使用一些辅助工具并在模块项目中隔离它们

public class ServiceModule : NinjectModule
{

    public override void Load()
    { 
         ConcreteService svc = new ConcreteService();
         Bind<IService1>().ToConstant(svc);
         Bind<IService2>().ToConstant(svc);
         ....
     }
}
公共类服务模块:Ninject模块
{
公共覆盖无效负载()
{ 
ConcreteService svc=新的ConcreteService();
Bind().ToConstant(svc);
Bind().ToConstant(svc);
....
}
}
Ninject 3 Ninject 3.0现在在对bind的调用中支持多种泛型类型,您试图做的事情可以在一个链式语句中轻松完成

kernel.Bind<IService1, IService2>()
      .To<ConcreteService>()
      .InSingletonScope();
kernel.Bind()
.至()
.InSingletonScope();
Ninject 2 您正在设置两个不同的绑定K=>T和L=>T。请求L的实例将返回T的瞬态实例。请求K将返回T的单个实例

在Ninject 2.0中,对象范围是绑定到范围回调的每个服务接口

当你有

Bind<IFoo>...InSingletonScope();
Bind<IBar>...InSingletonScope();
Bind…InSingletonScope();
绑定…InSingletonScope();
您正在创建两个不同的作用域

你是说 “绑定到IFoo将解析为返回的同一对象 什么时候打电话来的。” 和 “绑定到IBar将解析为返回的同一对象 什么时候打电话来的。”

您可以将绑定链接在一起,但需要删除IInitializable,因为激活实例时会导致重复初始化:

kernel.Bind<IBoo>()
      .To<Foo>()
      .InSingletonScope();
      .OnActivation(instance=>instance.Initialize());

kernel.Bind<IBaz>()
      .ToMethod( ctx => (IBaz) ctx.Kernel.Get<IBoo>() );
kernel.Bind()
.至()
.InSingletonScope();
.OnActivation(instance=>instance.Initialize());
kernel.Bind()
.ToMethod(ctx=>(IBaz)ctx.Kernel.Get());

kernel.Bind()
.OnActivation(instance=>instance.Initialize());
kernel.Bind().ToMethod(ctx=>ctx.kernel.Get());
kernel.Bind().ToMethod(ctx=>ctx.kernel.Get());

以便将多个接口解析为同一个单例实例。当我看到这样的情况时,我总是要问,如果你有一个有两个职责的单身汉,你的对象是否做得太多了?

行不通-问题是每次激活都会调用Ninject的
IInitialize
接口(即,作为
Bind
流的一部分创建)。您的示例归结为与问题相同的事情,因此也会初始化两次。我要说的是,实现IIInitialize完全没有必要,而且是一种糟糕的做法-如果有一天您必须切换到另一个容器,您的代码需要更改,您必须记住它是由容器初始化的,如果您忘记了这一点,只是删除了接口以使其可编译,那么您将遇到运行时问题。另一方面,如果一个“新”可以处理它,为什么要把它弄得这么复杂,不管怎样,容器是为了让代码更简单,而不是更难,而Moude的目的是构造对象,我自己并不介意“新”它。我同意你的一般看法(构造函数注入,没有容器细节泄漏到业务逻辑中等等)。我的关键点和-1的原因是a)你的代码与OP所说的不起作用的问题中的代码相同b)因此它不能回答或解决问题。IIInitializable的目的是促进两个阶段的构建,如果您必须重新排序以支持注入(例如,如果您的环境排除了构造函数注入),它将非常有用。但这些都是离题,与问题无关。IStartable是否会像Initializable一样被多次调用?(也许是吧
Bind<IFoo>...InSingletonScope();
Bind<IBar>...InSingletonScope();
kernel.Bind<IBoo>()
      .To<Foo>()
      .InSingletonScope();
      .OnActivation(instance=>instance.Initialize());

kernel.Bind<IBaz>()
      .ToMethod( ctx => (IBaz) ctx.Kernel.Get<IBoo>() );
kernel.Bind<Foo>().ToSelf().InSingletonScope()
    .OnActivation(instance=>instance.Initialize());
kernel.Bind<IBaz>().ToMethod( ctx => ctx.Kernel.Get<Foo>() );
kernel.Bind<IBoo>().ToMethod( ctx => ctx.Kernel.Get<Foo>() );