Search code examples
c#dependency-injectioninversion-of-controlcastle-windsor

Singleton with Dependency Injection


I decided to use singleton in order to load some file when the application started and use this configuration throughout the app lifetime as this file is changed once in a year. There is a singleton:

 public class Singleton
 {
    private static IReader reader;

    private Singleton(IReader reader)
    {
        Singleton.reader = reader;
    }

    private static readonly Lazy<Dictionary<string, HashSet<string>>> lazy =
    new Lazy<Dictionary<string, HashSet<string>>>(() => reader.ReadData("config") );


    public static Dictionary<string, HashSet<string>> Instance { get { return lazy.Value; } }
}

And on Appstart I have:

 IWindsorContainer container = new WindsorContainer();
 container.Install(FromAssembly.This());

And on WindsorInstaller I have:

public class WindsorInstaller : IWindsorInstaller
{
    public void Install(IWindsorContainer container, IConfigurationStore store)
    {
        container.Register(Component.For<IReader>().ImplementedBy<MyReader>());
    }
}

My reader class is following:

 public class MyReader : IReader
 {
    public Dictionary<string, HashSet<string>> ReadData(string source)
    {
        /*some code*/
        return dict;
    }
 }

It seems that there is no injection happening on Singleton and reader is null and I get error: Object reference not set to an instance of an object. Can you please suggest what I am doing wrong and how to do it better (probably not use singleton at all)?


Solution

  • Your concept of the singleton with dependency injection is a bit skewed if the intention is to use it with a container yet still use statics.

    Plus your class has a private constructor. How is the container suppose to explicitly inject dependencies into a private constructor?

    Construct the interface/abstraction of the intended singleton.

    public interface ISingleton {
        Dictionary<string, HashSet<string>> Instance { get; }
    }
    

    and implementation...

    public class Singleton: ISingleton {
        private readonly Lazy<Dictionary<string, HashSet<string>>> lazy;
    
        public Singleton(IReader reader) {
            this.lazy = new Lazy<Dictionary<string, HashSet<string>>>(() => reader.ReadData("config") );
        }
    
        public Dictionary<string, HashSet<string>> Instance { get { return lazy.Value; } }
    }
    

    You then register it with the container as a singleton

    public class WindsorInstaller : IWindsorInstaller {
        public void Install(IWindsorContainer container, IConfigurationStore store) {
            container.Register(Component.For<IReader>().ImplementedBy<MyReader>());
            container.Register(Component.For<ISingleton>().ImplementedBy<Singleton>().LifestyleSingleton());
        }
    }
    

    Any class that has ISingeton as a dependency will get the same instance injected when requested and the Singleton implementation will get its dependency when being resolved.