Search code examples
c#singletonninject

Can I use Ninject to instantiate singleton services that nothing depends on?


I have some services in my asp.net mvc application that listen for AMQP messages and invoke methods.

No controllers depend on this, so it won't get instantiated on its own.

I could instantiate it manually, explicitly providing its dependencies with kernel.Get but it feels like I shouldn't have to do that.

Can I make Ninject instantiate classes in singleton scope eagerly even when nothing else depends on it?


Solution

  • You cannot have ninject instantiate stuff in case you don't ask it to instantiate something yourself. The simple way is to ask ninject to instantiate things at composition root:

    var kernel = new StandardKernel();
    kernel.Bind<IFoo>().To<Foo>();
    kernel.Load(AppDomain.CurrentDomain.GetAssemblies()); // loads all modules in assemlby
    //...
    // resolution root completely configured
    
    kernel.Resolve<IFooSingleton>();
    kernel.Resolve<IBarSIngleton>();
    

    There is one alternative, actually, which is not the same, but can be used to achieve a similar effect. It requires that there is at least one single other service instantiated soon enough: Ninject.Extensions.DependencyCreation. It works like this:

    kernel.Bind<string>().ToConstant("hello");
    
    kernel.Bind<ISingletonDependency>().To<SingletonDependency>()
        .InSingletonScope();
    kernel.DefineDependency<string, ISingletonDependency>();
    
    kernel.Get<string>();
    // when asking for a string for the first time
    // ISingletonDependency will be instantiated.
    // of course you can use any other type instead of string
    

    Why

    Ninject is unlike some other containers (for example Autofac) not "built" in stages. There's no concept of first creating the bindings, and then creating the kernel to use them. The following is perfectly legal:

    kernel.Bind<IFoo>()...
    kernel.Get<IFoo>()...
    kernel.Bind<IBar>()...
    kernel.Get<IBar>()...
    

    so ninject can't possibly know when you want the singletons to be instantiated. With autofac it's clear and easy:

    var containerBuilder = new ContainerBuilder();
    
    containerBuilder
        .RegisterType<Foo>()
        .AutoActivate();
    
    var container = containerBuilder.Build(); // now