Search code examples
c#classdependency-injectionstatic

Use dependency injection in static class


I need to use Dependency Injection in a static class.

the method in the static class needs the value of an injected dependency.

The following code sample demonstrates my problem:

public static class XHelper
{
    public static TResponse Execute(string metodo, TRequest request)
    {
        // How do I retrieve the IConfiguracion dependency here?
        IConfiguracion x = ...;

        // The dependency gives access to the value I need
        string y = x.apiUrl;

        return xxx;
    }
}

Solution

  • You basically have two options:

    1. Change the class from static to an instance class and supply the dependency through Constructor Injection.
    2. Supply the dependency to the class's public method through Method Injection.

    Here are examples for each option.

    Option 1. Change the class from static to an instance class

    Change the class from static to an instance class and supply IConfiguration through Constructor Injection. XHelper should in that case be injected into the constructor of its consumers. Example:

    public class XHelper
    {
        private readonly IConfiguration config;
        
        public XHelper(IConfiguration config)
        {
            this.config = config ?? throw new ArgumentNullException("config");
        }
    
        public TResponse Execute(string metodo, TRequest request)
        {
            string y = this.config.apiUrl;
    
            return xxx;
        }
    }
    

    Consequence of this option is that the class XHelper must itself become a constructor argument of the constructor of its consumers, and thus itself be injected. This results in changes to the Composition Root by either adding a registration for XHelper—in case a DI Container is used—or to create and inject it to its consumers—in case Pure DI is practiced.

    2. Supply the IConfiguration to the Execute method through Method Injection.

    Example:

    public static class XHelper
    {
        public static TResponse Execute(
            string metodo,
            TRequest request,
            IConfiguration config) // <-- dependency now injected here
        {
            if (config is null) throw new ArgumentNullException("config");
        
            string y = config.apiUrl;
    
            return xxx;
        }
    }
    

    Consequence of this option is that the consumers of XHelper must supply the IConfiguration dependency while calling XHelper.Execute. This most likely means that IConfiguration must be injected into their own constructor.

    Less favorable options

    There are of course more options to consider, but I consider them all to be less favorable, because they would either cause code smells or anti-patterns.

    For instance:

    • You might be inclined to make the DI Container accessible through a static method and call it from inside your static class, but this is an anti-pattern called Service Locator.
    • You could allow setting the static class's dependencies through static properties on that class, but this leads to the Ambient Context anti-pattern.
    • You could change the class to an instance class as in option 1, but instead of using Constructor Injection make use of Property Injection, but this causes Temporal Coupling, which is a code smell.