FMM
FMM

Reputation: 4329

Ninject bindings for a dispatcher implementation of an interface

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

Answers (4)

Kevin Stricker
Kevin Stricker

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

soloist
soloist

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

Ruben Bartelink
Ruben Bartelink

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

Steven
Steven

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

Related Questions