Ninject Patterns and Anti-patterns

Exclusive offer: get 50% off this eBook here
Mastering Ninject for Dependency Injection

Mastering Ninject for Dependency Injection — Save 50%

Learn how Ninject facilitates the implementation of dependency injection to solve common design problems of real-life applications with this book and ebook

$19.99    $10.00
by Daniel Baharestani | September 2013 | Open Source

In this article, by Daniel Baharestani, the author of Mastering Ninject for Dependency Injection, we will learn how Ninject facilitates the implementation of Dependency Injection to solve common design problems of real-life applications in a simple and easy-to-understand format. It will teach you everything you need in order to implement Dependency Injection using Ninject in a real-life project.

(For more resources related to this topic, see here.)

Dependencies can be injected in a consumer class using different patterns and injecting them into a constructor is just one of them. While there are some patterns that can be followed for injecting dependencies, there are also some patterns that are recommended to be avoided, as they usually lead to undesirable results. In this article, we will examine only those patterns and antipatterns that are somehow relevant to Ninject features.

Constructor Injection

Constructor Injection is the most common and recommended pattern for injecting dependencies in a class. Generally this pattern should always be used as the primary injection pattern unless we have to use other ones. In this pattern, a list of all class dependencies should be introduced in the constructor.

The question is what if the class has more than one constructor. Although Ninject's strategy for selecting constructor is customizable, its default behavior is selecting the constructor with more parameters, provided all of them are resolvable by Ninject. So, although in the following code the second constructor introduces more parameters, Ninject will select the first one if it cannot resolve IService2 and it will even use the default constructor if IService1 is not registered either. But if both dependencies are registered and resolvable, Ninject will select the second constructor because it has more parameters:

public class Consumer { private readonly IService1 dependency1; private readonly IService2 dependency2; public Consumer(IService1 dependency1) { this.dependency1 = dependency1; } public Consumer(IService1 dependency1, IService2 dependency2) { this.dependency1 = dependency1; this.dependency2 = dependency2; } }

If the preceding class had another constructor with two resolvable parameters, Ninject would throw an ActivationException exception notifying that several constructors had the same priority.

There are two approaches to override this default behavior and explicitly select a constructor. The first approach is to indicate the desired constructor in a binding as follows:

Bind<Consumer>().ToConstructor(arg => new Consumer(arg.Inject<IService1>()));

In the preceding example, we explicitly selected the first constructor. Using the Inject<T> method that the arg argument provides, we requested Ninject to resolve IService1 in order to be injected into the specified constructor.

The second method is to indicate the desired constructor using the [Inject] attribute:

[Inject] public Consumer(IService1 dependency1) { this.dependency1 = dependency1; }

In the preceding example, we applied the Ninject's [Inject] attribute on the first constructor to explicitly specify that we need to initialize the class by injecting dependencies into this constructor; even though the second constructor has more parameters and the default strategy of Ninject would be to select the second one. Note that applying this attribute on more than one constructor will result in the ActivationException.

Ninject is highly customizable and it is even possible to substitute the default [Inject] attribute with another one, so that we don't need to add reference to the Ninject library from our consumer classes just because of an attribute:

kernel.Settings.Set("InjectAttribute",typeof(MyAttribute));

Initializer methods and properties

Apart from constructor injection, Ninject supports the injection of dependencies using initializer methods and property setters. We can specify as many methods and properties as required using the [Inject] attribute to inject dependencies. Although the dependencies will be injected to them as soon as the class is constructed, it is not possible to predict in which order they will receive their dependencies. The following code shows how to specify a property for injection:

[Inject]
public IService Service
{
get { return dependency; }
set { dependency = value; }
}

Here is an example of injecting dependencies using an injector method:

[Inject]
public void Setup(IService dependency)
{
this.dependency = dependency;
}

Note that only public members and constructors will be injected and even the internals will be ignored unless Ninject is configured to inject nonpublic members.

In Constructor Injection, the constructor is a single point where we can consume all of the dependencies as soon as the class is activated. But when we use initializer methods the dependencies will be injected via multiple points in an unpredictable order, so we cannot decide in which method all of the dependencies will be ready to consume. In order to solve this problem, Ninject offers the IInitializable interface. This interface has an Initialize method which will be called once all of the dependencies have been injected:

public class Consumer:IInitializable
{
private IService1 dependency1;
private IService2 dependency2;
[Inject]
public IService Service1
{
get { return dependency1; }
set { dependency1 = value; }
}
[Inject]
public IService Service2
{
get { return dependency2; }
set { dependency2 = value; }
}
public void Initialize()
{
// Consume all dependencies here
}
}

Although Ninject supports injection using properties and methods, Constructor Injection should be the superior approach. First of all, Constructor Injection makes the class more reusable, because a list of all class dependencies are visible, while in the initializer property or method the user of the class should investigate all of the class members or go through the class documentations (if any), to discover its dependencies.

Initialization of the class is easier while using Constructor Injection because all the dependencies get injected at the same time and we can easily consume them at the same place where the constructor initializes the class. As we have seen in the preceding examples the only case where the backing fields could be readonly was in the Constructor Injection scenario. As the readonly fields are initializable only in the constructor, we need to make them writable to be able to use initializer methods and properties. This can lead to potential mutation of backing fields.

Service Locator

Service Locator is a design pattern introduced by Martin Fowler regarding which there have been some controversies. Although it can be useful in particular circumstances, it is generally considered as an antipattern and preferably should be avoided. Ninject can easily be misused as a Service Locator if we are not familiar to this pattern. The following example demonstrates misusing the Ninject kernel as a Service Locator rather than a DI container:

public class Consumer
{
public void Consume()
{
var kernel = new StandardKernel();
var depenency1 = kernel.Get<IService1>();
var depenency2 = kernel.Get<IService2>();
...
}
}

There are two significant downsides with the preceding code. The first one is that although we are using a DI container, we are not at all implementing DI. The class is tied to the Ninject kernel while it is not really a dependency of this class. This class and all of its prospective consumers will always have to drag their unnecessary dependency on the kernel object and Ninject library. On the other hand, the real dependencies of class (IService1 and IService2) are invisible from the consumers, and this reduces its reusability. Even if we change the design of this class to the following one, the problems still exist:

public class Consumer
{
private readonly IKernel kernel;
public Consumer(IKernel kernel)
{
this.kernel = kernel;
}
public void Consume()
{
var depenency1 = kernel.Get<IService1>();
var depenency2 = kernel.Get<IService2>();
...
}
}

The preceding class still depends on the Ninject library while it doesn't have to and its actual dependencies are still invisible to its consumers. It can easily be refactored using the Constructor Injection pattern:

public Consumer(IService1 dependency1, IService2 dependency2)
{
this.dependency1 = dependency1;
this.dependency2 = dependency2;
}

Summary

In this article we studied the most common DI patterns and anti-patterns related to Ninject.

Resources for Article:


Further resources on this subject:


Mastering Ninject for Dependency Injection Learn how Ninject facilitates the implementation of dependency injection to solve common design problems of real-life applications with this book and ebook
Published: September 2013
eBook Price: $19.99
Book Price: $32.99
See more
Select your format and quantity:

About the Author :


Daniel Baharestani

Daniel Baharestani is an experienced IT professional living in Australia. He has over 10 years of professional experience in design and development of enterprise applications, mostly focused on Microsoft technologies and holds a B.Sc in software engineering. Daniel is currently working at 3P Learning, which is a global leader in online learning with its flagship platform, Mathletics—used by more than 4 million students worldwide.

For further details you can visit his website at http://baharestani.com.

Books From Packt


JBoss Weld CDI for Java Platform
JBoss Weld CDI for Java Platform

Java EE 6 with GlassFish 3 Application Server
Java EE 6 with GlassFish 3 Application Server

 Java EE 5 Development using GlassFish Application Server
Java EE 5 Development using GlassFish Application Server

 Instant Dependency Management with RequireJS How-to [Instant]
Instant Dependency Management with RequireJS How-to [Instant]

Instant Testing with CasperJS [Instant]
Instant Testing with CasperJS [Instant]

Java EE 5 Development with NetBeans 6
Java EE 5 Development with NetBeans 6

GlassFish Administration
GlassFish Administration

Ext JS 4 Plugin and Extension Development
Ext JS 4 Plugin and Extension Development


No votes yet

Post new comment

CAPTCHA
This question is for testing whether you are a human visitor and to prevent automated spam submissions.
B
k
L
U
T
9
Enter the code without spaces and pay attention to upper/lower case.
Code Download and Errata
Packt Anytime, Anywhere
Register Books
Print Upgrades
eBook Downloads
Video Support
Contact Us
Awards Voting Nominations Previous Winners
Judges Open Source CMS Hall Of Fame CMS Most Promising Open Source Project Open Source E-Commerce Applications Open Source JavaScript Library Open Source Graphics Software
Resources
Open Source CMS Hall Of Fame CMS Most Promising Open Source Project Open Source E-Commerce Applications Open Source JavaScript Library Open Source Graphics Software