Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Ways to setup a Ninject singleton

I have a class (MyFacade) that I injected parameter(s) with Ninject:

class MyFacade
{
    IDemoInterface demo;

    public MyFacade(IDemoInterface demo)
    {
        this.demo = demo;
    }

    public void MyMethod()
    {
        Console.WriteLine(demo.GetInfo());
    }
} 

Of course, I have to setup the Ninject to inject the appropiate implementation of my parameter (IDemoInterface)

I know, I can instantiate MyFacade object by doing kernel.Get<MyFacade>(); without setting anything else. Currently my facade doesn't have an interface (because it is my only implementation, maybe I will add its interface for standard proposes)

if I want to make this facade singlenton, I know two ways: create a empty constructor and pass a parameter by doing this kernel.Get<IDemoInterface>(); or by setup Ninject like: kernel.Bind<MyFacade>().To<MyFacade>().InSingletonScope();

The second one look a better approach, but do you know any other way to setup it in a singleton way?

like image 218
Jaider Avatar asked Feb 11 '14 15:02

Jaider


People also ask

How can Singleton be used in dependency injection?

Singleton is a design pattern, It means that there will be a single copy of your object inside server memory, which will be shared among all the requests (http/client). So, when you register any dependency in your application as a Singleton, then you will get a single copy of an object per server/node/instance.

What is ninject used for?

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 glue them back together in a flexible manner.

What is the difference between Singleton and dependency injection?

The use of singletons and dependency injection is not mutually exclusive. A singleton can implement an interface, therefore can be used to satisfy a dependency on another class. The fact that it is a singleton does not force every consumer to obtain a reference through it's "GetInstance" method/property.

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.


2 Answers

When setting up your bindings, you need to bind your dependencies. It is always better to setup your dependencies in your bindings, as opposed to doing a kernel.Get<T>() in a constructor. You are using IOC, so leverage the framework you are using to do the injection for you.

In your second example binding, what you are missing is binding in your IDemoInterface. Your bindings should look like this:

//bind the dependency to the implementation.
kernel.Bind<IDemoInterface>().To<DemoInterface>();
//since you bound your dependency, ninject should now have 
// all the dependencies required to instantiate your `MyFacade` object.
kernel.Bind<MyFacade>().To<MyFacade>().InSingletonScope(); 
like image 169
Joe Brunscheon Avatar answered Sep 28 '22 03:09

Joe Brunscheon


If you do not want the container to manage the lifecycle of your singleton by using InSingletonScope(), but still wants it to get injected, I can think of 2 ways to go about it. Choose which one suits better to your needs. Consider the following ISingleton (name your interface) implementation:

public class ConcreteSingleton : ISingleton
{
    private static readonly Lazy<ConcreteSingleton> _instance = new Lazy<ConcreteSingleton>(() => new ConcreteSingleton());

    private ConcreteSingleton() { }

    public static ConcreteSingleton Instance
    {
        get
        {
            return _instance.Value;
        }
    }
}
  1. Alter the singleton class to have a GetInstance(...) method

    In this method (my preferred approach), you won't be calling kernel.Inject(instance) each time, only for the first time the singleton is initialized. Adding the following method to your ConcreteSingleton class:

    public static ConcreteSingleton GetInstance(IKernel kernelForInjection)
    {
        if (_instance.IsValueCreated == false)
        {
            kernelForInjection.Inject(_instance.Value);
        }
    
        return _instance.Value;
    }
    

    And using this binding:

    kernel.Bind<ISingleton>().ToMethod(c => ConcreteSingleton.GetInstance(c.Kernel));
    

    Will achieve the desired behavior of not having a public constructor but enabling your facade to be efficiently injected.

  2. Perform injection each time the ISingleton instance is requested

    If by any reason you are not allowed to modify your ConcreteSingleton: This approach will wrap the singleton creation in a provider to efficiently inject the instance only for the first time it is created. It is important to note that the provider itself must be registered as a singleton.

    internal class ConcreteSingletonProvider : Provider<ISingleton>
    {
        public IKernel Kernel { get; set; }
    
        //Just a wrapper
        private readonly Lazy<ISingleton> _lazy = new Lazy<ISingleton>(() => ConcreteSingleton.Instance);
    
        public ConcreteSingletonProvider(IKernel kernel)
        {
            Kernel = kernel;
        }
    
        protected override ISingleton CreateInstance(IContext context)
        {
            if (_lazy.IsValueCreated == false)
            {
                Kernel.Inject(ConcreteSingleton.Instance);
            }
            return _lazy.Value;
        }
    }
    

    And your bindings should be like this:

    kernel.Bind<ISingleton>().ToProvider<ConcreteSingletonProvider>();
    kernel.Bind<ConcreteSingletonProvider>().ToSelf().InSingletonScope();
    

    This gist has a complete working sample for the above approach.

Hope that helps!

like image 34
cvbarros Avatar answered Sep 28 '22 03:09

cvbarros