Static dependency injection for libraries.
C# PowerShell Batchfile
Switch branches/tags
Nothing to show
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Failed to load latest commit information.
build
lib
src
tests
.gitignore
LICENSE.md
README.md
Rock.StaticDependencyInjection.sln
build.cmd

README.md

Rock.StaticDependencyInjection

Rock.StaticDependencyInjection is a dependency injection mechanism intended to be used by libraries, not applications. For applications, wiring up dependencies happens in the composition root. For console and WinForms applications, this would be at the beginning of Program.Main. For standard web apps, this would be in global.asax's Application_Start method. However, libraries do not have an entry point. Without an entry point, a library has no composition root. This is one problem that Rock.StaticDependencyInjection solves - it creates an entry point in your library.

Rock.StaticDependencyInjection also provides an api for static dependency injection. Most DI containers work via the concepts of constructor injection or property injection. These mechanisms rely on the creation and modification of objects. But what if you have a static dependency? And just what do I mean by a static dependency?

Let's say you own a widget library. And this is what a widget looks like, along with its dependency's interface.

public class Widget
{
    private readonly IFoo _foo;
    
    public Widget(IFoo foo = null)
    {
        _foo = foo ?? Foo.Current;
    }
    
    public void ReportDependencies()
    {
        Console.WriteLine("_foo: {0}", _foo.GetType().Name);
    }
}

public interface IFoo
{
}

There are a few interesting things about this Widget class. First, it has an optional dependency on the IFoo interface - if not provided, the value of the foo parameter defaults to null. Second, if that foo parameter is indeed null, it uses Foo.Current as its value. Here are the rest of the classes in this example.

public static class Foo
{
    static Foo()
    {
        Current = new DefaultFoo();
    }

    public static IFoo Current { internal get; set; }
}

public class DefaultFoo : IFoo
{
}

Foo.Current is the static dependency. It provides a fallback IFoo value for Widget to use if one was not explicitly provided. While this is dangerously close to the Service Locator anti-pattern, I give it a pass here for two reasons. First, the getter is internal, making the Current property unusable outside of the library. This clearly expresses its intent: you are welcome to set this value, but its value is for internal use only. Secondly: because there is a statically-accessible default value, the API of our library improves. Consumers of the Widget class don't need to pass an instance of IFoo to its constructor if they are ok with using the value from Foo.Current instead. This is a huge win for library APIs.

Here's how an application can customize the value of Foo.Current. Pretty simple and straightforward.

class Program
{
    static void Main()
    {
        Foo.Current = new SpecialFoo();
        RunApplication();
    }
    
    static void RunApplication()
    {
        // Note that we don't pass an instance of IFoo to the Widget's constructor.
        // The widget will get its IFoo from Foo.Current.
        var widget = new Widget();
        
        // Because we set Foo.Current, this will display: "_foo: SpecialFoo".
        // If we hadn't set Foo.Current, this would display: "_foo: DefaultFoo".
        widget.ReportDependencies();
    }
}

public class SpecialFoo : IFoo
{
}

However, while this pattern is good, it fails to be great. It requires that all applications that consume this library will have to explicitly specify, at its composition root, the implementation of IFoo to use.

Wouldn't it be great if, just by declaring a single implementation of IFoo, that implementation would be used? So that the application wouldn't need to add Foo.Current = new SpecialFoo(); to their composition root? What if that could be done automatically using some sort of convention?

Rock.StaticDependencyInjection allows you to do just that. You simply add a nuget package to your library, add a few lines of code, and your library will automatically discover and set the static dependencies that it requires with no intervention from the applications that use it.

This is what composition root of your widget library might look like (in CompositionRoot.cs).

class CompositionRoot
{
    public override void Bootstrap()
    {
        ImportSingle<IFoo>(foo => Foo.Current = foo); // Yep, this is it.
    }
}

With that one line of code, the static dependency injection mechanism will find the "best" implementation of IFoo, create an instance of it, and pass that instance to the lambda expression, foo => Foo.Current = foo. There are also many ways of customizing this process, including prioritizing one class over another, specifying the path(s) in which to search for assemblies with implementations of dependencies, and using named import/export pairs.

This ability to discover implementations of dependencies enables another neat pattern. What if an organization takes advantage of internal nuget packages for distribution of core modules of some sort? If one of these internal nuget packages depends on your library, then the libraries in that internal nuget package can define the dependencies for your library. As a result, by merely taking a nuget dependency on their internal nuget package, applications will be properly configured with the right dependency for their organization.

About InjectModuleInitializer

Many thanks to Einar Egilsson for his excellent module initialization mechanism. Rock.StaticDependencyInjection uses it to initiate static dependency injection when a library's assembly is loaded for the first time. Einar's InjectModuleInitializer project is hosted on github and is available via nuget.