Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Dependency injection for a static method [duplicate]

I have a class in an API, have a static method, intended to validate and log details. Any guidance how to inject ILogger interface please.

public class ValidateDataInAPI
{
    public static bool IsValid(string data)
    {
        //do something
        If(error) 
        {
            _logger.Error("Log error as implemented by caller");
        }
    }
}
like image 482
Bobr Avatar asked Apr 01 '15 11:04

Bobr


1 Answers

If I understand correctly, you want to inject an instance of ILogger into a static method. As you probably figured out already you cannot make use of Dependency Injection the "normal way" when the dependent method is static.

What you might be looking for here is the service locator pattern.

Using the StructureMap IoC container (but you can really use any container), the configuration for wiring it up might look like this:

For<ILogger>().Use<SomeLoggerImplementation>();

When implemented, your calling code might look something like this:

public class ValidateDataInAPI
{
    private static ILogger Logger
    {
        // DependencyResolver could be any DI container here.
        get { return DependencyResolver.Resolve<ILogger>(); }
    }

    public static bool IsValid(string data)
    {
        //do something
        If(error) 
        {
            Logger.Error("Log error as implemented by caller");
        }
    }
}

I would like to point out that this can be considered an anti-pattern and should only be used when there is a clear justification, not just out of convenience.

The whole idea of Dependency Injection is that you inject the dependencies into the calling code's constructor, thereby exposing all of a class's dependencies to the outside world.

This not only improves the readability of your code (there are no internally hidden "surprises"), it also improves the testability. You don't want to be configuring your IoC container in your Unit Tests projects, do you? Using Dependency Injection the right way eliminates this necessity and makes your life a whole lot easier when you want to unit test your code.

If you are not familiar with the concept of Dependency Injection, this link could help you to get started. There is plenty of information out there.

With Dependency Injection your calling code would look like this:

public class ValidateDataInAPI : IValidateDataInAPI
{
    private readonly ILogger _logger;

    // Since the dependency on ILogger is now exposed through the class's constructor
    // you can easily create a unit test for this class and inject a mock of ILogger.
    // You will not need to configure your DI container to be able to unit test.
    public ValidateDataInAPI(ILogger logger)
    {
        _logger = logger;
    }

    public bool IsValid(string data)
    {
        //do something
        If(error) 
        {
            _logger.Error("Log error as implemented by caller");
        }
    }
}

Similarly, by having an interface defined for your validation class you can inject that validation class into the API class:

public interface IValidateDataInAPI
{
    bool IsValid(string data);
}

You can now mock the Validator class which will allow you to unit test your API class more easily.

Having said that, if you really do need to keep your IsValid method static, the service locator pattern is probably the way to go.

like image 69
Fred Kleuver Avatar answered Sep 28 '22 07:09

Fred Kleuver