I have an application that uses Ninject for its DI. I'm adding some new classes and they are not being resolved the way I think they should be.
I have a class Foo
that implements an interface ISomething
. If I configure the bindings like this:
kernel.Bind<Foo>().ToSelf().InSingletonScope();
kernel.Bind<ISomething>().To<Foo>();
and then do:
var foo1 = kernel.Get<Foo>();
var foo2 = kernel.Get<ISomething>();
the two variables have different instances of the Foo
class.
If I change the binding to:
kernel.Bind<Foo>().ToSelf().InSingletonScope();
kernel.Bind<ISomething>().ToMethod(ctx => ctx.Kernel.Get<Foo>());
and then do:
var foo1 = kernel.Get<Foo>();
var foo2 = kernel.Get<ISomething>();
the two variables have the same instance.
My understanding is that in the first case it should resolve the ISomething
to Foo
, which will in turn resolve to the singleton of itself. Is my understanding incorrect, or is something else wrong? It seems a bit redundant to have to manually resolve it.
When you omit the lifestyle in the registration, by convention, Ninject uses the transient lifestyle. This means that this:
kernel.Bind<ISomething>().To<Foo>();
Is equivalent to:
kernel.Bind<ISomething>().To<Foo>().InTransientScope();
With the addition of the lifestyle, it becomes easier to spot the problem:
kernel.Bind<Foo>().ToSelf().InSingletonScope();
kernel.Bind<ISomething>().To<Foo>().InTransientScope();
Or even more clearly:
kernel.Bind<Foo>() .To<Foo>().InSingletonScope();
kernel.Bind<ISomething>().To<Foo>().InTransientScope();
Here you see that you are registering Foo
both as singleton and transient. This misconfiguration is a common pitfall called Ambiguous Lifestyles:
When multiple registrations with a different lifestyle map to the same component, the component is said to have ambiguous lifestyles. Having one single component with multiple lifestyles will cause instances of that component to be cached in different ways and this can lead to behavior that you might not expect.
Some DI Containers do contain verification mechanisms that you can use to detect this kind of misconfiguration, but all DI Containers that I'm familiar with do allow you to accidentally misconfigure the container this way.