12

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");
        }
    }
}
Bobr
  • 155
  • 1
  • 1
  • 7
  • 3
    Just pass the ILogger implementation into IsValid method. This is the only one way I can suggest, because I'm not aware of the overall intentions around your validation class. – EngineerSpock Apr 01 '15 at 11:23
  • [Dependency injection and named loggers][1] [1]: http://stackoverflow.com/questions/3452318/dependency-injection-and-named-loggers – Taras Kovalenko Apr 01 '15 at 11:25

1 Answers1

23

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.

Fred Kleuver
  • 7,797
  • 2
  • 27
  • 38
  • 2
    What are good examples where it's a valid scenario to be resolving a dependency in a static class? – Ciaran Gallagher Aug 19 '19 at 10:44
  • 1
    You are using an extension method, which of course must be static, to add a Custom Configuration Provider. And that needs to have a particular database implementation injected. – KarlZ Apr 14 '21 at 14:55