Reputation: 9609
Let's say I have the following classes that I want to construct using Ninject, with the arrows showing dependencies.
A > B > D
A > C > D
I want to configure Ninject such that A is transient scoped, i.e. every time you ask Ninject for an A, you get a new one. I also want B and C to be transient, you get a new one of those every time you ask for an A. But I want the D to be reused across both B and C. So every time I request an A, I want Ninject to construct one of each object, not two Ds. But I don't want Ds to be reused across different As.
What is the best way to set this up using Ninject?
Update:
After some more research, it seems like Unity has a PerResolveLifetimeManager which does what I'm looking for. Is there a Ninject equivalent?
Upvotes: 15
Views: 3756
Reputation: 139798
Ninject supports four built in object scopes out of the box: Transient, Singleton, Thread, Request.
So there isn't any PerResolveLifetimeManager
like scope but you can implement it easily with registering a custom scope with the InScope
method.
As it turned out there is an existing Ninject extension: ninject.extensions.namedscope
which provides the InCallScope
method which is what you are looking for.
However if you want to do it yourself you can do with a custom InScope
delegate. Where you can use the main IRequest
object for the type A
to use it as the scope object:
var kernel = new StandardKernel();
kernel.Bind<A>().ToSelf().InTransientScope();
kernel.Bind<B>().ToSelf().InTransientScope();
kernel.Bind<C>().ToSelf().InTransientScope();
kernel.Bind<D>().ToSelf().InScope(
c =>
{
//use the Request for A as the scope object
var requestForA = c.Request;
while (requestForA != null && requestForA.Service != typeof (A))
{
requestForA = requestForA.ParentRequest;
}
return requestForA;
});
var a1 = kernel.Get<A>();
Assert.AreSame(a1.b.d, a1.c.d);
var a2 = kernel.Get<A>();
Assert.AreSame(a2.b.d, a2.c.d);
Assert.AreNotSame(a1.c.d, a2.c.d);
Where the sample classes are:
public class A
{
public readonly B b;
public readonly C c;
public A(B b, C c) { this.b = b; this.c = c; }
}
public class B
{
public readonly D d;
public B(D d) { this.d = d; }
}
public class C
{
public readonly D d;
public C(D d) { this.d = d; }
}
public class D { }
Upvotes: 15
Reputation: 9609
I found the solution to my specific problem, which is InCallScope that is provided by the ninject.extensions.namedscope extension. This behaves identically to the Unity PerResolveLifetimeManager concept.
Upvotes: 6
Reputation: 10247
One alternative is to construct the dependencies yourself.
var kernel = new StandardKernel();
kernel.Bind<A>().ToMethod(ctx =>
{
var d = new D();
var c = new C(d);
var b = new B(d);
var a = new A(b, c);
return a;
});
This may not be the preferred method, but it will always construct a new instance of A
using a new instance of B
, C
, and D
(but reusing the same instance of D
for B
and C
). You can add a call to InTransientScope()
, but that is not required as it is the default scope.
Upvotes: 1