Dependency injection - Writing SOLID code - Adaptive Code via C# Agile coding with design patterns and SOLID principles (2014)

Adaptive Code via C# Agile coding with design patterns and SOLID principles (2014)

Part II: Writing SOLID code

Chapter 9. Dependency injection

After completing this chapter, you will be able to

Image Understand the importance of dependency injection.

Image Use dependency injection as the glue that holds SOLID code together.

Image Choose between Poor Man’s Dependency Injection, an Inversion of Control container, or convention over configuration.

Image Avoid dependency injection anti-patterns.

Image Organize your solutions around composition roots and resolution roots.

Image Know how the Factory pattern collaborates with dependency injection to manage object lifetimes correctly.

Dependency injection (DI) is a very simple concept with a similarly simple implementation. However, this simplicity belies the importance of the pattern. DI is the glue without which the techniques of the previous SOLID chapters—and much of the Agile foundation chapters—would not be possible.

When something is so simple, yet so important, people tend to overcomplicate it. DI is no exception, but there are a number of pitfalls that you should be aware of. These include anti-patterns and general bad practices that subvert the intent of this pattern.

Implemented correctly, dependency injection is invisible to the majority of a project’s code. It is limited to a very small amount of the code, often in a single assembly. The trick is to plan for dependency injection from the outset, because integrating it into an established project is difficult and time consuming.

Humble beginnings

The following example highlights the underlying problem that dependency injection solves. Imagine that you are developing a task management application that allows the user to manage a to-do list. In this hypothetical scenario, you are still in the early stages of development, using Windows Presentation Foundation (WPF) for the user interface. So far, you have a main window for the application that does little other than show the current state of your to-do list, which is read from persistent storage. Figure 9-1 shows this window.

Image

FIGURE 9-1 The task list has some state beyond the task description: priority, due date, and the task’s completion state.

Because this is a WPF application, you are using the Model-View-ViewModel (MVVM) pattern to ensure a separation of concerns between the layers. The application strives to use best practices—although dependency injection is still to come. One of the view models is the backing controller for the main window. TaskListController delegates to a TaskService to retrieve all of the tasks. An example of how this is currently accomplished without dependency injection is shown in Listing 9-1.

LISTING 9-1 This controller does not use dependency injection.


{
public event PropertyChangedEventHandler PropertyChanged = delegate { };

private readonly ITaskService taskService;
private readonly IObjectMapper mapper;
private ObservableCollection<TaskViewModel> allTasks;

public TaskListController()
{
this.taskService = new TaskServiceAdo();
this.mapper = new MapperAutoMapper();


var taskDtos = taskService.GetAllTasks();
AllTasks = new
ObservableCollection<TaskViewModel>(mapper.Map<IEnumerable<TaskViewModel>>(taskDtos));
}

public ObservableCollection<TaskViewModel> AllTasks
{
get
{
return allTasks;
}
set
{
allTasks = value;
PropertyChanged(this, new PropertyChangedEventArgs("AllTasks"));
}
}
}


The problems with this approach include:

Image Difficulty in unit testing the controller due to a dependency on an implementation.

Image Lack of clarity as to what this view model requires—depends on—unless its source is checked.

Image Implied dependency from this class to the dependencies of the service.

Image Lack of flexibility in providing alternative service implementations.

The rest of this section investigates these problems in greater depth by comparing the original class with a refactored version that uses dependency injection, as shown in Listing 9-2. (The changes have been highlighted in bold.)

LISTING 9-2 After refactoring, this controller uses dependency injection.


public class TaskListController : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged = delegate { };

private readonly ITaskService taskService;
private readonly IObjectMapper mapper;
private ObservableCollection<TaskViewModel> allTasks;

public TaskListController(ITaskService taskService, IObjectMapper mapper)
{
this.taskService = taskService;
this.mapper = mapper;
}

public void OnLoad()
{
var taskDtos = taskService.GetAllTasks();
AllTasks = new
ObservableCollection<TaskViewModel>(mapper.Map<IEnumerable<TaskViewModel>>(taskDtos));
}

public ObservableCollection<TaskViewModel> AllTasks
{
get
{
return allTasks;
}
set
{
allTasks = value;
PropertyChanged(this, new PropertyChangedEventArgs("AllTasks"));
}
}

}


To unit test the first class in isolation, as you should, the TaskService would need to be mocked. However, it is unlikely that the TaskService can be mocked by conventional means. It is not likely to be a proxiable class, nor should you be forced to make it so. The second class accepts an ITaskService, which is an interface, rather than a class. This is more testable because interfaces are always proxiable.


Image Note

A class is said to be proxiable if an alternative implementation—known as a proxy—can be provided to the client. Classes are only proxiable if they declare all of their methods as virtual. Interfaces, on the other hand, are always proxiable.


If a class arbitrarily constructs classes inside its methods, you cannot know externally what it requires in order to function correctly. The first example, without DI, is a black box of dependencies. You can only discover what it needs by opening the class file and reading through it studiously. It declares none of its dependencies as part of its interface or method signatures. The second example, with DI, clearly states that it needs an implementation of the task service in order to function. This is discoverable from client code by using IntelliSense, which is included with Microsoft Visual Studio.

When a dependency exists between class A and class B, if class B has a dependency on class C, it follows that class A is implicitly dependent on class C. This is how the Entourage anti-pattern manifests and leads to an interconnected web of dependencies that are very difficult to rectify. If you ensure that your interfaces generalize—that is, that they correctly abstract their behavior—a class that depends on an interface does not depend on anything further. This holds true even though implementations of the interface might depend on something heavy and external, such as a database. This is the Stairway pattern correctly applied.

When objects are instantiated directly, you also lose a possible extension point that an interface would otherwise provide. You cannot inherit from the TaskService and enhance its methods—assuming that they are declared virtual—because you would have to amend the controller to directly construct a new instance of this subclass. Interfaces lend themselves to all sorts of interesting patterns that can be used to provide alternative implementations or enhance the existing implementation. Additionally, as you have learned, this can be done after the initial version of the class has been written, before new requirements have been discovered. This is the key to code adaptability.

The Task List application

Figure 9-2 shows the package-level and class-level organization that you are aiming for with the Task List application.

Image

FIGURE 9-2 UML class diagram of the three-layered Task List application, with packages.

The user interface consists of WPF and controller/view model-specific code. The service layer is abstracted from the controllers via an interface, which has an implementation that uses a simple ADO.NET call to retrieve the tasks from persistent storage.

The TaskDto class is returned by the service as an in-memory representation of a task row from storage. This is a Plain Old CLR Object (POCO) and, as such, it is not as feature rich as a WPF view model really should be. Thus, when TaskController retrieves the TaskDto objects from the ITaskService, it asks an IObjectMapper to convert them to TaskViewModel objects, which implement INotifyPropertyChanged and can be embellished with other view-specific features.

The ADO.NET implementation of the ITaskService interface is shown in Listing 9-3. The constructor is your main concern, but later this chapter will discuss a lingering code smell in this class.

LISTING 9-3 The TaskService is responsible for retrieving the task list data.


public class TaskServiceAdo : ITaskService
{
public TaskServiceAdo(ISettings settings)
{
this.settings = settings;
}


public IEnumerable<TaskDto> GetAllTasks()
{
var allTasks = new List<TaskDto>();


private readonly ISettings settings;

private const int IDIndex = 0;
private const int DescriptionIndex = 1;
private const int PriorityIndex = 2;
private const int DueDateIndex = 3;
private const int CompletedIndex = 4;
using(var connection = new
SqlConnection(settings.GetSetting("TaskDatabaseConnectionString")))
{
connection.Open();

using(var transaction = connection.BeginTransaction())
{
var command = connection.CreateCommand();
command.Transaction = transaction;
command.CommandType = CommandType.StoredProcedure;
command.CommandText = "[dbo].[get_all_tasks]";

using(var reader = command.ExecuteReader(CommandBehavior.CloseConnection))
{
if (reader.HasRows)
{
while (reader.Read())
{
allTasks.Add(
new TaskDto
{
ID = reader.GetInt32(IDIndex),
Description = reader.GetString(DescriptionIndex),
Priority = reader.GetString(PriorityIndex),
DueDate = reader.GetDateTime(DueDateIndex),
Completed = reader.GetBoolean(CompletedIndex)
}
);
}
}
}
}
}

return allTasks;
}

}


The ISettings interface abstracts away from this class the details of retrieving the connection string. An implementation that is an adapter for the Microsoft .NET Framework’s ConfigurationManager class is provided. It is not hard to imagine that the settings could end up being stored elsewhere at some point, which justifies the use of an interface. Another problem is that the ConfigurationManager class is static and, thus, hard to mock. Using it directly would not only limit your options for retrieving application settings such as connection strings, it would also make the TaskServiceAdo class less testable.

Constructing the object graph

Often in this book, it has been an accepted fact that interfaces are injected into constructors. Eventually, of course, interfaces prove to be insufficient, and you must commit to an implementation. There are two main options for accomplishing this: Poor Man’s Dependency Injection and using an Inversion of Control container. In order to exemplify how dependency injection works, this section will first look at Poor Man’s DI.

Poor Man’s Dependency Injection

This pattern is so named because it does not require any external dependencies in order to function. It involves constructing the necessary object graph for the controller ahead of time. Listing 9-4 shows how to construct the refactored TaskListController and provide it to theTaskListView, which is the application’s main window.

LISTING 9-4 Poor Man’s DI is verbose but flexible.


public partial class App : Application
{
private void OnApplicationStartup(object sender, StartupEventArgs e)
{
CreateMappings();

var settings = new ApplicationSettings();
var taskService = new TaskServiceAdo(settings);
var objectMapper = new MapperAutoMapper();
controller = new TaskListController(taskService, objectMapper);
MainWindow = new TaskListView(controller);
MainWindow.Show();

controller.OnLoad();
}

private void CreateMappings()
{
AutoMapper.Mapper.CreateMap<TaskDto, TaskViewModel>();
}

private TaskListController controller;
}


This code is the entry point to your application. The OnApplicationStartup method is an event handler that is called by internal WPF code to inform you that you can initialize things. In different types of applications, the entry point varies in style but is always a good place to put your dependency injection code.

The process of bootstrapping the application is very simple. The target is to construct a Task-ListView, because that is the view class that acts as the resolution root of the application. Resolution roots are covered later in this chapter. In order to construct that class, you need aTaskList-Controller instance. But that class requires both an ITaskService and an IObjectMapper, so you instantiate classes for both—this is where you are committing to the implementations. The TaskServiceAdo, in turn, requires an ISettings implementation, so you commit to the ApplicationSettings, which is an adapter for the ConfigurationManager .NET Framework class. Figure 9-3 clarifies this with a class diagram.

Image

FIGURE 9-3 The interfaces, their implementations, and their dependencies, all of which make up the Task List application.

Each class requires one or more dependencies as sockets that are implemented by other classes that might also require dependencies. It is common for an implementation to be an adapter, such as the MapperAutoMapper and the ApplicationSettings classes. These simply fulfil the interface required of the dependency but delegate the actual work to another class. Even if the class is not an adapter, it is likely to have some dependencies of its own to which it delegates some of the work, like the TaskServiceAdo, which uses ADO .NET for the real retrieval of data. Other implementations of the ITaskService could get the task list from anywhere—a TaskServiceNHibernate class would be an alternative implementation that delegated much of the work to NHibernate. A TaskServiceOutlook class could depend on the Microsoft Outlook Add-In framework and read the tasks directly from the built-in task list of Outlook. It is imperative to note that, because the interface does not tie itself to any of these technologies, anything could be the source of tasks, assuming that it can fulfil the interface.

Poor Man’s DI is verbose. When this application is extended to support adding new tasks, editing tasks, or perhaps notifying of an imminent due date, it is clear that these few lines of construction code will grow significantly, to the point where they are no longer easily understood. However, Poor Man’s DI is flexible. Whatever complex object graph you want to construct, the way to construct it is obvious because there is only one way: manually creating instances of everything and passing them to classes that aggregate their functionality, repeating until you reach the resolution root. You can implement any number of decorators for the interfaces that each class depends on; Poor Man’s DI allows you to meticulously construct the resulting graph.

Method injection

The constructor isn’t the only option for providing dependencies to classes. Methods and properties can also be used, and they both have different use cases when compared to constructors.

Listing 9-5 shows part of the TaskListController that has been rewritten to furnish the ITaskService with its ISettings dependency as a parameter on the GetAllTasks method. This requires the interface for the method to be altered.

LISTING 9-5 The task service now accepts the settings as a method parameter instead of a constructor parameter.


public class TaskListController : INotifyPropertyChanged
{
public TaskListController(ITaskService taskService, IObjectMapper mapper, ISettings
settings
)
{
this.taskService = taskService;
this.mapper = mapper;
this.settings = settings;
}

public void OnLoad()
{
var taskDtos = taskService.GetAllTasks(settings);
AllTasks = new
ObservableCollection<TaskViewModel>(mapper.Map<IEnumerable<TaskViewModel>>(taskDtos));
}
}


This is useful when the method being called is the only one that requires the dependency. Constructor dependencies indicate that sufficient behavior in the class requires delegation to the dependency, but if only a small percentage of methods truly use the dependency, it might make more sense to pass it in to those methods specifically. The downside of method injection is that it requires the clients who call the method to “acquire” an instance of the dependency. They can do so either through a constructor parameter or through a method parameter that causes clients to pass the parameter down the call stack until it is used by the target class.

Property injection

Similar to method injection, property injection can be used to inject dependencies. Listing 9-6 refactors the prior example to show how the ITaskService could have its ISettings dependencies set by a property. Bear in mind that, again, the interface needs to be changed to support the property, not just the implementation.

LISTING 9-6 Dependency injection can also be accomplished via property injection.


public class TaskListController : INotifyPropertyChanged
{
public TaskListController(ITaskService taskService, IObjectMapper mapper, ISettings
settings
)
{
this.taskService = taskService;
this.mapper = mapper;
this.settings = settings;
}

public void OnLoad()
{
taskService.Settings = settings;
var taskDtos = taskService.GetAllTasks();
AllTasks = new
ObservableCollection<TaskViewModel>(mapper.Map<IEnumerable<TaskViewModel>>(taskDtos));
}
}


The benefit to this approach is that the instance property can be changed at run time. Whereas a constructor dependency is injected and that instance is used for the lifetime of the class, a property value can be replaced midway through the class’s lifetime.

Inversion of Control

Throughout this book, the examples have focused on developing classes that delegate to abstractions. These abstractions are then implemented by other classes, which delegate some work to more abstractions. Eventually, a class is so small and directed that it need not delegate any further, and the chain of dependency is ended. In order to construct the dependent classes, first their dependencies are constructed and then injected in as dependencies. You have learned how this dependency injection can be implemented by manually constructing classes and passing instances into the constructors. Though this elevates you from a situation in which dependent implementations cannot be swapped or decorated to one in which they can, the object graph is still constructed statically: which part goes where is known at compile time. Inversion of Control (IoC) allows you to defer this construction to run time.

IoC is most well known in the context of IoC containers. These systems allows you to link the interfaces of your application to their implementations and retrieve an instance of a class by resolving all of the dependencies.

The code in Listing 9-7 shows the application entry point rewritten to use the Unity IoC container. The first step is to instantiate a new UnityContainer instance. Note that when you are bootstrapping the IoC container like this, there is no alternative but to directly create instances of infrastructural components.

LISTING 9-7 With an IoC container, instead of manually constructing implementations, types are mapped to interfaces.


public partial class App : Application
{
private IUnityContainer container;
private void OnApplicationStartup(object sender, StartupEventArgs e)
{
CreateMappings();

container = new UnityContainer();
container.RegisterType<ISettings, ApplicationSettings>();
container.RegisterType<IObjectMapper, MapperAutoMapper>();
container.RegisterType<ITaskService, TaskServiceAdo>();
container.RegisterType<TaskListController>();
container.RegisterType<TaskListView>();

MainWindow = container.Resolve<TaskListView>();
MainWindow.Show();

((TaskListController)MainWindow.DataContext).OnLoad();
}

private void CreateMappings()
{
AutoMapper.Mapper.CreateMap<TaskDto, TaskViewModel>();
}

}


After the Unity container is created, you need to make it aware of each interface that will need to be resolved at some point during the application’s lifetime and map a concrete implementation to each interface. Whenever Unity encounters an interface, it will know which implementation it needs to resolve. If you fail to indicate which class to use for an interface, Unity will loudly remind you that it cannot instantiate interfaces.

After all registration is complete, you need to get an instance of your resolution root: the TaskListView. The Resolve method of the container will examine the constructor of this class and try to instantiate any dependencies by examining their constructors and trying to instantiate their dependencies, and so on down the chain. Eventually, when there are no more classes to instantiate, the Resolve method is able to call the constructors that it found by passing in the instances it has created so far. This is exactly the same process that you follow when using Poor Man’s DI, but with that approach you examine the constructors manually and instantiate the classes directly.

The Register, Resolve, Release pattern

All Inversion of Control containers reduce to a simple interface with only three methods, as shown in Listing 9-8. Unity is no exception to this and follows a similar pattern.

LISTING 9-8 Although each implementation will embellish it, this is the general interface for all IoC containers.


public interface IContainer : IDisposable
{
void Register<TInterface, TImplementation>()
where TImplementation : TInterface;

TImplementation Resolve<TInterface>();

void Release();
}


The purpose of each of the three methods is explained in the following list:

Image Register This method is called first, at application initialization. It will be called many times to register many different interfaces to their implementations. The where clause enforces the constraint that the TImplementation type must implement—that is, inherit the interface of—the TInterface type. Other permutations of this method allow you to register an already-constructed instance of a class and a type without a specific interface. (Such a type will be registered against all the interfaces it implements.)

Image Resolve This method is called during the running of the application. It is common for a particular family of classes to be resolved as the top-level object of the graph. For example, this would be the controllers in an ASP.NET Model-View-Controller (MVC) application, the viewmodels in a ViewModel-first WPF application, and the views in a Windows Forms Model-View-Presenter (MVP) application. The call to this method should be an infrastructural concern. That is, you should not call Resolve inside your application’s classes for controllers, views, presenters, services, domain, business logic, or data access.

Image Release At some point, the classes will no longer be needed and their resources can be released. This might happen at the end of the application, but it also could happen at a more opportune moment during the application’s lifetime. In a web scenario, for example, it is common for resources to live only per-request. Thus, Release could be called at the end of each request. This sort of object lifetime concern is discussed in more detail later.

Image Dispose Most IoC containers will implement the IDisposable interface, so it has been included in this reference interface, too. The Dispose method will be called once when the application is shut down. It is distinct from Release in that the Dispose call will clear out the internal dictionaries of the container so that it has no registrations and is unable to resolve anything.

The first IoC example (shown in Listing 9-7) can be rewritten so that all interaction with the container is encapsulated in a class. This moves the verbose registration code away from the code-behind in the WPF application. This is shown in Listing 9-9.

LISTING 9-9 The startup event handler delegates much of its work to a configuration class.


public partial class App : Application
{
private IocConfiguration ioc;

private void OnApplicationStartup(object sender, StartupEventArgs e)
{
CreateMappings();

ioc = new IocConfiguration();
ioc.Register();

MainWindow = ioc.Resolve();
MainWindow.Show();

((TaskListController)MainWindow.DataContext).OnLoad();
}

private void OnApplicationExit(object sender, ExitEventArgs e)
{
ioc.Release();
}

private void CreateMappings()
{
AutoMapper.Mapper.CreateMap<TaskDto, TaskViewModel>();
}
}


The entry point is now simpler than it was before, and the IoC registration has been moved to a dedicated class. Listing 9-10 shows this class for the Task List application. When the application exits, it calls the Release method, which you can hook into by registering a handler to the appropriate Application event.

LISTING 9-10 The configuration class has methods for all three phases of the Register, Resolve, Release pattern.


public class IocConfiguration
{

private readonly IUnityContainer container;
public IocConfiguration()
{
container = new UnityContainer();
}

public void Register()
{
container.RegisterType<ISettings, ApplicationSettings>();
container.RegisterType<IObjectMapper, MapperAutoMapper>();
container.RegisterType<ITaskService, TaskServiceAdo>();
container.RegisterType<TaskListController>();
container.RegisterType<TaskListView>();
}

public Window Resolve()
{
return container.Resolve<TaskListView>();
}

public void Release()
{
container.Dispose();
}
}


The Register method contains exactly the same code as before. As this method grows, however, it can be refactored into multiple methods and generally kept neater than it otherwise might be if it was contained in the application entry point.

The Resolve method returns a generic Window, which is a common resolution root for a WPF application. Specifically, the TaskListView is returned because it is the main window for your application. In other application types, such as ASP.NET MVC, there are often multiple resolution roots—one for each controller. The organization of the composition root for MVC and other applications is discussed later in this chapter.

Imperative vs. declarative registration

The registration code to this point has been written imperatively with procedural calls to methods on a container object. This gives you some advantages: it is easy to read, it is relatively succinct, and it provides a minimum of compile-time checking, such as protection against typographical errors. One disadvantage is that you are tying yourself to an implementation at compile time. If you want to swap out one of your implementations for an alternative, this requires a recompile of the code.

If, instead, you use declarative registration via XML, you can obviate the need for a recompile by moving the decision to configuration time. Listing 9-11 shows Unity’s support for XML registration.

LISTING 9-11 A section in the application configuration file can describe how interfaces should map to implementations.


<configuration>
<configSections>
<section name="unity"
type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection,
Microsoft.Practices.Unity.Configuration" />
</configSections>
<appSettings>
<add key="TaskDatabaseConnectionString" value="Data Source=(local);Initial
Catalog=TaskDatabase;Integrated Security=True;Application Name=Task List Editor" />
</appSettings>
<unity xmlns="http://schemas.microsoft.com/practices/2010/unity">
<typeAliases>
<typeAlias alias="ISettings" type="ServiceInterfaces.ISettings, ServiceInterfaces"
/>
<typeAlias alias="ApplicationSettings" type="UI.ApplicationSettings, UI" />
<typeAlias alias="IObjectMapper" type="ServiceInterfaces.IObjectMapper,
ServiceInterfaces" />
<typeAlias alias="MapperAutoMapper" type="UI.MapperAutoMapper, UI" />
<typeAlias alias="ITaskService" type="ServiceInterfaces.ITaskService,
ServiceInterfaces" />
<typeAlias alias="TaskServiceAdo" type="ServiceImplementations.TaskServiceAdo,
ServiceImplementations" />
<typeAlias alias="TaskListController" type="Controllers.TaskListController,
Controllers" />
<typeAlias alias="TaskListView" type="UI.TaskListView, UI" />
</typeAliases>
<container>
<register type="ISettings" mapTo="ApplicationSettings" />
<register type="IObjectMapper" mapTo="MapperAutoMapper" />
<register type="ITaskService" mapTo="TaskServiceAdo" />
</container>
</unity>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
</startup>
</configuration>


This XML is the content of the application configuration file for the WPF Task List. Adding a configuration section for Unity enables the typeAlias and container elements. The former is used to alias shorter names for longer types, which need to be specified by their assembly-qualified names so that Unity can find them at run time. After the types have been aliased, the latter section performs the same job as the Register method: mapping an interface to an implementation.

Some changes need to be made to the application entry point for Unity to read this XML configuration. Listing 9-12 shows that these changes are minimal.

LISTING 9-12 Now the registration phase involves passing the configuration section to the container.


public partial class App : Application
{
private IUnityContainer container;

private void OnApplicationStartup(object sender, StartupEventArgs e)
{
CreateMappings();

var section = (UnityConfigurationSection)ConfigurationManager.GetSection("unity");
container = new UnityContainer().LoadConfiguration(section);

MainWindow = container.Resolve<TaskListView>();
MainWindow.Show();

((TaskListController)MainWindow.DataContext).OnLoad();
}

private void CreateMappings()
{
AutoMapper.Mapper.CreateMap<TaskDto, TaskViewModel>();
}
}


Just two lines are required. First, you load the unity section from the configuration file by using the ConfigurationManager class. This is cast to the UnityConfigurationSection type so that it can be passed to the LoadConfiguration method of a newly instantiatedUnityContainer. After this, the container can be used, as before, to resolve the main window of the application.

Although declarative registration brings the benefit of configuration-time type mapping, it has significant drawbacks that make it impractical in many situations. The biggest problem is its verbosity. This small example is already a lot more typing than before, but this example is small. In some cases, the registration code could be a few times larger than this, or more. As XML, it would be even larger still. If a typographical error was made in any of the alias or registration sections, it would not be caught until run time, whereas such errors are caught by the compiler in procedural code.

The most compelling reason that declarative registration is suboptimal is that most IoC containers allow for a lot of variation in registration. This can include lambda factories, whereby a lambda method is provided to the registration method, to be called whenever the interface is resolved. Such procedural code is not possible in declarative XML.

Object lifetime

It is important to acknowledge that not every object in the application has an equal lifetime. That is, some objects might need to live longer than others. Of course, in the managed languages of .NET, there is no deterministic way to destroy an object, but you can ask it to relinquish its resources by calling the IDispose.Dispose() method, if it implements that interface.

For example, the TaskService from Listing 9-3 had a remaining code smell of manually creating a SqlConnection instance. This was left there because the lifetime of that connection could not be matched to that of the TaskService, which is created on application startup and exists for the duration of the application. If the SqlConnection was injected into the TaskService, as shown in Listing 9-13, it would live for the lifetime of the application. This does not mean, however, that the connection would be open for the duration, because opening the connection is a separate operation from its construction.

LISTING 9-13 Some resources have a lifetime that must be carefully managed.


private void OnApplicationStartup(object sender, StartupEventArgs e)
{
CreateMappings();

container = new UnityContainer();
container.RegisterType<ISettings, ApplicationSettings>();
container.RegisterType<IObjectMapper, MapperAutoMapper>();
container.RegisterType<ITaskService, TaskServiceAdo>(new InjectionFactory(c => new
TaskServiceAdo(new
SqlConnection(c.Resolve<ISettings>().GetSetting("TaskDatabaseConnectionString")))));
container.RegisterType<TaskListController>();
container.RegisterType<TaskListView>();

MainWindow = container.Resolve<TaskListView>();
MainWindow.Show();

((TaskListController)MainWindow.DataContext).OnLoad();
}
// . . .
public class TaskServiceAdo : ITaskService
{

private readonly IDbConnection connection;
public TaskServiceAdo(IDbConnection connection)
{
this.connection = connection;
}

public IEnumerable<TaskDto> GetAllTasks()
{
var allTasks = new List<TaskDto>();

using (connection)
{
connection.Open();

using (var transaction = connection.BeginTransaction())
{
var command = connection.CreateCommand();
command.Transaction = transaction;
command.CommandType = CommandType.StoredProcedure;
command.CommandText = "[dbo].[get_all_tasks]";

using (var reader =
command.ExecuteReader(CommandBehavior.CloseConnection))
{
while (reader.Read())
{
allTasks.Add(
new TaskDto
{
ID = reader.GetInt32(IDIndex),
Description = reader.GetString(DescriptionIndex),
Priority = reader.GetString(PriorityIndex),
DueDate = reader.GetDateTime(DueDateIndex),
Completed = reader.GetBoolean(CompletedIndex)
}
);
}
}
}
}

return allTasks;
}

}


The first change is made to the entry point, where an injection factory is used for constructing the service. This is a lambda expression that has access to the container for resolving parameters and returns a new instance of the service. The call to the ISettings service’s GetSettingsmethod has been moved to this injection factory to retrieve the connection string. This is passed to the SqlConnection constructor which, in turn, is passed to the service.

In the GetAllTasks() method, the presence of the using(connection) is problematic. This ensures that SqlConnection.Dispose() is called at the end of the using scope. After this call, the connection can no longer be used, yet you could feasibly call this method again.

Instead, what if the TaskServiceAdo implemented IDisposable and delegated its Dispose method to that of the connection? This is explored in Listing 9-14.

LISTING 9-14 The service implements IDisposable so that it can dispose of the connection.


public class TaskServiceAdo : ITaskService, IDisposable
{
public TaskServiceAdo(IDbConnection connection)
{
this.connection = connection;
}

public IEnumerable<TaskDto> GetAllTasks()
{
var allTasks = new List<TaskDto>();

connection.Open();

try
{
using (var transaction = connection.BeginTransaction())
{
var command = connection.CreateCommand();
command.Transaction = transaction;
command.CommandType = CommandType.StoredProcedure;
command.CommandText = "[dbo].[get_all_tasks]";

using (var reader =
command.ExecuteReader(CommandBehavior.CloseConnection))
{
while (reader.Read())
{
allTasks.Add(
new TaskDto
{
ID = reader.GetInt32(IDIndex),
Description = reader.GetString(DescriptionIndex),
Priority = reader.GetString(PriorityIndex),
DueDate = reader.GetDateTime(DueDateIndex),
Completed = reader.GetBoolean(CompletedIndex)
}
);
}
}
}
}
finally
{
connection.Close();
}

return allTasks;
}

public void Dispose()
{
connection.Dispose();
}
}


Instead of disposing the connection in the method, the connection is disposed of only when the service is disposed. This raises the important question of when the task service should be disposed. Should all of the task’s clients, which will receive ITaskService as a constructor parameter, also implement IDisposable? Who will dispose of these objects? Eventually, you would need to call Dispose() on something.

It is important to note that if a class is handed a dependency via its constructor, it should not manually dispose of the dependency itself. The class cannot guarantee that it has been given the one and only instance of the dependency; it might share it with others and therefore cannot dispose of it without potentially having a negative impact on other classes.

The answer to the question of how to manage the lifetime of objects when using dependency injection is much closer to how the service was originally implemented.

The connection factory

Recall that the Factory pattern is a way of replacing manual object instantiation with delegation to a class whose purpose is to create objects.

A connection factory could look something like the interface shown in Listing 9-15. This interface has been made slightly more general by returning the IDbConnection interface, rather than committing all of its clients to the SqlConnection class.

LISTING 9-15 The connection factory interface is very simple.


public interface IConnectionFactory
{
IDbConnection CreateConnection();
}


This interface will be injected into the task service so that you have a way of retrieving a connection without manually constructing it, keeping the service testable through mocking. Listing 9-16 shows the refactored service.

LISTING 9-16 Dependency injection can work in tandem with the Factory pattern.


public class TaskServiceAdo : ITaskService
{
private readonly IConnectionFactory connectionFactory;

public TaskServiceAdo(IConnectionFactory connectionFactory)
{
this.connectionFactory = connectionFactory;
}

public IEnumerable<TaskDto> GetAllTasks()
{
var allTasks = new List<TaskDto>();

using(var connection = connectionFactory.CreateConnection())
{
connection.Open();

using (var transaction = connection.BeginTransaction())
{
var command = connection.CreateCommand();
command.Transaction = transaction;
command.CommandType = CommandType.StoredProcedure;
command.CommandText = "[dbo].[get_all_tasks]";

using (var reader =
command.ExecuteReader(CommandBehavior.CloseConnection))
{
while (reader.Read())
{
allTasks.Add(
new TaskDto
{
ID = reader.GetInt32(IDIndex),
Description = reader.GetString(DescriptionIndex),
Priority = reader.GetString(PriorityIndex),
DueDate = reader.GetDateTime(DueDateIndex),
Completed = reader.GetBoolean(CompletedIndex)
}
);
}
}
}
}

return allTasks;
}
}


Note that the return value from the CreateConnection method is being disposed by the using block. This is viable in this instance, because the product from the factory implements IDisposable. Through interface inheritance, it is possible to enforce multiple interfaces on implementors.

However, the question must be asked whether every implementation will definitely need every interface. Sometimes they do, but given the wide variety of implementations that an interface can have—long after it was originally written—it is a big assumption to make. When it comes toIDisposable, I’m not sure it always applies.

The Responsible Owner pattern

Instead of artificially forcing the IDisposable interface onto every implementation, you can use it only on those that truly need it. This does cause a problem, though. If the product of the factory—your interface—does not implement IDisposable, you can no longer use a usingblock to neatly dispose of the product after it falls out of scope. In this case, you must use the Responsible Owner pattern.

Listing 9-17 shows that the using block can be replaced with a try/finally block, and that you can check at run time to find out whether the product implements the IDisposable interface.

LISTING 9-17 The Responsible Owner pattern ensures that resources are disposed of appropriately.


public IEnumerable<TaskDto> GetAllTasks()
{
var allTasks = new List<TaskDto>();

var connection = connectionFactory.CreateConnection();
try
{
connection.Open();

using (var transaction = connection.BeginTransaction())
{
var command = connection.CreateCommand();
command.Transaction = transaction;
command.CommandType = CommandType.StoredProcedure;
command.CommandText = "[dbo].[get_all_tasks]";

using (var reader = command.ExecuteReader(CommandBehavior.CloseConnection))
{
while (reader.Read())
{
allTasks.Add(
new TaskDto
{
ID = reader.GetInt32(IDIndex),
Description = reader.GetString(DescriptionIndex),
Priority = reader.GetString(PriorityIndex),
DueDate = reader.GetDateTime(DueDateIndex),
Completed = reader.GetBoolean(CompletedIndex)
}
);
}
}
}
}
finally
{
if(connection is IDisposable)
{
var disposableConnection = connection as IDisposable;
disposableConnection.Dispose();
}
}

return allTasks;
}


Only if the connection is of type IDisposable do you then attempt to call the Dispose method on it. This will work regardless of whether the product returned by the factory implements IDisposable or not, but if it does, it will correctly dispose of it, correctly cleaning up its resources.

The Responsible Owner pattern deterministically disposes of objects if they implement IDisposable. The pattern effectively ignores the objects if they do not implement IDisposable. However, SOLID code often results in multiple decorators that wrap around each other to add extra functionality. In this case, only if the top-layer object implements IDisposable will the Responsible Owner pattern function correctly. When the outer decorator does not implement IDisposable, but subsequent layers do, the Responsible Owner pattern will not correctly dispose of these instances. Instead, you must use the Factory Isolation pattern.

The Factory Isolation pattern

This pattern is able to deterministically dispose of the complex object graphs that often form as a result of SOLID code. It is named after the glove box isolators that are commonly found in laboratories. These are glass or metal boxes with integrated gloves to allow safe, protected access to the contents. In a similar fashion, the Factory Isolation pattern allows safe, protected access to an instance of an object that will be correctly disposed of after use.

The Factory Isolation pattern is only required when the target interface does not implement IDisposable. Extending the IDisposable interface burdens all implementations with the requirement that they implement a Dispose method, even in circumstances where this is unnecessary. Instead, IDisposable should be treated as an implementation detail and assigned to classes on an individual basis. This then leads naturally to the application of the Responsible Owner pattern and the Factory Isolation pattern.

The examples so far have all targeted the lifetime of the IDbConnection interface. Unfortunately, this interface extends the IDisposable interface. If, instead, the assumption is made that the target interface does not extend IDisposable, the client-side view of the Factory Isolation pattern would look like the code in Listing 9-18.

LISTING 9-18 An example of a client using the Factory Isolation pattern.


public IEnumerable<TaskDto> GetAllTasks()
{
var allTasks = new List<TaskDto>();
connectionFactory.With(connection =>
{
connection.Open();
using (var transaction = connection.BeginTransaction())
{
var command = connection.CreateCommand();
command.Transaction = transaction;
command.CommandType = CommandType.StoredProcedure;
command.CommandText = "[dbo].[get_all_tasks]";
using (var reader = command.ExecuteReader(CommandBehavior.CloseConnection))
{
while (reader.Read())
{
allTasks.Add(
new TaskDto
{
ID = reader.GetInt32(IDIndex),
Description = reader.GetString(DescriptionIndex),
Priority = reader.GetString(PriorityIndex),
DueDate = reader.GetDateTime(DueDateIndex),
Completed = reader.GetBoolean(CompletedIndex)
}
);
}
}
}
});

return allTasks;
}


The Factory Isolation pattern replaces the common Create method, which returns an instance of a factory product, instead providing a With method, which accepts a lambda method that has the factory product as a parameter.

The advantage here is that the lifetime of the factory product is explicitly linked to the lambda method’s scope. This succinctly communicates to the client that it is not in control of the product’s lifetime. The factory implementation itself is very simple, as shown in Listing 9-19.

LISTING 9-19 Creating an isolating factory is simple.


public class IsolationConnectionFactory : IConnectionIsolationFactory
{
public void With(Action<IDbConnection> do)
{
using(var connection = CreateConnection())
{
do(connection);
}
}
}


The With method is able to construct a florid object graph of decorators, adapters, and composites—just as SOLID suggests—and manage their lifetimes without the calling client concerning itself with anything but using the final product.

Note that it is possible to circumvent the Factory Isolation pattern by assigning the lambda-scoped product instance to a variable that has wider scope, so client code is discouraged from doing this.

Beyond simple injection

Dependency injection can be implemented in many different ways, by using a variety of different frameworks. Some patterns out there are benevolent, supporting and enhancing DI while reinforcing what it aims to accomplish. Other patterns do the opposite: they detract from the underlying purpose of DI, actively undermining it and detracting from the whole point.

Two such patterns are particularly insidious. The Service Locator anti-pattern is, unfortunately, all too common. It is used in many frameworks and libraries—sometimes, it is the only way to create a hook to use dependency injection. Worse than the Service Locator is an anti-pattern with an unfortunate moniker that I shall eschew in favor of something a bit more sanitized: Illegitimate Injection. This is a middle ground where dependency injection is used “sometimes,” allowing the construction of services, controllers, and similar entities without properly providing their dependencies.

When you are using DI, each type of application requires a different kind of setup. With each, you need to identify the composition root in order to correctly integrate your registration code. The location of the composition root in a WPF application differs from that of a Windows Forms application. Both will differ from that of an ASP.NET MVC application.

In advanced scenarios, the manual composition of classes through Poor Man’s DI and the individual registration of classes through an Inversion of Control container are both too laborious and verbose. By deferring registration to one or more conventions, you can eliminate a lot of boilerplate code but also provide some manual registration, to handle the edge cases when conventions do not suffice.

The Service Locator anti-pattern

Service locators look very similar to Inversion of Control containers, which is precisely why they are not always thought of as detrimental to the code. Listing 9-20 shows an example of the service locator provided by the Patterns and Practices team at Microsoft.

LISTING 9-20 The IServiceLocator interface appears to be just another IoC container.


public interface IServiceLocator : IServiceProvider
{
object GetInstance(Type serviceType);

object GetInstance(Type serviceType, string key);

IEnumerable<object> GetAllInstances(Type serviceType);

TService GetInstance<TService>();

TService GetInstance<TService>(string key);

IEnumerable<TService> GetAllInstances<TService>();
}


Note that methods such as TService GetInstance<TService>() could have been taken directly from the IUnityContainer interface—just by swapping the name for Resolve. The problem arises from how a service locator is used, thanks to the static ServiceLocatorclass, as shown in Listing 9-21.

LISTING 9-21 This static class is the cause of the anti-pattern.


/// <summary>
/// This class provides the ambient container for this application. If your
/// framework defines such an ambient container, use ServiceLocator.Current
/// to get it.
/// </summary>
public static class ServiceLocator
{
private static ServiceLocatorProvider currentProvider;

public static IServiceLocator Current
{
get { return currentProvider(); }
}

public static void SetLocatorProvider(ServiceLocatorProvider newProvider)
{
currentProvider = newProvider;
}
}


The class summary comment, which I have left in, hints toward the problem. The concept of an ambient container implies a leak of knowledge that a container exists. Although there is a laudable decoupling of the specific implementation of the service locator behind an interface, the problem is the acknowledgement—inside any class other than the composition root—of the service locator or container. Listing 9-22 shows how the TaskListController would look if it was rewritten to use the ServiceLocator.

LISTING 9-22 A service locator allows classes to retrieve anything at all, whether appropriate or not.


public class TaskListController : INotifyPropertyChanged
{
public void OnLoad()
{
var taskService = ServiceLocator.Current.GetInstance<ITaskService>();
var taskDtos = taskService.GetAllTasks();
var mapper = ServiceLocator.Current.GetInstance<IObjectMapper>();
AllTasks = new
ObservableCollection<TaskViewModel>(mapper.Map<IEnumerable<TaskViewModel>>(taskDtos));
}

public ObservableCollection<TaskViewModel> AllTasks
{
get
{
return allTasks;
}
set
{
allTasks = value;
PropertyChanged(this, new PropertyChangedEventArgs("AllTasks"));
}
}

public event PropertyChangedEventHandler PropertyChanged = delegate { };

private ObservableCollection<TaskViewModel> allTasks;
}


Now there is no constructor, nor is there constructor injection. Instead, when required, the class makes a call to the static ServiceLocator class and returns the service requested. Recall that static classes like this are skyhooks—a code smell.

Worse still, the class is able to retrieve anything and everything from the service locator. You are no longer following the “Hollywood Principle” of dependency injection: Don’t call us, we’ll call you. Instead, you are directly asking for the things you need, rather than having them handed to you. How can you tell what dependencies this class needs? With the service locator, you have to examine the code, searching for capricious calls that retrieve a required service. Constructor injection allowed you to view dependencies—all of them—with a glance at the constructor, or at a distance, via IntelliSense.

The problem is not necessarily one of unit testing. The service locator allows you to set an IServiceLocator implementation before use, which means that it can be mocked and the classes can be unit tested. At least it does not prevent that. It just seems absurd to register classes and map them to their interfaces—a not-insignificant task—only to pollute controllers, services, and other classes with infrastructural code such as this. It is doubly absurd when there is no problem to be solved—constructor injection did not need to be circumvented in this way.

An adapter for the service locator is provided for Unity. Listing 9-23 shows how this is registered after the mappings have been set up.

LISTING 9-23 The service locator will delegate directly to the UnityContainer instance to resolve instances.


private void OnApplicationStartup(object sender, StartupEventArgs e)
{
CreateMappings();

container = new UnityContainer();
container.RegisterType<ISettings, ApplicationSettings>();
container.RegisterType<IObjectMapper, MapperAutoMapper>();
container.RegisterType<ITaskService, TaskServiceAdo>();
container.RegisterType<TaskListController>();
container.RegisterType<TaskListView>();

ServiceLocator.SetLocatorProvider(() => new UnityServiceLocator(container));

MainWindow = container.Resolve<TaskListView>();
MainWindow.Show();

((TaskListController)MainWindow.DataContext).OnLoad();
}


This looks remarkably similar to the prior versions except for setting the locator provider. The call to Resolve, though, does not truly “resolve” the object graph; there are no longer any dependencies to inject into the TaskListView. They are all fetched individually as and when needed within the methods of the class.

The Service Locator anti-pattern is a good example of literal irony applied to a programming context, in that what is claimed is contrary to the reality. It is claimed that classes do not have dependencies, due to their default constructor, but that is simply not the case: they do have dependencies, otherwise you wouldn’t be trying to fetch them from a service locator!

Unfortunately, the service locator is sometimes an unavoidable anti-pattern. In some application types—particularly Windows Workflow Foundation—the infrastructure does not lend itself to constructor injection. In these cases, the only alternative is to use a service locator. This is better than not injecting dependencies at all. For all my vitriol against the (anti-)pattern, it is infinitely better than manually constructing dependencies. After all, it still enables those all-important extension points provided by interfaces that allow decorators, adapters, and similar benefits.

Injecting the container

Closely related to the service locator is the concept of injecting the container directly into a class. This, similarly, hands the class the keys to the safe, in that it is then free to retrieve anything that it wants from the container. Imagine such a class that, scattered throughout its many methods, retrieves a dozen services. Now compare it with a class that has a constructor that requires those dozen services and enforces their presence with up-front preconditions that throw exceptions if null references are passed in. Both of these classes are clearly doing too much—as indicated by the dependencies they require—and should be refactored into smaller classes or their dependencies grouped into meaningful decorators. However, only the latter makes it explicitly obvious at a glance that this smell exists.

Added to this, the class that requires the container as a constructor parameter must also reference the container’s assembly. This will proliferate infrastructural code throughout the entire codebase, because each class accepts the container in order to access the services it truly needs.

Illegitimate Injection

Illegitimate Injection looks much like normal, correctly implemented, dependency injection. There is a constructor that accepts dependencies, and these are provided either by Poor Man’s DI or an Inversion of Control container.

However, the pattern is polluted—indeed, fatally poisoned—by the presence of a second, default constructor. As Listing 9-24 shows, this second constructor proceeds to construct some implementations for the dependencies directly, circumventing DI.

LISTING 9-24 Having a constructor that directly references implementation negates some of the benefits of dependency injection.


public class TaskListController : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged = delegate { };

private readonly ITaskService taskService;
private readonly IObjectMapper mapper;
private ObservableCollection<TaskViewModel> allTasks;

public TaskListController(ITaskService taskService, IObjectMapper mapper)
{
this.taskService = taskService;
this.mapper = mapper;
}

public TaskListController()
{
this.taskService = new TaskServiceAdo(new ApplicationSettings());
this.mapper = new MapperAutoMapper();
}

public void OnLoad()
{
var taskDtos = taskService.GetAllTasks();
AllTasks = new
ObservableCollection<TaskViewModel>(mapper.Map<IEnumerable<TaskViewModel>>(taskDtos));
}

public ObservableCollection<TaskViewModel> AllTasks
{
get
{
return allTasks;
}
set
{
allTasks = value;
PropertyChanged(this, new PropertyChangedEventArgs("AllTasks"));
}
}

}


This means that this class must reference whichever assemblies the implementations are in and, concomitantly, all subsequent dependencies. This is the Entourage anti-pattern all over again. Although the first constructor, which accepts only interfaces, sets the scene for the Stairway pattern and well-mannered DI, the second, default constructor undermines this.

What happens when this “default” implementation is not what you want anymore? This class will be edited to construct the preferred class instead. What about when one default constructor is not enough and, in some scenarios, you want implementation A whereas in others, you want implementation B? That’s enough to make a person nauseous.

Sometimes this anti-pattern is used to support unit testing, with the defaults being mock implementations that do not have dependencies and that might reside local to this class. Classes should never contain anything that exists only to support unit testing. A common example of this sort of practice is converting private methods to internal and using the InternalsVisibleToAttribute to allow test assemblies to access these methods—rather than testing classes solely through their public interface. True, this might appear to be an arbitrarily fine line—after all, DI is much vaunted for its enabling of unit testing. But that is precisely the point: you have already enabled unit testing through the use of interfaces and their injection via the constructor. Mocks can, and should, be provided through that constructor.

It is worth noting that the classification of Illegitimate Injection as an anti-pattern does not hinge on the visibility of the constructor. Whether the constructor is public, protected, private, or internal, the outcome is the same: you are referencing implementations where you should not be.

The composition root

Only one location in an application should have any knowledge of dependency injection: the composition root. This is where classes are constructed when you are using Poor Man’s DI, or where interfaces and class mappings are registered when you are using an Inversion of Control container.

The ideal is for the composition root to be as close to the entry point of the application as possible. This allows you to bootstrap DI as soon as possible, gives you a recognized location to find the DI configuration, and helps you avoid leaking dependencies on the container throughout the application. It also means that for each application type there is a different composition root.

The resolution root

Closely related to the composition root is the resolution root. This is the object type that forms the root of the object graph to be resolved. As in the prior WPF examples, it could be that the resolution root is even a single instance, but it is more commonly a family of types unified by a common base.

In some cases, you will manually resolve the resolution root yourself, but some application types that facilitate dependency injection—like MVC—require you to register the mappings while the application resolves the roots itself.

ASP.NET MVC

MVC projects lend themselves very well to dependency injection via an IoC container. They have clearly defined resolution roots and composition roots, and they are extensible enough to support any library that you might need to integrate into the framework for IoC.

The resolution root of an MVC application is the controller. All requests from the browser are made to routes that map directly to methods—called actions—on a controller. As the request comes in, the MVC framework maps the URL to a controller name, finds the type to which this name corresponds, instantiates it, and then invokes the action on the instance. Figure 9-4 depicts this interaction in a UML sequence diagram.

Image

FIGURE 9-4 A UML sequence diagram showing how MVC constructs controllers via a factory.

When you are using IoC for dependency injection, the instantiation of the controller is, more accurately, the resolution of the controller. This means that you can easily follow the Register, Resolve, Release pattern, keeping the Resolve call down to the ideal minimum, which is in one place.

Listing 9-25 shows the composition root of an ASP.NET MVC user interface for the Task List application.

LISTING 9-25 The Application_Start method of the HttpApplication is a common composition root in web applications.


public class MvcApplication : HttpApplication
{
public static UnityContainer Container;

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

FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);

AutoMapper.Mapper.CreateMap<TaskDto, TaskViewModel>();

Container = new UnityContainer();
Container.RegisterType<ISettings, ApplicationSettings>();
Container.RegisterType<IObjectMapper, MapperAutoMapper>();
Container.RegisterType<ITaskService, TaskServiceAdo>();
Container.RegisterType<TaskViewModel>();
Container.RegisterType<TaskController>();

ControllerBuilder.Current.SetControllerFactory(new
UnityControllerFactory(Container));

}
}


Some of this code is boilerplate that is created by default when a new MVC application is created. This includes all of the MVC-specific initialization code, such as that for registering areas, filtering, routes, and bundles. This is all performed at the first opportunity—in theApplication_Start method. This method is called when the first request is made after the application has been started in IIS. It is located in the code-behind file of the Global.asax and contains the application-specific subclass of the HttpApplication class.

Other than for the MVC-specific TaskController class, the rest of the service interfaces and implementations have been reused. The previous TaskController was centered around WPF, so it could not be reused outside of that context. Instead, the new TaskController does much the same job—retrieving tasks and converting them to a more view-friendly format via the IObjectMapper—but inherits from an MVC base class for controllers. This cements it as a resolution root for the application, because it inherits from theSystem.Web.Mvc.Controller class. Listing 9-26 shows this new controller.

LISTING 9-26 This TaskController is a resolution root and has a constructor requiring dependencies.


public class TaskController : Controller
{
private readonly ITaskService taskService;
private readonly IObjectMapper mapper;

public TaskController(ITaskService taskService, IObjectMapper mapper)
{
this.taskService = taskService;
this.mapper = mapper;
}

public ActionResult List()
{
var taskDtos = taskService.GetAllTasks();
var taskViewModels = mapper.Map<IEnumerable<TaskViewModel>>(taskDtos);
return View(taskViewModels);
}
}


The List method is the action method that is called by the same view that renders all of the tasks. Just as in the WPF application, the controller first delegates to the ITaskService to retrieve the tasks, and then delegates to the IObjectMapper to convert the returned data transfer objects into viewmodels for use by the view.


Image Note

The same ViewModel that was used for WPF is used here, too. This is okay because the INotifyPropertyChanged interfaces is not strictly WPF-centric (it is located in the System.ComponentModel namespace). However, MVC does not care about that interface and will not respond to any events that are fired on the ViewModel. Furthermore, MVC allows you to decorate ViewModels with validation hints and other such attributes that are part of the MVC assemblies, so it is best to create MVC-specific ViewModels.


By default, MVC controllers are required to have public default constructors so that the framework can construct instances of them before calling an action method. But when you are using dependency injection, you need to have constructors that accept the interfaces of your required services. Luckily, MVC uses the Factory pattern for creating the controller and provides an extension point for you to provide your own implementation, as Listing 9-27 shows.

LISTING 9-27 MVC provides many extension points. Providing a custom controller factory facilitates DI.


public class UnityControllerFactory : DefaultControllerFactory
{
private readonly IUnityContainer container;

public UnityControllerFactory(IUnityContainer container)
{
this.container = container;
}

protected override IController GetControllerInstance(RequestContext requestContext,
Type controllerType)
{
if (controllerType != null)
{
var controller = container.Resolve(controllerType) as IController;
if (controller == null)
{
controller = base.GetControllerInstance(requestContext, controllerType);
}
if (controller != null)
return controller;
}
requestContext.HttpContext.Response.StatusCode = 404;
return null;
}
}


When you constructed the UnityControllerFactory in the Application_Start method, you passed in the container as a parameter. Here, as emphasized in bold, you can tell that the GetControllerInstance override uses the container’s Resolve method to create an instance of the requested controller by type. This is where the controller—the resolution root—is resolved, along with the rest of the object graph that might be required.

It is necessary to bear in mind the different lifetimes involved in this example. The IoC container is created, and mappings are registered, at application startup. The controllers, however, are resolved per request. As the request comes in, the controller is resolved, and as the request ends, the controller falls out of scope and is no longer used.

Windows Forms

In a Windows Forms application, bootstrapping dependency injection is more like that of a WPF application than an ASP.NET MVC application. The resolution root of both is the view, with the presenter or controller being passed in as a constructor parameter and the object graph proceeding from there.

Listing 9-28 shows the composition root of the Windows Forms front end for the Task List application. It is located in the Program class—in the Main method—which is the entry point of the application. As usual, it is important to try to keep the registration code as close to the entry point as possible.

LISTING 9-28 The Program class’s Main method is the entry point to the application and makes a good composition root.


static class Program
{
public static UnityContainer Container;

[STAThread]
static void Main()
{
AutoMapper.Mapper.CreateMap<TaskDto, TaskViewModel>();

Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);

Container = new UnityContainer();
Container.RegisterType<ISettings, ApplicationSettings>();
Container.RegisterType<IObjectMapper, MapperAutoMapper>();
Container.RegisterType<ITaskService, TaskServiceAdo>();
Container.RegisterType<TaskListController>();
Container.RegisterType<TaskListView>();

var mainForm = Container.Resolve<TaskListView>();
Application.Run(mainForm);
}
}


Note that, in this case, you are able to reuse not only the service implementations, but also the TaskListViewController because it doesn’t (yet) depend on anything wholly specific to WPF. Of course, in the future, it probably will, so it might be necessary to create a controller or presenter specifically to support the Windows Forms application.

The view in this application is very simple, in that the code-behind merely accepts the controller as a constructor parameter and initializes the data binding, as shown in Listing 9-29. When you are using the Model-View-Presenter pattern, the view implements an interface to which the presenter can manually delegate calls for setting data.

LISTING 9-29 This view uses data binding to set the retrieved task list to a data grid control.


public partial class TaskListView : Form
{
public TaskListView(TaskListController controller)
{
InitializeComponent();

controller.OnLoad();
this.taskListControllerBindingSource.DataSource = controller;
}
}


Without a framework to resolve your view for you, you must do it yourself before passing the form into the Application.Run method, which starts the Windows Forms application. This is only applicable if there is only one main view for the application, which is often the case in desktop applications. Dialog boxes and other child windows would be created via service calls from the controllers or presenters that are implemented by the view.

Convention over configuration

Registering by configuration involves painstakingly mapping interfaces to implementations. Aside from being time consuming, it is also verbose. Instead, you can use conventions to cut down on the amount of code written.

Conventions are instructions to the container that tell it how to automatically map interfaces to implementations. These instructions form the inputs to the container, in place of the registrations. Ideally, the container takes this input and processes it, with the output being exactly the same registrations that you would otherwise have done manually.


Image Note

The “over” here can be read as “instead of.” Thus, this topic is about convention instead of configuration.


Listing 9-30 shows how the continuing example could use convention over configuration for registering.

LISTING 9-30 The registration phase can be greatly simplified by using conventions.


private void OnApplicationStartup(object sender, StartupEventArgs e)
{
CreateMappings();

container = new UnityContainer();
container.RegisterTypes(
AllClasses.FromAssembliesInBasePath(),
WithMappings.FromMatchingInterface,
WithName.Default
);

MainWindow = container.Resolve<TaskListView>();
MainWindow.Show();

((TaskListController)MainWindow.DataContext).OnLoad();
}


The registrations have been replaced by a call to RegisterTypes, which is the method used to provide the container with instructions on how to find classes and map them to interfaces. The instructions provided in this example tell the container to:

Image Register all classes from the assemblies in the bin folder (which is the base path).

Image Map those classes to the interface that matches the name of the class. The convention here is that the Service implementation class would be registered against the IService interface.

Image Use the default to name the mapping when registering each mapping. This default is null, meaning that the mapping is unnamed.

As a result, the container will iterate through each public class in each assembly that is in the bin folder, find its implemented interfaces, and map it to the one that matches the class’s name (prefixed with an I, for Interface), without providing a name for the mapping. It is not hard to imagine that the resulting registration will be quite greedy, potentially registering more classes to interfaces than you usually would if you were registering manually. However, a more important concern is whether it correctly registers the classes you want to the correct interfaces. This is the new problem introduced by conventions.

The registration is undeniably simpler than its previous incarnation, but only insofar as it is shorter: less code. With registration by configuration, it was easy to comprehend which implementation was being used for each interface—and that they were definitely registered correctly.

The first parameter to RegisterTypes is a collection of the types to register. The AllClasses static class provides some helper methods for retrieving such a collection by using various common strategies. The second parameter requires a function that accepts a Type passed in from the collection in the first parameter—the implementation type—and returns a collection of Type instances to which it will be mapped—the interface types. The WithMappings static helper provides some methods that match this signature and use various strategies for finding appropriate interfaces to map to each type. The third parameter is another function, this time requiring that you return a name for the mapping for each type. The WithName static helper class provides two alternatives: Default, which always returns null (thus the mapping is unnamed), and TypeName, whereby the type’s name is used for the mapping name. This allows you to call Resolve<IService>("MyServiceImplementation") to retrieve the mapped type by its name.

Of course, with the parameters of this method being so general, you are at liberty to provide whatever methods match the signature so that you can tailor the convention to your needs. As Listing 9-31 shows, the crux of registering by convention is in the conventions that are used to find types, map them, and name them.

LISTING 9-31 Conventions can be tailored to your specifications.


public partial class App : Application
{
private void OnApplicationStartup(object sender, StartupEventArgs e)
{
CreateMappings();

container = new UnityContainer();
container.RegisterTypes(
AllClasses.FromAssembliesInBasePath().Where(type =>
type.Assembly.FullName.StartsWith(MatchingAssemblyPrefix)),
UserDefinedInterfaces,
WithName.Default
);

MainWindow = container.Resolve<TaskListView>();
MainWindow.Show();

((TaskListController)MainWindow.DataContext).OnLoad();
}

private IEnumerable<Type> UserDefinedInterfaces(Type implementingType)
{
return WithMappings.FromAllInterfaces(implementingType)
.Where(iface => iface.Assembly.FullName.StartsWith(MatchingAssemblyPrefix));
}
}


You start by retrieving all of the types from the assemblies in the bin folder again. But this time, you limit the acceptable assemblies by returning only those whose full name starts with a specific prefix string. It is common practice to use a dot notation for naming assemblies so that they match the top-level namespace that they contain. So Microsoft.Practices.Unity is the name of the DLL in which that namespace resides. If that assembly exists in your bin folder—and it is certain to if you are using Unity—you might want to omit it from the scan for types to map. A simple way to do this is to retrieve only those types that match the prefix of your own application. Instead of Microsoft, you would use something like MyBusiness or OurProject.

The second parameter has been replaced with a reference to your own local method, which matches the required signature. Given a Type, which is the implementation type, you need to return a collection of other types that represent the interfaces to map to. Rather than write anything particularly complex, you specialize WithMappings.FromAllInterfaces, which returns all of the interfaces that the type implements. This list could feasibly include interfaces that you really do not want to map to—INotifyPropertyChanged or IDataErrorInfo, for example. So again, you only return the interfaces that reside in assemblies that match your assembly prefix. This ensures that you map only your own types to your own interfaces.

Pros and cons

Much like Poor Man’s Dependency Injection and vanilla registration with an Inversion of Control container, using conventions involves a tradeoff. You have less code to write, but that code is more algorithmic than the declarative alternatives.

Conventions are initially harder to set up. If you are writing truly SOLID code, not everything will lend itself to a perfect one-to-one mapping of class to interface. In fact, if an interface only has one implementation, that is itself a code smell—and mocks for unit tests do not count toward that total. Whether they are adapters, decorators, or different strategies, it should be common to have more than one implementation per interface, making registration by convention that much more difficult. As it becomes more commonplace to have florid object graphs injected into classes, it becomes harder to devise a general rule by which classes and interfaces can be mapped to each other. Under such circumstances, the conventions cover only a small portion of the required registration code, rather than being the general case.

Mark Seemann, author of the excellent Dependency Injection in .NET (Manning Publications, 2011), has explored the three options available for DI and has arrived at the conclusion summarized by Figure 9-5. In brief, the tradeoffs are between two criteria: value and complexity. Value is a utilitarian measure of the worth of the option, ranging from pointless to valuable. Complexity measures the relative difficulty of the options, ranging from simple to sophisticated. As shown in the figure, all three options exist at different points of the bell curve. Poor Man’s DI is simple and valuable, whereas convention over configuration is sophisticated and valuable. The main difference between them, then, is that using conventions is more complex than manually constructing the classes and forming an object graph from those classes.

Image

FIGURE 9-5 The tradeoffs between the three options for dependency injection mapped on two axes.

Interestingly, Seemann considers manual registration to sit somewhere between simple and sophisticated on the complexity scale but claims that it is pointless on the utilitarian scale. Why is this? The main reason is because registering types manually with a container is weakly typed. If you try to construct a class and pass in an instance for one of its parameters that does not match the type required, the compiler will complain when you try to build. However, no such compile-time error is generated by an IoC container. Instead, you defer the error to run time, which causes you to enter an inefficient loop of write > compile > run > test. Not only that, but you have spent time and energy learning how to register mappings with the container, for little gain and some extra pain.

The choice seems simple: either Poor Man’s DI or conventions. If the project is simple and a limited amount of mappings will be required, Poor Man’s DI is as simple as can be: just construct the objects manually. If the project is likely to be more complex, requiring many interfaces and classes to be mapped together, target the majority of the registrations with conventions, with the rest of the more specialized mappings being manually registered.

I also highly recommend Mark Seemann’s blog, where he explores many topics and is always methodical in his approach1.

1 blog.ploeh.dk

Conclusion

Dependency injection is the glue that holds together every other facet of this book. Without DI, it would not be possible to focus so keenly on factoring dependencies out of classes and hiding their implementation behind general interfaces. Such extension points are key to the development of adaptive code and key to the steady progress of an application as it gains in size and complexity.

There are different options for the implementation of DI, each of which has its own place. Whether you use Poor Man’s DI or conventions (with some minimal manual mapping), having DI at all is more important than how it is accomplished.

Some common uses of DI are actually abuses that fit better into the category of code smell or anti-pattern. Service Locator and Illegitimate Injection are two abuses that negate some of the positive effects of properly implemented DI.

Each application type has a composition root and a resolution root, the identification of which help you understand how the classes should be organized to facilitate DI. The composition root is always very close to the entry point of the application, assuming that registration is an initialization concern. The resolution root is the only type of object that should be resolved. In some applications, there is only one instance of the resolution root, whereas in others, a family of different subclasses will be resolved.

For all its far-reaching effects, dependency injection is actually a deceptively simple pattern that is nonetheless powerful and misunderstood