Search code examples
c#dependency-injectioninversion-of-controlautofac

Using constructor injection when caller expects a specific constructor signature


I'm new to DI in .NET C# & autofac and having problems to understand how to use DI when I can't fully control the caller side.

There are two scenarios I have problems to understand.

Scenario 1: Caller expects a default constructor (without any parameters)

How to handle this scenario when I still want to inject some Service Interfaces when the class is constructed? I was thinking of constructor chaining, but that would mean I have to know the concrete type and it works around the idea of DI. (at least I think).

public class ServiceWorker
{
    IService _service;

    public ServiceWorker(IService service) 
    { 
        _service = service
    }
}

public class Caller
{
    // No way to change this. 
    var serviceWorker = new ServiceWorker();
}

Scneario 2: Caller expects a specific constructor signature (e.g.

Same question here. How can I inject additional dependencies when the caller expects an exact match for the constructor signature?

I think my main issue in understanding the concept is, that I don't see how to do DI only partially when not everything is constructed by DI (caller)

public class ServiceWorker
{
    IService _service;

    public ServiceWorker(string name, string id, IService service) 
    { 
        _service = service
    }
}

public class Caller
{
    // No way to change this. 
    var serviceWorker = new ServiceWorker(name, id);
}

I know, this is pretty basic, but I believe I need to understand this first before moving on. Are there alternatives?


Solution

  • As Steven correctly points out in his comment, being restricted to a specific constructor signature is an instance of the Constrained Construction anti-pattern. Sometimes, however, that can be outside your control.

    An example is the so-called 'Provider pattern', which isn't a pattern at all. In such an example, you may have to play by the rules of a third-party framework, so there isn't much you can do about it. Such frameworks should be considered unfriendly to Dependency Injection.

    Consider scenario 2 in the OP, since scenario 1 is just a special case of scenario 2. If you must supply a class with a certain constructor, you could create a Facade that has the required constructor signature. This enables you to avoid polluting your well-designed classes that use Dependency Injection with the constraints imposed by the third-party framework. It could look like this:

    public class ServiceWorker
    {
        IService _service;
    
        public ServiceWorker(string name, string id, IService service) 
        { 
            _service = service
        }
    }
    
    public class ServiceWorkerFacade
    {
        ServiceWorker imp;
    
        public ServiceWorkerFacade(string name, string id) 
        { 
            imp =
                new ServiceWorker(
                    name,
                    id,
                    new FooService(
                        new BarService(),
                        new BazService());
        }
    }
    
    public class Caller
    {
        // No way to change this. 
        var serviceWorker = new ServiceWorkerFacade(name, id);
    }
    

    FooService implements IService. Just to make things interesting, I've assumed that FooService has dependencies of its own, and that those dependencies are satisfied by BarService and BazService.

    As Steven suggests, then, you can (from necessity) consider the Facade's constructor the Composition Root.

    If you have any opportunity to influence the design of the framework in question, you could point the developers to my guidance on designing DI-friendly frameworks.