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?
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 { }
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With