Abstracting your Dependency Injection framework
August 1, 2008 · 2 minute read
I’ve used various Dependency Injection frameworks in the last year or so and have yet to settle on any one in particular.
My focus has been on StructureMap and Microsoft’s Unity (I know I know everyone seems to dislike the latter for some reason but it does have its uses!).
On a couple of occasions I had to switch DI frameworks in the middle of a project. At first this was hard work as I had multiple references to the specific DI framework and had to change them all.
Whilst doing a bit more research I stumbled upon this post which talks about abstracting your DI implementation and it ticked a lot of boxes for me.
The basic idea is to provide methods for interacting with your DI framework and then make sure you reference those methods and not the DI framework directly.
Specifically we’ll need methods to register a type, retrieve the injected instance of a type and pass in mock types for unit testing purposes (for more detail be sure to check out the original post by Nikola Malovic)
1: public static void Register() where T: I
<pre style="font-size:8pt;overflow:visible;width:100%;color:black;line-height:12pt;font-family:consolas, 'background-color:#f4f4f4;border-style:none;margin:0;padding:0;"><span style="color:#606060;"> 2:</span> {</pre>
<pre style="font-size:8pt;overflow:visible;width:100%;color:black;line-height:12pt;font-family:consolas, 'background-color:white;border-style:none;margin:0;padding:0;"><span style="color:#606060;"> 3:</span> _unityContainer.RegisterType<I, T>(<span style="color:#0000ff;">new</span> ContainerControlledLifetimeManager());</pre>
<pre style="font-size:8pt;overflow:visible;width:100%;color:black;line-height:12pt;font-family:consolas, 'background-color:#f4f4f4;border-style:none;margin:0;padding:0;"><span style="color:#606060;"> 4:</span> }</pre></p>
The register method simply takes an type definition I (e.g. ILogger) and implementation T (e.g. FileLogger).
In this case I am using Microsoft Unity to register the type but it could be any DI framework.
1: public static T Retrieve()
<pre style="font-size:8pt;overflow:visible;width:100%;color:black;line-height:12pt;font-family:consolas, 'background-color:#f4f4f4;border-style:none;margin:0;padding:0;"><span style="color:#606060;"> 2:</span> {</pre>
<pre style="font-size:8pt;overflow:visible;width:100%;color:black;line-height:12pt;font-family:consolas, 'background-color:white;border-style:none;margin:0;padding:0;"><span style="color:#606060;"> 3:</span> <span style="color:#0000ff;">return</span> _unityContainer.Resolve<T>();</pre>
<pre style="font-size:8pt;overflow:visible;width:100%;color:black;line-height:12pt;font-family:consolas, 'background-color:#f4f4f4;border-style:none;margin:0;padding:0;"><span style="color:#606060;"> 4:</span> }</pre></p>
The Retrieve method simply returns the injected implementation for the type specified in the parameter (again using MS Unity in this case)
1: public static void InjectStub(I instance)
<pre style="font-size:8pt;overflow:visible;width:100%;color:black;line-height:12pt;font-family:consolas, 'background-color:#f4f4f4;border-style:none;margin:0;padding:0;"><span style="color:#606060;"> 2:</span> {</pre>
<pre style="font-size:8pt;overflow:visible;width:100%;color:black;line-height:12pt;font-family:consolas, 'background-color:white;border-style:none;margin:0;padding:0;"><span style="color:#606060;"> 3:</span> _unityContainer.RegisterInstance<I>(instance, <span style="color:#0000ff;">new</span> ContainerControlledLifetimeManager());</pre>
<pre style="font-size:8pt;overflow:visible;width:100%;color:black;line-height:12pt;font-family:consolas, 'background-color:#f4f4f4;border-style:none;margin:0;padding:0;"><span style="color:#606060;"> 4:</span> }</pre></p>
Finally the InjectStub method allows us to explicitly pass in an instance of a type (I instance) and have the DI framework use that instance instead of anything we might have registered using the Register method.
This is especially useful when writing unit tests.
1: _logger = _mockery.CreateMock();
<pre style="font-size:8pt;overflow:visible;width:100%;color:black;line-height:12pt;font-family:consolas, 'background-color:#f4f4f4;border-style:none;margin:0;padding:0;"><span style="color:#606060;"> 2:</span>  </pre>
<pre style="font-size:8pt;overflow:visible;width:100%;color:black;line-height:12pt;font-family:consolas, 'background-color:white;border-style:none;margin:0;padding:0;"><span style="color:#606060;"> 3:</span> ServiceLocator.InjectStub(_logger);</pre></p>
When running tests following the above code, any calls to ServiceLocator.Retrieve