Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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?

like image 424
FMM Avatar asked Oct 11 '12 19:10

FMM


People also ask

What is ninject used for?

Why use Ninject? Ninject is a lightweight Dependency Injection framework for . NET applications. It helps you split your application into a collection of loosely-coupled, highly-cohesive pieces, and then glues them back together in a flexible manner.

What is a ninject module?

The Ninject modules are the tools used to register the various types with the IoC container. The advantage is that these modules are then kept in their own classes. This allows you to put different tiers/services in their own modules.


1 Answers

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));
like image 175
Kevin Stricker Avatar answered Sep 28 '22 06:09

Kevin Stricker