Export (0) Print
Expand All

Dependency Injection

Retired Content

This content is outdated and is no longer being maintained. It is provided as a courtesy for individuals who are still using these technologies.
This page may contain URLs that were valid when originally published, but now link to sites or pages that no longer exist.

Problem

You have classes that have dependencies on services or components whose concrete type is specified at design time. In this example, ClassA has dependencies on ServiceA and ServiceB. Figure 1 illustrates this.

Ff709852.54b4190e-0037-4eb6-98b7-0766c6d98cc0(en-us,PandP.10).png

Figure 1

ClassA has dependencies on ServiceA and ServiceB

This situation has the following constraints:

  • To replace or update the dependencies, you must change the source code of your classes.
  • The concrete implementation of the dependencies must be available at compile time.
  • Your classes are difficult to test in isolation because they have a direct reference to their dependencies; therefore, the dependencies cannot be replaced with stubs or mocks.
  • Your classes contain repetitive code for creating, locating, and managing their dependencies.

Forces

  • You want to decouple your classes from their dependencies so that the dependencies can be replaced or updated with minimal or no changes to the source code of your classes.
  • You want to be able to write classes that depend on classes whose concrete implementation is not known at compile time.
  • You want to be able to test your classes in isolation, without using the dependencies.
  • You want to decouple your classes from being responsible for locating and managing the lifetime of dependencies.

Solution

Do not instantiate the dependencies explicitly in your class. Instead, declaratively express dependencies in your class definition. Use a Builder object to obtain valid instances of your object’s dependencies and pass them to your object during the object’s creation and/or initialization. Figure 2 illustrates this.

Ff709852.6a0168cd-c036-4654-a167-948eaf9183ba(en-us,PandP.10).png

Figure 2

Conceptual view of the Dependency Injection pattern

The two main forms of dependency injection are:

  • Constructor injection. In constructor injection, you use parameters of the object’s constructor method to inject it with its dependencies.
  • Setter injection. In setter injection, the object exposes setter properties that the builder uses to pass the dependencies to it during object initialization.

Implementation with ObjectBuilder and the Composite Web Application Block

ObjectBuilder is an open source framework for creating dependency injection systems. It is used by the Composite Web Application Block, the Composite UI Application Block, and the Enterprise Library.

ObjectBuilder uses a locator to store references to components and services. In your class source code, you declaratively express dependencies with the [ServiceDependency] attribute. This attribute indicates to ObjectBuilder that it has to search for a valid instance of the dependency in the locator, and inject it when building an object of the type of your class.

The following code demonstrates how to use setter injection.

private IAccountServices  _accountServices;

[ServiceDependency]
public IAccountServices AccountServices
{
  set { _accountServices = value; }
} 

The [ServiceDependency] attribute can also be applied to parameters of a method. To use constructor injection, add the attribute to parameters of a constructor method.

The following code demonstrates how to use constructor injection.

public class ElectronicFundsTransferController
{
  private IAccountServices  _accountServices;

  public ElectronicFundsTransferController
    (
      [ServiceDependency] IAccountServices accountServices
    )
  {
    _accountServices = accountServices;
  }
  ...
}

Liabilities

The dependency injection pattern has the following liabilities:

  • There are more solution elements to manage.
  • You have to ensure that, before initializing an object, the dependency injection framework can resolve the dependencies that are required by the object.
  • There is added complexity to the source code; therefore, it is harder to understand.

More Information

  • To better understand how ObjectBuilder enables you to use the Dependency Injection pattern, see ObjectBuilder.

Related Patterns

  • Service Locator. The Service Locator pattern solves the same problems that the Dependency Injection pattern solves, but it uses a different approach.
  • Inversion of Control. The Dependency Injection pattern is a specialized version of the Inversion of Control pattern.
Show:
© 2014 Microsoft