dependency-injectionsingletonunity-container

Singleton class with Dependency Injection c#


We have an external project with a QCServiceLog class that has a ILogging dependency which is resolved by Unity. But QCServiceLog is a Singleton class as you can see in the following example:

private readonly ILogging _logging = null;

private static QCServiceLog _instance = null;
public static QCServiceLog Instance
{
    get
    {
        return _instance;
    }
}

public QCServiceLog(ILogging logging)
{
    _logging = logging;
    if (_instance == null)
    {
        _instance = this;
    }
}

We are trying to use it, and in our solution we did the registration like:

uc.RegisterType<ILogging, QCFileManager>(new ContainerControlledLifetimeManager());

But since QCServiceLog is a Singleton we believe that the code never gets through the constructor, then _instance is never instantiated. We are using it doing this:

QCServiceLog.Instance.Log(ex);

Is that Singleton implemented correctly? We believe that it´s never doing a new of QCServiceLog.

What do you think? Is there anything that we can do without changing the external project? The exception as you can imagine is:

Object reference not set to an instance of an object.

I would really appreciate your help!


Solution

  • Is that Singleton implemented correctly?

    Yes. But it needs to be instantiated first from the container before you can get a static instance of it.

    In other words, you can't use this line:

    QCServiceLog.Instance.Log(ex);
    

    until you first call:

    container.Resolve<QCServiceLog>();
    

    (assuming you have registered an instance of ILogging with Unity) because the first call will not hit the constructor to populate the _instance value.

    You are probably better off either injecting it directly where it is needed:

    public class Foo(QCServiceLog log)
    

    Or alternatively making a wrapper class that contains the logic to wire it up correctly before using it that is injected via your DI container.

    Either way, you should note that DI is primarily for your application. 3rd party utilities don't necessarily do things in a DI-friendly way, so you may need to use a facade or adapter in order to make them DI-friendly for use within the context of your application.