Total votes: 0
Print: Print Article
Please login to rate or to leave a comment.
Published: 08 Oct 2010
This article will serve as an elementary tutorial to help you quickly get started with the lightweight and open sourced dependency injector for .NET applications - Ninject.
The main reason driving me to write this article is due to Balder - the famous 3D engine targeting
Silverlight game. As you may image, in the infrastructure of the Balder engine, Ninject is widely used. In
fact, in developing modern and large-scaled applications, especially underlining architectures, to create a
loosely-coupled, highly-cohesive, and flexible ones, some dependency inject frameworks are usually required
to come to help. Ninject is one of these; it mainly targets .NET based C# area.
So, this article will
serve as an elementary tutorial to help you quickly get started with the lightweight and open sourced
dependency injector for .NET applications - Ninject. And hence, we'll not touch anything upon Silverlight or
ASP.NET MVC, but merely on the simplest Console samples.
The development environments and tools we'll use in these series of articles
1. Windows XP Professional (SP3);
2. .NET 3.5 (currently Ninject 2.0 does not support .NET
3. Visual Studio 2010;
4. Ninject 2.0 for .NET 3.5
What is Dependency Inject?
Design patterns, especially structural ones, often aim to resolve dependencies between objects, changing
the dependence from upon the specific to on the abstract. In normal development, if we find clients rely on
an object, we will usually abstract them to form abstract classes or interfaces, so that the clients can get
rid of the dependence of the specific types.
In fact, something in the above process has been ignored -
who bears the responsibility to choose the specific types related to the abstract ones required by the
client? You will find, at most times, to create some types of models can more elegantly solve this problem.
But another problem arises: what if your design is not the specific business logic, but the public library or
framework of the program? At this time, you are a "service side," not that you call those structures, but
they send you the abstract type. How to pass the client the processed abstract type is another
Next, let's consider a simple example.
Suppose the client application needs an object
that can provide the System.DateTime type. After that, whenever it is needed, it only needs to abstract the
year part from it. So, the initial implementation may look like the following.
Listing 1: The initial solution
Later, for some reason, the developer finds .NET Framework comes with a date type precision
that is not enough, and needs to provide other sources of TimeProvider, to ensure accuracy in the different
functional modules with different TimeProviders. Thus, questions focus on the changes of the TimeProviders
that will affect client applications; but, in fact, the clients only require using the abstract method to
obtain the current time. To do this, we can add an abstract interface to ensure the clients depend only on
the interface TimeProvider. Because this part of the client application needs only accurate to the year, so
it can use a type called SystemTimeProvider. The new implementation is shown below.
Listing 2: The new implementation
This seems the client-side follow-up treatments all depend on the abstract SystemTimeProvider.
And, the problem seems solved? No, it should also know the specific ITimeProvider. Therefore, you also need
to add an object, which will choose a method of an instance of ITimeProvider passed to the client
application; the object can be called Assembler. The new structure is shown in Figure 1 below.
Figure 1: The new dependency relationships after adding the Assembler object
In conclusion, the Assembler's responsibilities are as
- Know the type of each specific TimeProviderImpl.
- According to the client's request, feed the abstract ITimeProvider back to the client.
- Also responsible for the creation of TimeProviderImpl.
Below is one of the possible implementations of the Assemble.
Listing 3: One possible implementation of the Assemble
Up till this point, you should no doubt realize the important role of the Assembler above. In
fact, as you may have doped out, Ninject just plays the role of the above Assembler and, of course, far more
Next, let's turn to the really interesting topic.
Why Select Ninject?
There are already several dependency injection libraries available in .NET circles. Then, why select
First, most of other frameworks heavily rely on XML configuration files to instruct the
framework on resolve the related components of your application. This may bring numerous
Second, most of the other frameworks often require you to add several assembly
dependencies to your project, which can possibly result in framework bloat. However, Ninject aims to keep
things simple and straightforward.
Third, by introducing an extremely powerful and flexible form of
binding -contextual binding, Ninject can be aware of the binding environment, and can change the
implementation for a given service during activation.
Injection Patterns in Ninject
Ninject 2.0 supports three patterns for injection: constructor injection, property injection, and method
injection. Next, let me introduce them by related examples one by one.
The most frequently-used type should be constructor injection. When activating an instance of a type,
Ninject will select one of the type's contructors by applying the following rules in order.
- If a constructor has an
[Inject] attribute, Ninject singles it out.
- If no constructors have an
[Inject] attribute, Ninject will select the one with the
most parameters that Ninject understands how to resolve.
- If no constructors are defined, Ninject will select the default parameterless constructor.
Next, let's take a related example.
Listing 4: Constructor injection in action
In the above code, the kernel plays the core role in the application. In most cases, we just
need to create an instance of the class StandardKernel with zero or more instances of the module
classes as the parameters. For this, please refer to the following definition of the constructor of the class
Listing 5: The constructors of the StandardKernel class
Next, to request an instance of a type (mostly abstract, such as an interface or abstract
class) from Ninject, we just need to call one of the related
Get() extension methods. Here we
used the following:
As for locating the corresponding concrete instance to be used inside the instance in the class
Soldier, this is accomplished in the module WarriorModule through various kinds of
Please notice that only one constructor can be marked with an
[Inject] attribute. Putting an
[Inject] attribute on more than one constructor will
result in Ninject throwing a NotSupportedException at the first time an instance of the type is
Moreover, in Ninject 2.0 the
[Inject] attribute can be left off completely.
So, most of your code doesn't need to be aware of the existence of Ninject. And, therefore, you won't need to
reference the Ninject related namespace/libraries, which is also most useful in the case that we cannot have
access to the target source code but still require injecting dependencies into it.
Figure 2: The running-time snapshot related to the constructor injection demo
Next, let's look at another kind of injection – property
To make a property injected you must annotate it with
[Inject]. Unlike the constructor
injection rule, you can decorate multiple properties with an
[Inject] attribute. However, the
order of property injection is not deterministic, which means there is no way to tell in which order Ninject
will inject their values in. Let's look at an example.
Listing 6: Property injection in action
In the above code, the property Weapon of the class Soldier is decorated with the annotation
[Inject]. So, in the Main function (the client-side application) by defining the bold line,
wherever the IWeapon interface appears it is identified as the concrete class
What's more, the module is not defined as the previous sample. In fact, in Ninject 2.0,
the modules become optional – we can directly register bindings (still using the
().To<T>() methods) directly on the kernel.
Of course, the running-time result is easy to
image. It is: Killed the foemen using Sword.
How about the method inject? It's also easy to
The following gives the method injection related key code.
Listing 7: Method injection in action
As you've seen, the method Arm is annotated with
[Inject] in the Soldier class.
So later, by invoking
kernel.Bind<IWeapon>().To<Gun>(); where the interface IWeapon
(usually called a service type) is depended upon ( in the method Arm ), the concrete class Gun (also named an
implementation type) is injected.
Also, above we've added the unbind test. This is more easily
implemented by calling
kernel.Unbind<IWeapon>();. After that, the service type IWeapon
becomes another concrete class – Sword.
Now, let's, as usual, look at the running-time snapshot, as
shown in Figure 3 below.
Figure 3: Method injection related demo’s output
With Ninject, the type bindings are typically collected into groups called modules, each of which
represents an independent part of the application. To create modules, you just need to implement the
INinjectModule interface. But, for simplicity, under most circumstances we should just extend the
NinjectModule class. You can create as many modules as you'd like, and pass them all to the kernel's
constructor. See the sample sketch below.
Listing 8: The multiple modules related sample sketch
That's it. Starting from the next section, let's continue to discuss some more advanced
Bind to Provider
What is a provider? Why do we mention it? Virtually, as you've already seen, the type binding plays a
significant role in Ninject. Rather than simply casting from one type to another, bindings are actually from
a service type to a provider. A provider is an object that can create instances of a specified type, which is
in some degree like a factory.
In Ninject 2.0, there are three built-in providers (defined in the
namespace Ninject.Activation.Providers): CallbackProvider, ConstantProvider, and StandardProvider, the most
important of which should be StandardProvider. In the previous example concerning the binding from IWeapon to
Sword, we in fact declared a binding from IWeapon to StandardProvider. All of the other related stuffs happen
behind the scenes; we at most time do not care about it. However, sometimes you might want to do some sort of
complex custom initialization to your objects, rather than letting Ninject work its magic. In this case, you
can create your own provider and bind directly to it. Let's create a related example, as shown in Listing 9
Listing 9: Create a custom provider
Please notice the bold lines in the above code. First, we've defined a generic custom provider
named SwordProvider<T>. In fact, the really important member is the
method. However, for simplicity, we did nothing special but return the Value property. The second
part of the bold lines is the most vital. As you no doubt have doped out, the functionality equals to the
following (at least in this sample):
Anyway, the custom provider do provide us a free place to do some sort of complex custom
initialization to our objects.
A lighter weight alternative to writing IProvider implementations is to bind a service to a delegate
method. Listing 10 gives a related sample.
Listing 10: A simplified method to implement a custom provider
The most interesting part should be the bold line. Here, I want to leave it to you to examine
Finally, let's switch to the most important binding – contextual binding related
One of the more powerful (and complex) features of Ninject is its contextual binding system. Up until this
point, we've only been talking about default bindings - bindings that are used unconditionally, in any
In this section, we are going to look at the contextual binding. First of all, please check
out the code below.
Listing 11: Several cases related to contextual binding
The above code gives three cases related to contextual binding. Please notice the bold lines
inside the three modules. In the ToConstantServiceModule module, we achieve the target of binding the service
(the interface ITester here) to the specified constant value. The second module SingletonServiceModule
defines a typical Singleton case. Note, In Ninject 2.0, the annotation
[Singleton] is no more
supported; instead, it suggests using the following new syntax:
Here, the class IocTester is defined as a Singleton.
Finally, in the third module
WithConstructorArgumentServiceModule, we defined a binding from ITester to IocTester, but required the
argument (in this case logger) of the constructor of the class IocTester should be overridden with the
specified value (an instance of the class FlatFileLogger here).
OK, there are still several more
contextual binding defined in Ninject. With these bindings, you can bring Ninject's power and flexibility
into full play. But the rest depond on you readers to continue digging.
About the Balder Engine and Ninject
As addressed previously, the motive drives me to write this article mainly results from the Balder engine.
In my experience, to gain a thorough understanding with the engine, you have to make clear most of the
details inside the Ninject framework. As you've known, the architecture design of the Balder engine depends
heavily upon Ninject. In the previous samples, I've only show you the textbox styled routine to utilize
Ninject, while in fact you can arm yourself with all you learn to reorganize your targets. Figure 4 indicates
the class diagram for the PlatformKernel class in Balder, which greatly enhances and simplifies the role of
StandKernal in Ninject.
Figure 4: The class diagram for the PlatformKernel class
Next, based upon the custom PlatformKernel class, Balder broke the above textbook-styled way to use
Ninject 2.0 in its own way. Listing 12 below gives one of the most important binding definitions in the the
Listing 12: Define required bindings in the PlatformKernel class constructor rather than in the
As said above, in Ninject 2.0 we can now register bindings directly on the kernel; modules
become optional. The above code also proves this, doesn't it?
Well, now you may also have understood
why I mentioned the Balder engine - to master Ninject and to put it into your real development, this article
is far from the real requirements – it just scratches the surface of it.
As pointed out at the beginning, this article mainly aims to serve as one of the most elementary tutorials
concerning the Ninject framework. In fact, there are far more than those covered here. So, in your later
application development, such as those related to WPF, Silverlight, ASP.NET MVC, etc. you should do more
research into Ninject. And it's not until then can it become your own Swiss army knife in your work.
I'm a college teacher and also a freelance developer and writer from WeiFang China, with more than fourteen years of experience in design, and development of various kinds of products and applications on Windows platform. My expertise is in Visual C++/Basic/C#, SQL Server 2000/2005/2008, PHP+MyS...
This author has published 81 articles on DotNetSlackers. View other articles or the complete profile here.
Please login to rate or to leave a comment.