Can I use Ninject to instantiate single-user services that nothing depends on?

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

No controllers depend on this, so it won't be created by itself.

I could create it manually by explicitly providing its dependencies kernel.Get

, but it seems to me that I shouldn't.

Can I create Ninject instance classes in the Singleton scope with a look even if nothing depends on it?

+4


source to share


2 answers


You don't have the ability to instantiate ninject unless you ask it to create something. An easy way is to ask ninject to create objects at the root of the composition:

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, in fact, which is not the same, but can be used to achieve a similar effect. This requires at least one other service to be created quickly 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 different from some other containers (eg Autofac) and is not "built" in stages. There is no concept of making the first bindings and then building a core to use them. It is quite legal:

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

      

so ninject cannot know when you want the singletons to be created. With autofac it is clear and easy :

var containerBuilder = new ContainerBuilder();

containerBuilder
    .RegisterType<Foo>()
    .AutoActivate();

var container = containerBuilder.Build(); // now

      

+3


source


Coming from Guice in Java, I really missed the impatient singletons pattern. They are useful in scenarios where, for example, modules act like plugins. If you imagine that the service is built from modules specified in the configuration, you may run into the problem that you are also trying to specify what should be automatically generated for this module when the application starts.

To me, the module is where the composition of the application is defined, and dividing the impatient singletons elsewhere in the code seems more awkward and less intuitive.

Anyway, I was able to very easily implement this as a layer on top of Ninject, here is the code:

public static class EagerSingleton
{
    public static IBindingNamedWithOrOnSyntax<T> AsEagerSingleton<T>(this IBindingInSyntax<T> binding)
    {
        var r = binding.InSingletonScope();

        binding.Kernel.Bind<IEagerSingleton>().To<EagerSingleton<T>>().InSingletonScope();

        return r;
    }
}

public interface IEagerSingleton { }

public class EagerSingleton<TComponent> : IEagerSingleton
{
    public EagerSingleton(TComponent component)
    {
        // do nothing. DI created the component for this constructor.
    }
}

public class EagerSingletonSvc
{
    public EagerSingletonSvc(IEagerSingleton[] singletons)
    {
        // do nothing. DI created all the singletons for this constructor.
    }
}

      



Once you've built your kernel, add one line:

kernel.Get<EagerSingletonSvc>(); // activate all eager singletons

      

You use it in a module like this:

Bind<UnhandledExceptionHandlerSvc>().ToSelf().AsEagerSingleton();

      

+1


source







All Articles