You're doing it wrong.
You can't do Dependency Injection and have static
class dependencies scattered throughout your code: when you do Dependency Injection, you need to go all the way or not at all, else you gain the complexity and lose the benefits.
Proper DI goes like this:
- Register: Set up your IoC container and register dependencies.
- Resolve: Resolve the entire application's dependency graph - this is ONE method call.
- Release: Dispose any disposables, clean up and tear down.
Your solution doesn't follow the Resolve step correctly, since you're calling .Resolve
to fetch a single specific type, only to call that specific Init
method on your static class: in all likelihood you're eventually going to need to do this in more than one place, and that's only because you stopped injecting dependencies at one point.
Any code that uses this HeaderHelper
static class has a hidden dependency that isn't being injected, which means every single piece of code that uses HeaderHelper
is tightly coupled with one specific implementation of that class.
Consider the below hypothetical MyClass
; its constructor implicitly documents the type's dependencies (here ISomeDependency
), but DoSomething
has a dependency that isn't injected from the outside:
private readonly ISomeDependency _dependency;
public MyClass(ISomeDependency dependency)
{
_dependency = dependency; // explicit dependency, constructor-injected
}
private void DoSomething()
{
var foo = HeaderHelper.Foo; // HeaderHelper is a hidden dependency
_dependency.DoSomething(foo);
}
There are several ways to fix this, but which is best for your case largely depends on context you haven't provided in your question (we know nothing of HeaderHelper
other than it has a vague useless name that doesn't mean anything - you should really avoid "Helper" in class names).
1. Constructor Injection
You could do exactly like you did with the static ConfigurationManager
class, and wrap it with an interface:
public interface IHeaderHelper // todo: rename!!!
{
// members
}
That Init
method seems rather artificial, and wouldn't be needed if the class' constructor took an IConfigurationReader
dependency.
public class HeaderHelper : IHeaderHelper // notice: NOT static
{
private readonly IConfigurationReader _configReader;
public HeaderHelper(IConfigurationReader configReader)
{
_configReader = configReader;
}
// members
}
And then every class that needs to use a HeaderHelper
should intake an IHeaderHelper
constructor argument, and replace the implicit dependencies to the static class with explicit dependencies to that interface, so instead of this:
HeaderHelper.Foobar();
You would have that:
_headerHelper.Foobar();
Where _headerHelper
is a private readonly IHeaderHelper
instance field.
2. Ambient Context
Constructor injection is nice, but sometimes there are cross-cutting dependencies that are needed pretty much everywhere - it's fairly possible that configuration is one of such dependencies. Wrapping it with an interface and constructor-injecting it will work, but then you'll end up with lots of classes that intake this dependency, and when that feels like constructor-bloating, you might want to explore other possibilities.
Mark Seemann's blog describes an interesting pattern to address this problem: the Ambient Context.
This DI pattern would change this:
var foo = HeaderHelper.Foo();
Into this:
var foo = HeaderSettingsContext.Current.Foo();
The Ambient Context is still an implicit dependency though, and Constructor Injection should be preferred most of the time. But by storing the current context in thread-local storage, your tests can easily manipulate the current context, and alter what Foo()
does in your application (e.g. hit the file system and read some XML value vs return a mocked-up value).
This article by Adras Nemes describes more DI patterns (the article is based on Mark Seemann's work).
IConfigurationReader
instance to its constructor. \$\endgroup\$