Skip to content

A really simple guide to getting started with Dependency Injection in ASP.NET MVC 3

This tutorial will walk you through creating a basic ASP.NET MVC 3 project that makes use of the new Dependency Injection (DI) features whilst explaining why you might want to use it, even in small applications.

The code for this post can be found on GitHub: ASP.NET MVC 3 Dependency Injection Demo.

First we need to consider our solution structure.  I like to split my solution into three projects.  My MVC3 Web Application and two class libraries: Core and Data.  Core will define our domain and business logic.  Data will provide data access classes and any services needed.  With the three projects created, add a project reference to Core from the Data project.  Add references to both Core and Data from the Web project.

At this stage we will also grab ourselves a Dependency Resolver.  I like to to use Ninject as it’s incredibly simple (there are many, many others out there). To install Ninject I use the NuGet package manager in Visual Studio (if you’re new to NuGet go read up on it and use it, it’s awesome!).  Right click on your web project and select ‘Manage NuGet packages…’.  In the search box type ‘Ninject’ and select the Ninject.MVC3 package.  This gives us both the Ninject core library and some wiring to make it work in an MVC3 project out of the box.

Now we have our project setup, let’s start writing some code!

To use Dependency Injection you first write a service contract (an Interface in .NET).  You then create an implementation of the service that fulfills that contract.  That sounds a little scary, so let’s see an example.

In your Core project create a new file called IMessagingService and enter:

public interface IMessagingService 
{ 
    void Send(string message); 
}

Now in your Data project create a new file called EmailService (don’t forget to import your Core project’s namespace) and enter:

public EmailService : IMessagingService 
{ 
    public void Send(string message)
    { 
        // send the message 
    } 
}

See, not so scary.  In a normal application you would have written EmailService anyway, all we’ve done is make a note of the public methods and put them in an interface.

Next we need to tell Ninject about our service and it’s implementation.  In the Web project you should have an App_Start folder, inside you’ll find NinjectMVC3.cs.  Open up that file.  At the bottom there is an empty method called RegisterServices.  This is where we wire things up.  Change the method so that it reads:

private static void RegisterServices(IKernel kernel)
{ 
    kernel.Bind<IMessagingService>().To<EmailService>(); 
}

You’ll need to import both your Core and Data namespaces at the top of the file.  Now we’re ready to use our service!

In a traditional project when you wanted to send an email you’d have probably have written controller code a little like this:

public ActionResult SendMessage(string message)
{ 
    var emailSvc = new EmailService();  
    emailSvc.Send(message); 
    return RedirectToAction("Index"); 
}

This tightly couples our web project to using EmailService to send messages and makes it very hard to test our controller independently of EmailService and without sending emails every time our tests run.  Dependency Injection breaks that coupling, allowing us to swap out the implementation and makes our code far more testable.  Let’s see the controller re-written to use DI:

public class HomeController
{ 
    private IMessagingService messageSvc;  

    public HomeController(IMessagingService msg)
    { 
        this.messageSvc = msg; 
    } 

    public ActionResult SendMessage(string message)
    { 
        this.messageSvc.Send(message); 
        return RedirectToAction("Index"); 
    }

Notice how at no point do we refer to the actual EmailService class.  The dependency resolution bits of the MVC3 framework and Ninject work their magic and link everything up.  If you want to understand how that magic happens, here’s Micrsoft’s guide.  With our new clean controller we can now do two things.  First, we can swap out the messaging service by simply changing the NinjectMVC3.cs file in App_Start (more below).  Second, we can easily unit test our controller by passing in a mock messaging implementation.

Changing the implementation

We’ve nearly finished lovingly creating our web application and it’s busy sending email messages at key points then the client/boss comes in and says there’s been a change of plan – messages should instead be inserted into a CRM system using an HTTP API.  What do you do now?  Well, if your application was written without DI you’ll need to write a new service to send messages to the CRM system and then find every reference to the email and update it.  If you’ve written your app with DI you only need to write the new service and update one line in your config file:

public class CRMService : IMessagingService 
{ 
    public void Send(string message)
    { 
        // Send 
    } 
}

and

kernel.Bind<IMessagingService>().To<CRMService>();

Now that was much easier, wasn’t it?  But what if that pesky boss or client comes back and says “actually, what we want is for the message to be sent by email AND appear in the CRM system”.  D’oh!  But don’t worry, DI can help us here too.

Dependency Resolution doesn’t have to yield just one result, it can return an array of implementations.  With a couple small changes we can have  our application sending messages all over the place to wherever the client/boss thinks of next week!  Let’s see how:

First, we provide two bindings:

kernel.Bind<IMessagingService>().To<EmailService>();
kernel.Bind<IMessagingService>().To<CRMService>();

Next, we need to alter our controller to accept an array of implementations:

private IMessagingService[] messageSvc;

public HomeDIMultiController(IMessagingService[] msg)
{ 
    this.messageSvc = msg; 
}

Finally, we dispatch the Send method on each of our implementations:

foreach(var svc in this.messageSvc)
{ 
    svc.Send(message);  
}

With this new structure in place we can easily respond to the changing whims of our overlords by adding or removing message destinations by simply adding or removing lines from NinjectMVC3.cs  Awesome, eh?

I hope that’s given you a feel for DI, how it’s not really this big scary enterprisey thing and convinced you to give it a go on your next project!