Sebastian Edelmeier
Sebastian Edelmeier

Reputation: 4157

Ninject injection chain isolation

I'm working on an application that is split over multiple assemblies. Each of the assemblies provides Interfaces to the outside world, instances are generated via Ninject-based factories.

Ah well, let there be Code. This is from the executing Assembly.

public class IsolationTestModule : NinjectModule
{
    public override void Load()
    {
        ServiceFactory sf = new ServiceFactory();
        Bind<IService>().ToMethod(context=>sf.CreatService()).InSingletonScope();
    }
}

public partial class App : Application
{
    protected override void OnStartup(StartupEventArgs e)
    {
        IKernel kernel = new StandardKernel(new IsolationTestModule());
        IService service = kernel.Get<IService>();
    }
}

The ServiceFactory also relies on Ninject, but has its own Kernel and its own Module:

public interface IService
{
    void Idle();
}

public interface IDependantService
{
    void IdleGracefully();
}

public class ServiceImpl : IService
{
    [Inject]
    public IDependantService DependantService { get; set; }

    public void Idle() 
    {
        DependantService.IdleGracefully();
    }
}

public class DependantServiceImpl : IDependantService
{
    public void IdleGracefully() { }
}

public class ServiceFactory
{
    private IKernel _kernel = new StandardKernel(new SuppliesModule());

    public IService CreatService()
    {
        return _kernel.Get<IService>();
    }
}

public class SuppliesModule : NinjectModule
{
    public override void Load()
    {
        Bind<IService>().To<ServiceImpl>().InSingletonScope();
        Bind<IDependantService>().To<DependantServiceImpl>().InSingletonScope();
    }
}

What actually happens : All's well until the ServiceFactory has completed to build the ServiceImpl-instance. In the next step, the application's kernel tries to resolve ServiceImpl dependencies via IsolationTestModule and - of course - fails with an exception (no binding available, type IDependantService is not self-bindable). In my understanding the factory's kernel should do that... Actually I never knew Ninject was that eager to resolve dependencies even in those instances it did not immediately create, which surely opens up new horizons to me ;-)

To temporarily solve this, I change the ServiceImpl to Constructor based injection as depicted below:

public class ServiceImpl : IService
{
    public IDependantService DependantService { get; set; }

    [Inject]
    public ServiceImpl(IDependantService dependantService)
    {
        DependantService = dependantService;
    }

    public void Idle() 
    {
        DependantService.IdleGracefully();
    }
}

Nevertheless, I would prefer a solution that does not force me to change my Injection strategy. Does anyone have an idea how I can separate the Injection chains?

Upvotes: 1

Views: 633

Answers (1)

Remo Gloor
Remo Gloor

Reputation: 32725

Your observations are correct. Ninject will do property injection for objects created by ToMethod. Also your solution to use constructor injection is the right way to go. Constructor injection is the perfered way to use Ninject anyway. Property Injection should be used for optional dependencies only.

What you should consider is to use just one kernel. It is very unusual to use multiple kernel instances in an application.

Upvotes: 1

Related Questions