The Dependency Injection Design Pattern

Applies to: Windows Communication Foundation

Published: June 2011

Author: Alex Culp

Referenced Image

This topic contains the following sections.

  • Introduction to Dependency Injection
  • Introduction to Unity

Introduction to Dependency Injection

Dependency Injection (DI) is a design pattern that demonstrates how to create loosely coupled classes. The term "loosely coupled" deserves clarification and sometimes the best way to explain something is by first describing its opposite, which in this case is "tight coupling." When two classes are tightly coupled, they are linked with a binary association. For example, you might have two classes, Class1 and Class2, that are joined together as an aggregation. This is shown in the following code.

public class Class1
{
    public Class2 Class2 { get; set; }
}
 
public class Class2
{
}

The following figure illustrates the concept of tight coupling.

Two Tightly Coupled Classes

Referenced Image

Typically, if Class1 and Class2 were loosely coupled, Class1 would have a reference to an interface instead of a direct binary reference to Class2. This is shown in the following code.

public class Class1
{
    public IClass2 Class2 { get; set; }
}
 
public interface IClass2 
{
}
 
public class Class2 : IClass2
{
 
}

The following figure illustrates the concept of loose coupling.

Two Loosely Coupled Classes

Referenced Image

However, this implementation of loose coupling presents a problem. If Class1 is responsible for creating a new instance of Class2*, you only have the illusion of being loosely coupled because* Class1 must still know about Class2. This is shown in the following code.

public class Class1
{
    public Class1()
    {
        Class2 = new Class2();           
    }
    public IClass2 Class2 { get; set; }
}
 
public interface IClass2 
{
}
 
public class Class2 : IClass2
{
}

As you can see, because of its constructor, Class1 is still tightly coupled to Class2. A solution to this problem is to use DI. A third class that resolves the dependencies eliminates the last bit of tight coupling. The following code uses DI to implement loose coupling.

public class Class1
{
    public readonly IClass2 _class2;
 
    public Class1():this(DependencyFactory.Resolve<IClass2>())
    {
 
    }
 
    public Class1(IClass2 class2)
    {
        _class2 = class2;
    }
}

Even after a demonstration of how to use DI, you still might wonder why it is useful. Two answers are that it is useful for unit testing, validation and exception management.

Unit Testing. Unit testing, or white box testing, tests a unit of work (often, this is a method). The assumption is that the developer writes the tests because it is the developer who knows the implementation details of what is being tested. A proper unit test can run without any reliance on external dependencies. DI enables you to replace complex dependencies, such as databases, with mocked implementations of those dependencies. This allows you to completely isolate the code that is being testing. For more information about unit testing in WCF, see www.microsoft.com.

Validation/Exception Management. DI allows you to inject additional code between the dependencies. For example, it is possible to inject exception management logic or validation logic, which means that the developer no longer needs to write this logic for every class. For more information about how to use DI for validation and exception management, see www.microsoft.com.

The rest of this article focuses on how to implement DI in WCF services.

Introduction to Unity

Unity is Microsoft's Patterns and Practices solution for DI. It can be downloaded here: https://msdn.microsoft.com/en-us/library/ff663144.aspx.

Unity can also be combined with the great features for exception management and logging that are in the full version of the Microsoft Enterprise Library, which can be found here: https://www.microsoft.com/downloads/en/details.aspx?FamilyID=bcb166f7-dd16-448b-a152-9845760d9b4.

With Unity you can either use configuration files to load dependencies, which is an approach that offers flexibility, or you can use code to register dependencies.

A Note on Configuration versus Code: Although configuration files do offer a flexible way to register dependencies, there is currently no tool to manage those files, so it must be done by hand. In addition, in many organizations, this flexibility is often limited by IT policies. It can require just as much effort, QA testing, and paperwork to move a configuration change into production as it takes for a code change. Consequently, it may be more efficient to use code to register dependencies than to use configuration files.

Unity includes the Interception container extension, which allows you to inject exception management, logging, or even your own custom code between the caller and the called. If you consider Class1 and Class2 from the code examples in the Introduction, an example of when to inject additional logic would be if Class1 needs to make a call to an operation on Class2. You can use Interception to inject the additional logic without having to change any code in Class1 or in Class2.

This article is not an in-depth discussion on how to use Unity, or how to configure it. There is already a great deal of information available. Links to some websites are included at the end of this article, under Additional Resources. Instead, this article focuses on how to use Unity as a DI solution within WCF. There are a number of other tools, other than Unity, that are available for DI. The concepts explained in this article are valid, regardless of the particular tool that you use.

Previous article: Production Configuration Settings

Continue on to the next article: Examples: Using Unity to Implement DI