Published: 09 Dec 2009
By: Manning Publications

In this article, an excerpt from the book "Dependency Injection in .NET", we will take a detailed look at the DI pattern known as Constructor Injection.

Contents [hide]

About the book

This is a sample chapter of the book Dependency Injection in .NET. It has been published with the exclusive permission of Manning.


Written by: Mark Seemann
Pages: 375
Publisher: Manning
ISBN: 9781935182504

Get 30% discount

DotNetSlacker readers can get 30% off the full print book or ebook at www.manning.com using the promo code dns30 at checkout.

Introduction

Dependency Injection (DI) is a technique and a set of design patterns that enable us to develop loosely coupled code. Instead of directly instantiating concrete classes whenever we need to invoke a particular service, we program against interfaces. Instances of these interfaces are injected into the code by the external client so that the code can vary independently of the Dependency.

Here we will take a detailed look at the DI pattern known as Constructor Injection. Since it is a design pattern, I have chosen to present it in the formal design pattern style.

How do we guarantee that a necessary Dependency is always available to the class we are currently developing?

By requiring all callers to supply the Dependency as a parameter to the class' constructor.

Figure 1: NeedyClass needs an instance of Dependency to work, so it requires any Client to supply an instance via its constructor. This guarantees that the instance is available to NeedyClass whenever it is needed.

NeedyClass needs an instance of 

Dependency to work, so it requires any Client to supply an instance via its constructor. This guarantees that the instance is available to NeedyClass whenever it is 

needed.

When a class requires an instance of a Dependency to work at all, we can supply that Dependency through the class' constructor, enabling it to store the reference for future (or immediate) use.

How it works

The class that needs the Dependency must expose a public constructor that takes an instance of the required Dependency as a constructor argument. In most cases, this should be the only available constructor. If more than one Dependency is needed, additional constructor arguments can be used.

Listing 1: A constructor injection

The Dependency (in listing A that would be the abstract DiscountRepository class) is a required constructor argument. Any client code that does not supply an instance of the Dependency simply cannot compile. However, since both interfaces and abstract classes are reference types, a caller can pass in null as an argument to make the calling code compile, so we need to protect the class against such misuse with a Guard Clause.

The combined efforts of the compiler and the Guard Clause guarantees that the constructor argument is valid if no exception is thrown, so at this point, the constructor can save the Dependency for future use without knowing anything about the real implementation.

It is good practice to mark the field holding the Dependency as readonly - this guarantees that once the initialization logic of the constructor has executed, the field cannot be modified. This is not strictly required from a DI point of view, but it protects you from accidentally modifying the field (such as setting it to null) somewhere else in the depending class' code.

When the constructor has returned, the new instance of the depending class is in a consistent state with a proper instance of its Dependency injected into it. Since it holds a reference to this Dependency it can use it as often as necessary from any of its other members. It does not need to test for null, because the instance is guaranteed to be present.

When to use it

Constructor Injection should be your default choice for DI. It addresses the most common scenario where a class requires one or more Dependencies, and no reasonable Local Defaults are available.

Constructor Injection addresses that scenario very well because it guarantees that the Dependency is present. If the depending class absolutely cannot function without the Dependency, that guarantee is valuable.

In cases where the local library can supply a good default implementation, Property Injection may be a better fit, but this is often not the case. In the earlier chapters, I have shown many examples of Repositories as Dependencies, and these are good examples of Dependencies where the local library can supply no good default implementation, since the proper implementations belong in specialized Data Access libraries.

Table 1: Constructor injection advantages and disadvantages

Advantages

Disadvantages

Injection is guaranteed

Requires up-front wiring of entire dependency graph

Easy to implement

-

Apart from the guaranteed injection already discussed, this pattern is also very easy to implement using the four steps implied by listing 4.1.

The main disadvantage to Constructor Injection is that it requires that the entire dependency graph is initialized immediately – often at application startup. We saw that in listing 3.4: to create the custom ControllerFactory, I have to create all of its Dependencies. One of these is a BasketDiscountPolicy, but the implementation I want to use has its own Dependency that also needs to be initialized. Even in this relatively simple example, I need to initialize six Dependencies before I can create a BasketController instance.

When we use a DI Container that supports Auto-wiring, this is not particularly difficult to define in code, but the actual act of initializing all these objects still takes time. Depending on how complex the dependency graph is, this may cause the application startup time to be slower than it otherwise would be.

Known use

Although Constructor Injection tends to be ubiquitous in applications employing DI, it is not very present in the .NET Base Class Library (BCL). This is mainly because the BCL is a set of libraries and not a full-fledged application.

Two related examples where we can see a sort of Constructor Injection in the BCL is with System.IO.StreamReader and System.IO.StreamWriter that both take a System.IO.Stream instance in their constructors. They also have a lot of overloaded constructors that take a file path instead of a Stream instance, but these are just convenience methods that internally create a FileStream based on the specified file path – here are all the StreamWriter constructors, but the StreamReader constructors are similar:

The Stream class is an abstract class that serves as an Abstraction upon which StreamWriter and StreamReader operates to perform their duties. You can supply any Stream implementation in their constructors and they will use it, but they will throw ArgumentNullExceptions if you try to slip them a null Stream.

While the BCL can provide us with examples where we can see Constructor Injection in use, it is always more instructive to see an example, so the next section walks you through a full implementation example.

Example: Adding a currency provider to the shopping basket

I would like to add a new feature to the sample commerce application I expanded in chapter 3 – namely the ability to perform currency conversions. I will spread the example throughout this chapter to demonstrate the different DI patterns in play, but when I'm done, the Home page should look like figure 2.

Figure 2: The sample commerce application with currency conversion implemented. The user can now select among three different currencies, and both product prices and basket totals will be displayed in that currency.

The sample commerce application 

with currency conversion implemented. The user can now select among three different currencies, and both product prices and basket totals will be displayed in that 

currency.

One of the first things we need is a CurrencyProvider – a Dependency that can provide us with the currencies we request. Let's define it like this:

The Currency class is another abstract class that provides conversion rates between itself and other currencies:

We need the currency conversion feature in both the HomeController and the BasketController, and since both implementations are quite similar, I will show you only the BasketController.

A CurrencyProvider is very likely to represent an out-of-process resource, such as a web service or a database that can supply conversion rates. This means that it would be most fitting to implement a concrete CurrencyProvider in a separate project (such as a Data Access library). Hence, there is no reasonable Local Default. At the same time, the BasketController class will need a CurrencyProvider to be present, so Constructor Injection is a good fit. Listing 2 shows how the CurrencyProvider Dependency is injected into the BasketController.

Listing 2: Injecting a CurrencyProvider into the BasketController

The BasketController class already had a Dependency on IBasketService, so I simply add the new CurrencyProvider Dependency as a second constructor argument and then follow the same sequence outlined in listing 1: Guard Clauses guarantee that the Dependencies are not null, which means it is safe to store them for later use in read-only fields.

Now that since the CurrencyProvider is guaranteed to be present in the BasketController, it can be used from anywhere within – for example in the Index method:

I haven't yet discussed the CurrencyProfileService, so for now, just know that it provides the current user's preferred currency code. In section 4.2.4 I will discuss the CurrencyProfileService in greater detail.

Given a currency code, the CurrencyProvider can be invoked to provide a Currency that represents that code. Notice that I can simply use the currencyProvider field without needing to check it in advance, because it is guaranteed to be present.

Now that I have the Currency, I can then proceed to perform the rest of the work in the Index method, but I have not yet shown that implementation. As we progress through this chapter, I will built on this method and add more currency conversion functionality along the way.

Related patterns

Constructor Injection is the most generally applicable DI pattern available, and also the easiest to implement correctly. It applies when the Dependency is required.

If we need to make the Dependency optional, we can change to Property Injection if we have a proper Local Default.

When the Dependency represents a Cross-Cutting Concern that should be potentially available to any module in the application, we can use an Ambient Context instead.

There is more than one way to implement DI in a single class, but Constructor Injection is a good default choice. It is simple to implement because we simply define the class' constructor so that it requires the Dependency as a constructor parameter. This forces all callers to supply the Dependency and helps enforce as an invariant that the Dependency has been supplied and is always available.

<<  Previous Article Continue reading and see our next or previous articles Next Article >>

About Manning Publications

Manning Publication publishes computer books for professionals--programmers, system administrators, designers, architects, managers and others. Our focus is on computing titles at professional levels. We care about the quality of our books. We work with our authors to coax out of them the best writi...

This author has published 33 articles on DotNetSlackers. View other articles or the complete profile here.

Other articles in this category


Introduction to StructureMap
Have you heard of StructureMap, generally know what it’s for, and want to know how to get started qu...
To mock or not to mock, that is the question – Part 1
This article gives a quick introduction in the usage of two of the most known mocking frameworks: Rh...
The Command Pattern
In this article I will provide a quick refresher on what the command pattern is used for, how it wor...
TypeMock’s Arrange-Act-Assert
Brian Mains discusses how to implement the Arrange-Act-Assert pattern in TypeMock.
Key Process Patterns
This article, based on chapter 2 of Specification by Example, presents effective patterns for softwa...

You might also be interested in the following related blog posts


How to Make crossdomain.xml Work with SharePoint read more
How to display data from different tables using one data source read more
12 ASP.NET MVC Best Practices read more
Postgresql - Day 2 read more
SharePoint 2010 Workflow read more
Formatting Text in RadControls for WinForms Q3 2009 read more
My History of Visual Studio (Part 9) read more
How do I deploy an application and its prerequisites? (Mary Lee) read more
Did you know about protocol-relative hyperlinks? read more
Avoid Entrenched Dependencies read more
Top
 
 
 

Please login to rate or to leave a comment.