Reputation: 4329
I have an interface:
public interface IService
{
void DoStuff(int parm1, string parm2, Guid gimmeABreakItsAnExampleK);
}
I'd like to configure Ninject (v3) bindings so that I can have a "dispatcher" shuffle method calls out to multiple instances of IService
, like so:
public sealed class DispatcherService : IService
{
private IEnumerable<IService> _children;
public DispatcherService(IEnumerable<IService> children)
{
this._children = children.ToList();
}
public void DoStuff(int parm1, string parm2, Guid gimmeABreakItsAnExampleK)
{
foreach(var child in this._children)
{
child.DoStuff(parm1, parm2, gimmeABreakItsAnExampleK);
}
}
}
However, my bindings, that look like this, wind up throwing an exception at runtime indicating a cyclic dependency:
this.Bind<IService>().To<DispatcherService>();
this.Bind<IService>().To<SomeOtherService>()
.WhenInjectedExactlyInto<DispatcherService>();
this.Bind<IService>().To<YetAnotherService>()
.WhenInjectedExactlyInto<DispatcherService>();
Is this possible? If so, what am I doing wrong? Can the ninja escape this cyclical dependency doom?
Upvotes: 10
Views: 683
Reputation: 17388
If your dispatcher is the only IService which is going to take a list of IServices as a parameter, this does work (I tested):
kernel.Bind<IService>().To<DispatcherService>().When(x => x.IsUnique);
this.Bind<IService>().To<SomeOtherService>()
.WhenInjectedExactlyInto<DispatcherService>();
this.Bind<IService>().To<YetAnotherService>()
.WhenInjectedExactlyInto<DispatcherService>();
The reason that When
clause works for this case is that the IsUnique
field of IRequest
gets set to true
when your constructor calls for a single instance of a service. Since your DispatcherService
calls for an IEnumerable
, the value is false
when activating the DispatcherService
. That prevents the circular dependency from happening.
Really, any correct way of telling the kernel not to not try to inject the DispatcherService into itself would work (this is just a potentially useful example).
Edit: The more explicit way of simply short circuiting your circular dependency appears to be this:
kernel.Bind<IService>().To<DispatcherService>().When(
request => request.Target.Member.DeclaringType != typeof (DispatcherService));
Upvotes: 2
Reputation: 21
Why not get rid of IService in the DispatcherService and call it IDispatcherService and make the called services (receivers) implement IService?
Upvotes: 1
Reputation: 61893
You could segregate the two subsets (either Dispatcher or the recievers) out of the way by making one of them a Named Binding, and then use the name as a way to feed one to the other (either via a NamedAttribute
or in your wiring)
Upvotes: 0
Reputation: 172855
I must admit that I'm not that familiar with the Ninject API, but I think this would do the trick:
kernel.Bind<IService>().To<DispatcherService>();
kernel.Bind<IEnumerable<IService>>().ToMethod(() => new IService[]
{
kernel.Get<SomeOtherService>(),
kernel.Get<YetAnotherService>(),
});
Upvotes: 1