0% found this document useful (0 votes)
16 views14 pages

(Paper) Dependency Injection in C# With Ninject

This document provides a comprehensive guide on using the Ninject Dependency Injection framework in C#. It explains the concept of Dependency Injection, its benefits, and how to implement it step-by-step, including setting up Ninject, creating bindings, and managing dependencies. The guide emphasizes the importance of reducing hard-coded dependencies for improved flexibility, code quality, and unit testing capabilities.

Uploaded by

Ignacio Goicoa
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
16 views14 pages

(Paper) Dependency Injection in C# With Ninject

This document provides a comprehensive guide on using the Ninject Dependency Injection framework in C#. It explains the concept of Dependency Injection, its benefits, and how to implement it step-by-step, including setting up Ninject, creating bindings, and managing dependencies. The guide emphasizes the importance of reducing hard-coded dependencies for improved flexibility, code quality, and unit testing capabilities.

Uploaded by

Ignacio Goicoa
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 14

A step-by-step guide to using

Ninject for dependency


injection in C#
Christiaan Verwijs
Follow
Jul 28, 2012 ·

Recently, I’ve been trying out the Ninject Dependency


Injection framework. It’s amazing! In this post I would like
to give you some pointers on how to use it. I will also briefly
explain the purpose of Dependency Injection. For those
aching to play with some code rather than reading a lengthy
blog (for webforms or as a console application), check the
sourcecode repositories below.

What is dependency injection?


Dependency Injection (DI, wikipedia) is a design pattern
that reduces hard-coded dependencies between your classes
by injecting these dependencies at run-time, instead of
during design-time. Technically, Dependency Injection is a
mechanism that allows the implementation of another, more
high-level, design pattern called Inversion of Control
(IoC, wikipedia). The purpose of both patterns is to reduce
hard-coded dependencies (or ‘coupling’) between your
classes.
What are dependencies?
Suppose that you are building a web application that is
going to send e-mails to visitors that have entered a form. In
object-oriented code, it is important to separate
responsibilities. So you’ll probably end up with a class that
handles the form input (FormHandler) and a class that is
responsible for sending the e-mails (MailSender). The
MailHandler class looks like this:

public class MailSender


{
public void Send(string toAddress, string subject)
{
Console.WriteLine("Sending mail to [{0}] with subject
[{1}]", toAddress, subject);
}
}

If you don’t use Inversion of Control, your FormHandler


class will look like this:

public class FormHandler


{
public void Handle(string toAddress)
{
MailSender mailSender = new MailSender();
mailSender.Send(toAddress, "This is non-Ninject
example");
}
}

Although there’s nothing wrong with this code, it is creating


a dependency between the FormHandler and MailSender
classes. The dependency is created at line 5.
Using the New keyword in your code to instantiate a class
implies that you are creating a dependency. From a practical
point of view, you are telling your FormHandler class to use
a concrete implementation of the MailSender class.
There’s no flexibility. ‘But why’, you ask, ‘is this a bad
thing?’. Let’s take a look at some reasons …

Why are dependencies a bad


thing?
• You can’t use multiple implementations of the
MailSender class: If you write the code like shown
above, you will lose one of the benefits of object oriented
code. You can’t easily swap out the implementation of
MailSender with another implementation. Perhaps you
want to avoid sending real mails and log them instead for
a staging environment of your application. Or you want
to send mails in plaintext instead of with HTML. In these
cases, you can only change the implementation of
MailSender by changing the MailSender class and the
FormHandler classes. Bottom-line: you lose flexibility;

• It makes it easier to write sloppy code: If your


classes are tightly coupled, it will be more tempting to
mix up responsibilities. If you use Dependency Injection
(as you’ll see), you have to invest more time in coming up
with a good design for your classes and, specifically, their
interface. Therefore, using Inversion of Control or
Dependency Injection will improve the quality of code
because it makes it harder to cut corners;

• It makes unit testing (nearly) impossible: When


you’re writing unit tests for a class, you want to
test only the behavior of that particular class. If you
would write unit tests for the FormHandler, you’ll end up
testing the MailSender as well. After all, the MailSender
is used ‘under the hood’ of the Handle method, and
there’s no way to do anything about that. This makes
writing unit tests nearly impossible. If you are writing
unit tests, dependency injection is often required;

The bottom-line is that your FormHandler shouldn’t know


what concrete implementation of the MailSender is used.
What concrete implementation is used, should be
determined outside of your classes. That way, you can swap
out the MailSender with another implementation if the need
arises. If you are writing unit tests for the FormHandler, you
can swap out the MailSender class with a mocked version,
for example.

So, how do I get rid of


dependencies?
One way to do this is by using a Dependency Injection
framework, like Spring, Unityor Ninject. These frameworks
allow you to configure, separate from your classes, which
concrete implementations should be used. I prefer Ninject
because it is lightweight, easy to use and requires little
change in your code.

Step 1: Download Ninject


Go to the Ninject website and download the latest version
for the .NET platform you’re targeting. Take .NET 4.5 if you
are not sure. You can do this through NuGet in Visual
Studio. I still prefer the manual approach and put the
assembly (ninject.dll) in a folder in my solution called
\Assemblies.

Step 2: Preparing the code


Before diving into Ninject, the first thing we have to do is
rewrite our code to use Interfaces. This is required for
Dependency Injection, but is good practice anyways. An
interfaces is basically a contract between classes that force
one class to behave exactly as described by the interface. The
contract can be implemented by other implementations
(different class, same behavior). We create a very
straightforward interface for the MailSender class:

public interface IMailSender


{
void Send(string toAddress, string subject);
}
We also rewrite the MailSender class to implement the
IMailSender interface:

public class MailSender : IMailSender


{
public void Send(string toAddress, string subject)
{
Console.WriteLine("Sending mail to [{0}] with subject
[{1}]", toAddress, subject);
}
}

We’ve basically told C# that the concrete implementation of


our MailSender class follows the IMailSender interface (or
contract). It is now possible to create other concrete
implementations that follow the same interface but do
different things ‘under the hood’, for example:

public class MockMailSender : IMailSender


{
public void Send(string toAddress, string subject)
{
Console.WriteLine("Mocking mail to [{0}] with subject
[{1}]", toAddress, subject);
}
}

Right now, we can change which concrete implementation is


used by our FormHandler by rewriting the code where the
class is instantiated:
public class FormHandler
{
public void Handle(string toAddress)
{
IMailSender mailSender = new MockMailSender();
mailSender.Send(toAddress, "This is still a non-
Ninject example");
}
}

Of course, this already adds a lot of flexibility to our code, as


we can swap out which concrete implementation of
IMailService is used by changing line 5. Although C# will
now force you to implement the IMailSender interface to the
letter, your code will already improve a lot by using
interfaces. The next step is to implement manual
dependency injection to get rid of this codechange that is
required to change which implementation is used.

Step 3: Implementing manual


dependency injection
Before using Ninject to inject dependencies, it’s useful to do
it manually to understand the basics. Basically, we’re going
to pass the dependency in through the constructorof the
FormHandler class. This way, the code that is using the
FormHandler can determine which concrete
implementation of IMailSender to use:
public class FormHandler
{
private readonly IMailSender mailSender;

public FormHandler(IMailSender mailSender)


{
this.mailSender = mailSender;
}

public void Handle(string toAddress)


{
mailSender.Send(toAddress, "This is non-Ninject
example");
}

The code that creates our FormHandler has to pass in a


concrete implementation of IMailService. This means that
control is now inverted; instead of the FormHandler
deciding which implementation to use, the calling code
does. This is the whole point of Inversion of Control, of
which Dependency Injection is just one approach. The
calling code (the code that uses the FormHandler and now
controls the dependencies) looks like this:

class Program
{
static void Main(string[] args)
{
IMailSender mailSender = new MockMailSender();
FormHandler formHandler = new FormHandler(mailSender);
formHandler.Handle("[email protected]");

Console.ReadLine();
}
}
This is an example of manual dependency injection,
because we’re not relying on any framework to do the heavy
lifting for us. The above code is fine, and will work like a
charm. But this approach will become progressively harder
as the number of dependencies increases. After all, you’ll
have to add one constructor parameter for every new
dependency in the class you’re instantiating. This can be
quite infuriating. Therefore, we need a framework to take
care of this. This is where Ninject, or any other DI
framework, comes in.

Step 4: Implementing Ninject to


inject dependencies for us
Ninject is fairly extensive, but I’ll stick to the easiest (and
most often used) dependency injection, called constructor
injection. The nice thing about Ninject is that you don’t
have to change MailSender, IMailSender or FormHandler at
all. You do need to add a reference to the Ninject.dll
assembly in your project and create a separate class in your
project that Ninject uses to configure the dependencies at
run-time:
using Ninject.Modules;
using Ninject;

public class Bindings : NinjectModule


{
public override void Load()
{
Bind<IMailSender>().To<MockMailSender>();
}
}
The name of the class can be whatever you like; Ninject will
find it as long as it inherits from NinjectModule. Your
calling code (Program.cs) has to use Ninjectto determine
which concrete implementation to use:

using Ninject;

class Program
{
static void Main(string[] args)
{
var kernel = new StandardKernel();
kernel.Load(Assembly.GetExecutingAssembly());
var mailSender = kernel.Get<IMailSender>();

var formHandler = new FormHandler(mailSender);


formHandler.Handle("[email protected]");

Console.ReadLine();
}
}

When running this code, your console will say ‘Mocking mail
to ….’, which is also what we expected. The dependency
injection is working! The code is creating a Ninject
Kernel that resolves our entire chain of dependencies. We
tell Ninject to load the bindings from the executing
assembly. This is the most common scenario. In this case,
your Bindings class should live in one of the assemblies
included in your executing project. Practically speaking, this
means that your Bindings class will usually live in your
website, webservice, windows service, console application or
unit test project, as they are at the top of the chain of
executing code. For every chain / context (website, unit
tests, console) you can create a different Bindings class with
different configurations. For example, you can change the
Bindings class to use the MailSender wherever IMailSender
is used:

public class Bindings : NinjectModule


{
public override void Load()
{
Bind<IMailSender>().To<MailSender&gt;();
}
}

Running the same code will now result in your console


saying ‘Sending mail to …’ (and not the Mock version),
which is what we expected.

Step 5: More levels of


dependencies, and where the
magic truly shows
The above example works, but it doesn’t show the true
power of Ninject. When your project grows, and the number
of dependencies increases, Ninject will automatically figure
out which concrete implementations to pass into
constructors based on the Bindings. Suppose our
MailSender is going to call a separate class for logging
exceptions. Without dependency injection, our
FormHandler would now depend on the MailSender, which
in turn depends on the Logging class. So, your MailSender
class could look like this:

public class MailSender : IMailSender


{
private readonly ILogging logging;

public MailSender(ILogging logging)


{
this.logging = logging;
}

public void Send(string toAddress, string subject)


{
logging.Debug("Sending mail");
Console.WriteLine(string.Format("Sending mail to [{0}]
with subject [{1}]", toAddress, subject));
}
}

Your bindings will look like this:

public class Bindings : NinjectModule


{
public override void Load()
{
Bind<IMailSender>().To<MockMailSender>();
Bind<ILogging>().To<MockLogging>();
}
}

Now, if you call FormHandler from the console application,


two dependency injections will take place. The first one
we’ve already seen; we ask Ninject to give us a concrete
implementation of IMailService and pass it into the
constructor of FormHandler. When Ninject instantiates
MailSender, it understands that this class requires ILogging.
It will check its Bindings and load the concrete
implementation specified there automatically. The nice
thing is that if you forgot to add a configuration for ILogging
in the bindings, Ninject will throw a friendly exception
explaining what you have to do.

So, once you’ve set up the top level of the execution


hierarchy (in this example) by creating the Kernel, Ninject
will take care of the rest for you. This is a big difference from
most other Dependency Injection frameworks. They often
require code changes within all your classes with
dependencies.

Avoid Service Locator anti-


patterns
A mistake I initially made is that I used a container or IoC
manager as a Service Locator (another design pattern).
Basically, I created a class that lived as a singleton and was
called from all classes with dependencies to resolve the
dependency (IoCManager.Resolve()). Many Dependency
Injection frameworks facilitate this approach, like Unity.
This is a common strategy, but it causes a dependency on
the IoC container _itself_and is not necessary. The code I’ve
shown above works without any kind of custom Service
Locator pattern. In fact, the MailSender and FormHandler
classes have not changed since the manual injection
approach. For more information, see this or this blog.
Concluding thoughts
Dependency Injection is a difficult concept to grasp if you’ve
never used it before. Just give it a try, and you’ll see how
flexible it makes your code. Especially when you’re writing
unit tests you’ll quickly see the benefits. In that case, you can
easily swap in mock implementations of dependencies. If
anything, it makes your code a lot cleaner and sort of forces
you to write better code. And don’t forget to check
out Ninject’s website for far more advanced scenarios.

Check out the code for a simple console app here (Visual
Studio 2013):
https://bitbucket.org/cverwijs/examples.ninject

Or this code for a simple webapplication (Visual Studio


2013):
https://bitbucket.org/cverwijs/examples.ninject.webapp

The webapplication implements the same classes in a


Webforms context. Although there is no visible
functionality injected by Ninject, you can verify and follow
the injection by placing a breakpoint in Default.aspx.cs.
Injection is also possible for master pages and other pages,
but check the Ninject.Web documentation for that. The
bindings are configured in the
/App_start/NinjectWebCommon.cs.

You might also like