Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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?

like image 365
Matthew Avatar asked Jul 16 '15 03:07

Matthew


1 Answers

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
like image 130
BatteryBackupUnit Avatar answered Nov 15 '22 04:11

BatteryBackupUnit