Best Practices for Dependency Injection

Dependency injection (DI) is a design pattern meant to transform hard-coded dependencies into swappable ones, generally at run-time. DI is the primary mechanism by which to implement Inversion of Control (IoC) techniques to load dependencies at run-time as well as the most effortless way to swap dependency implementations with mocks or stubs for unit testing. DI is a best practice that yields more readable and maintainable code due to the way all of an implementation’s dependencies are knowable at-a-glance and by the amazing side effect of creating easily testable code.

The Practices

Designing for DI incorporates concepts that require discipline to maintain and perpetuate throughout an application lifecycle, but the benefits are worth the work. DI doesn’t just help you achieve the “D” in SOLID, it also helps with the “S”, “L”, and “I” principles, as well. SOLID should guide as many design choices as you’re able to control on any object-oriented software project, so give DI a chance if you’re trying to build up your design chops.

Let’s walk through a simple (and contrived) example of what a typical controller action might look like in an ASP.NET MVC application and then refactor it and its dependencies to use DI. Along the way I’ll define some terms and describe the benefits of refactoring towards DI.

Tight vs. Loose Coupling

Here’s an example of a trivial controller action with tight couplings between the action and its dependencies:

    public class HomeController : Controller
    {
        public ActionResult Index()
        {
            var foo = new FooService();

            return View(foo.Process());
        }
    }

Two classes are said to have a “loose coupling” when one consumes the other without any knowledge of its internal implementation, such as through an interface, instead of directly accessing the implementation. You can see that that the opposite is true in the example above; the action is dependent on FooService, which supplies the viewmodel for the Index view, and further it is tightly coupled to FooService because it’s actually created an instance of the concrete implementation of FooService. Let’s examine FooService:

    public class FooService
    {
        private readonly BarRepository _barRepository;

        public FooService()
        {
            _barRepository = new BarRepository();
        }

        public ExampleModel Process()
        {
            return _barRepository.GetViewModel();
        }
    }

Ok, things aren’t as simple as the Index action would lead us to believe. FooService is dependent on—and tightly coupled to—BarRepository! Again, this implementation is contrived and trivial, and FooService doesn’t really do anything except pass a value up the dependency chain from BarRepository. It’s only meant to illustrate a typical coupling between a few interrelated components, so feel free to imagine a much more complicated transformation of the ExampleModel it retrieves from BarRepository. Here’s what our trivial BarRepository looks like:

    public class BarRepository
    {
        public ExampleModel GetViewModel()
        {
            // Actual untestable code that talks to a db
            return new DataContext().Bars
                .Select(b => new ExampleModel { Data = b.DataValue });
        }
    }

BarRepository doesn’t have any hidden dependencies of its own, so the dependency chain that started in the Index action on HomeController stops here. This tightly coupled implementation works fine, but there are major flaws:

  • The Index action’s interaction with FooService cannot be unit tested, and FooService’s interactions with BarRepository cannot be safely unit tested because GetViewModel() connects to a datasource, an action that could create side-effects or simply fail in certain environments
  • As the example grows into a larger, more complicated application, dependencies that are created on the fly become more difficult to identify and track
  • Because there is no way to inject dependencies, there is no ability for the developer to swap them out at runtime, or implement the IoC pattern

These flaws work against the maintainability of the application because they greatly hinder the developer’s ability to test and refactor the code.

Unit Testing

Unit testing is a best practice that provides an automated mechanism for verifying the quality of an application from the developer’s perspective, and provides a behavior contract for future developers to follow. An exhaustive unit test suite can act as a reliable safeguard for anyone who needs to refactor code, modify features, fix bugs, or even make major architectural changes. Look to the automated unit testing best practices post for more details on how testing can benefit the maintainability and quality of your applications. Unit test frameworks like NUnit provide a mechanism for naming and testing individual units of functionality in your implementations. When combined with DI, each of your implementations that don’t directly access an infrastructure component like an OS resource (files, registry, etc.), a database, or the network should be completely testable in isolation from all other components, including its dependencies.

Often the last dependency in a chain isn’t considered testable because it’s usually the class that actually communicates with an infrastructure resource like a database or the file system and contains logic that isn’t safe to execute inside a test because it might cause side effects or fail to run at all. Let’s start one level from the bottom and try to make FooService interaction with BarRepository testable. Here’s the start of an NUnit test:

    [Test]
    public void ProcessCallsGetViewModelOnBarRepository()
    {
        var foo = new FooService();

        Assert.That(foo.Process(), ???);
    }

Well we can’t really assert anything except that foo.Process() returns a particular type…since FooService isn’t declaring BarRepository as an injectable dependency, there’s no way to control its instantiation and measure how FooService interacts with it internally. Let’s refactor FooService to inject BarRepository on its constructor:

    public class FooService
    {
        private readonly BarRepository _barRepository;

        public FooService(BarRepository barRepository)
        {
            _barRepository = barRepository;
        }

        public ExampleModel Process()
        {
            return _barRepository.GetViewModel();
        }
    }

That wasn’t a very big change—now the creator of FooService is responsible for passing a BarRepository instance to the constructor. Can we unit test yet? Let’s try:

    [Test]
    public void ProcessCallsGetViewModelOnBarRepository()
    {
        var bar = new BarRepository();
        var foo = new FooService(bar);

        Assert.That(foo.Proces, ???);
    }

Ugh, so close! We still can’t verify that Process() calls bar.GetViewModel(). Polymorphism to the rescue! Declaring dependencies using an abstraction like an interface is a best practice to make implementing fakes of the dependency in your unit tests easier. Let’s extract an interface for BarRepository:

    public interface IBarRepository
    {
        ExampleModel GetViewModel();
    }

    public class BarRepository : IBarRepository
    {
        public ExampleModel GetViewModel()
        {
            // Actual untestable code that talks to a db
            return new DataContext().Bars
                .Select(b => new ExampleModel { Data = b.DataValue });
        }
    }

All we have to do is swap out BarRepository for IBarRepository on FooService and we can create a fake IBarRepository in our unit test class. We’ll make the fake GetViewModel method return a particular instance of ExampleModel to prove that FooService is really getting it from IBarRepository and not just creating it on its own:

    [Test]
    public void ProcessCallsGetViewModelOnBarRepository()
    {
        var model = new ExampleModel();
        var bar = new FakeBar(model);
        var foo = new FooService(bar);

        // If model is not returned by Process(), that means
        // it never called IBarRepository.GetViewModel()!
        Assert.That(foo.Process(), Is.SameAs(model));
    }

    class FakeBar : IBarRepository
    {
        private readonly ExampleModel _modelToReturn;

        public FakeBar(ExampleModel modelToReturn)
        {
            _modelToReturn = modelToReturn;
        }

        public ExampleModel GetViewModel()
        {
            return _modelToReturn;
        }
    }

Finally—a unit test that works! FakeBar has a constructor that accepts an ExampleModel which is returned by GetViewModel(). This allows our test to inject a particular model instance and assert that it was returned as expected by the FooService’s interaction with IBarRepository!

So what we’ve done is make the FooService testable, but we changed our controller action’s implementation as a side effect. What if we want to test the controller action?

    public ActionResult Index()
    {
        var foo = new FooService(new BarRepository());

        return View(foo.Process());
    }

Long story short: you can’t for the same reason that FooService wasn’t testable when we started: we would need to be able to inject a FooService instance into the Controller somehow. Here’s what the controller looks after constructor injection refactoring:

    public class HomeController : Controller
    {
        private readonly IFooService _fooService;

        public HomeController(IFooService fooService)
        {
            _fooService = fooService;
        }

        public ActionResult Index()
        {
            return View(_fooService.Process());
        }
    }

While I was at it, I extracted an interface for FooService. Let’s test it:

    public void IndexActionReturnsViewWithModelFromIFooServiceProcess()
    {
        var model = new ExampleModel();
        var foo = new FakeFoo(model);
        var controller = new HomeController(foo);
        var result = controller.Index();

        // Ensure the Index action's result isn't null, that it's a view,
        // and that the model is set correctly to the one injected into our fake
        Assert.That(result, Is.Not.Null);
        Assert.That(result, Is.TypeOf());
        Assert.That(((ViewResult)result).Model, Is.SameAs(model));
    }

    class FakeFoo : IFooService
    {
        private readonly ExampleModel _modelToReturn;

        public FakeFoo(ExampleModel modelToReturn)
        {
            _modelToReturn = modelToReturn;
        }

        public ExampleModel Process()
        {
            return _modelToReturn;
        }
    }

So, this looks straight forward enough, right? Wait, how does a controller get created? Isn’t that ASP.NET MVC’s job? How does the MVC framework know what to pass in for IFooService on the HomeController’s constructor? Let’s fire up the app and see what happens:

No Parameterless Constructor defined for object.
Looks like ASP.NET MVC only supports parameterless constructors on controllers by default. This brings us to the concept of the composition root.

Composition Roots

Mark Seemann defines the composition root of an application as “the central place in an application where the entire application is composed from its constituent modules.” In plainer language this means the spot in your application where an incoming request (a button click, an HTTP command, etc.) creates the first link in a dependency chain and allows core application logic to interact with it.

Every framework has a different composition root location (WPF, ASP.NET WebForms, WCF, etc.) and style. In ASP.NET MVC, the composition root is the DefaultControllerFactory implementation, which you can see in the stack trace of the error above. The built-in implementation can create an instance of any class that descends from Controller as long as it has a default or parameterless constructor. If you want to inject dependencies into your controllers’ constructors, you need to implement a custom DefaultControllerFactory, override GetControllerInstance() and insert your own access logic to create your controllers. Here’s an example custom implementation that knows how to create our HomeController with the dependencies passed in:

public class CustomControllerFactory : DefaultControllerFactory
{
    protected override IController GetControllerInstance(System.Web.Routing.RequestContext requestContext, Type controllerType)
    {
        if (controllerType == null) return null;
        if (controllerType == typeof(HomeController)) return new HomeController(new FooService(new BarRepository()));
        return base.GetControllerInstance(requestContext, controllerType);
    }
}

Now we have to tell ASP.NET MVC how to find our custom implementation by wiring it up in Global.asax:

protected void Application_Start()
{
    AreaRegistration.RegisterAllAreas();

    WebApiConfig.Register(GlobalConfiguration.Configuration);
    FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
    RouteConfig.RegisterRoutes(RouteTable.Routes);
    BundleConfig.RegisterBundles(BundleTable.Bundles);
    AuthConfig.RegisterAuth();
    ControllerBuilder.Current.SetControllerFactory(new CustomControllerFactory());
}

Now when we fire up the app, the MVC infrastructure knows how to create a HomeController and the app loads as expected! So far we’ve made everything testable and we’ve declared our dependencies in a readable and maintainable way. The remaining flaw in the original, tightly coupled implementation is an inability to implement the IoC pattern.

Inversion of Control is a concept where the specific coupling between abstractions and implementations is not knowable at compile time, and so isn’t established until run time. DI is the main method to implement IoC, both being extremely effective techniques for constructing composable, testable software. Our CustomControllerFactory implementation is still “newing up” our controller and its dependencies and so doesn’t meet the criteria to implement true run time IoC.

This is where a DI framework (aka IoC Container) comes into play. Using a DI Framework is a best practice for implement bindings between interfaces (or abstract classes) and their implementations in code or configuration files that are available at run time. DI frameworks are amazing pieces of near-magical software and deserve a lot more coverage than I can provide right here…look for the [[IoC best practice]] on this site for more details about implementing one to enable true IoC in your application and learn how it can improve the maintainability and flexibility of your code.

Summary

There is no question in my mind that making all dependencies injectable results in more dynamic, more maintainable, more easily testable code. Even if you don’t want to use a mocking framework, even if you don’t want to unit test at all, even if you won’t use a DI framework and swap implementations at run-time, you can still reap maintainability benefits at no cost from writing software where dependencies are clearly identified, particular on an implementation’s constructor, and that says more to me than all the testing, IoC and mocking tutorials can about the soundness and robustness of the DI pattern.

Trackbacks

  1. […] Best Practices for Dependency Injection (ilmbestpractices.wordpress.com) […]

Leave a Comment

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: