Dependency injection in ASP .NET MVC with Autofac

Dependency injection (DI) is one form of inversion of control, which is a technique used to reduce coupling between components by replacing hard-coded dependencies with abstractions (usually interfaces) that are passed (injected) to the consuming component.

DI offers a number of benefits and encourages good practices that result in other benefits, such as:

  • Modularity: dependency injection practices favor a more modular application design.
  • Simplified Unit testing
  • Dynamic behavior: allows the changing of concrete implementations of services at runtime or compile time.
  • Scalability
  • Decoupling
  • Service life-cycle management: service containers can take care of the creation, sharing, and disposal of object instances when needed (i.e., we don’t need to call IDisposable.Dispose ourselves).

There are many CI containers out there, but today I will talk about one that I like in particular because it’s simple, flexible and light: Autofac. More specifically, I will show you how you can use it in your ASP .NET MVC projects.

We’ll start by creating an MVC project in Visual Studio (in this case, MVC 4). Choose the template that best suits your needs; in this example I chose the Basic template and I called it AutofacExample. Open the Package Manager Console and execute the following command to install Autofac for MVC 4:

Install-Package Autofac.Mvc4

(You can use the Manage NuGet Packages option, and then search for Autofac MVC4, if you’re more comfortable with the UI version.)

Suppose we already have a few business entities, including Customer. Let’s start by defining some simple services (interfaces and implementation).

using System.Collections.Generic;
using AutofacExample.Models;
 
namespace AutofacExample.Services
{
	public interface IRepository<T> where T : class
	{
		IEnumerable<T> All();
 
		T Get(int id);
 
		void Update(T entity);
 
		void Delete(int id);
	}
 
	public interface ICustomerRepository : IRepository<Customer>
	{
		IEnumerable<Receipt> GetReceipts(int customerId);
	}
 
	public class CustomerRepository : ICustomerRepository
	{
		public IEnumerable<Customer> All()
		{
			// Code goes here
		}
 
		public Customer Get(int id)
		{
			// Code goes here
		}
 
		public void Update(Customer entity)
		{
			// Some code
		}
 
		public void Delete(int id)
		{
			// Code goes here
		}
 
		public IEnumerable<Receipt> GetReceipts(int customerId)
		{
			// Code goes here
		}
	}
}

Next, in our MvcApplication class (in the Global.asax.cs file), we create a RegisterServices method, which we’ll invoke in Application_Start:

private static void RegisterServices()
{
	var builder = new ContainerBuilder();
	var assembly = Assembly.GetExecutingAssembly();

	// Tell autofac to scan the assembly and register all subclasses of System.Web.Mvc.Controller 
	builder.RegisterControllers(assembly);

	// Register repository, and expose it only through the ICustomerRepository interface
	builder.RegisterType<CustomerRepository>()
		.As<ICustomerRepository>().InstancePerHttpRequest();
 
	// Build the container and set it as the default dependency resolver
	var container = builder.Build();
	var resolver = new AutofacDependencyResolver(container);
	DependencyResolver.SetResolver(resolver);
}

(You will need to add using statements for Autofac and Autofac.Integration.Mvc.)

Notice we declared our repository’s lifetime as per HTTP request. This means that the container will dereference the instance after the request has completed so that it can be garbage-collected. If the service implements the IDisposable interface, the Dispose method will be invoked before the instance is released.

Finally, we can add a CustomerController (or use the default HomeController) to consume our newly created CustomerRepository, through its interface. The controller will declare a constructor dependency to ICustomerRepository and Autofac will take care of resolving and instantiating the dependencies and the controller itself.

using AutofacExample.Services;
using System.Web.Mvc;
 
namespace AutofacExample.Controllers
{
	public class CustomerController : Controller
	{
		private readonly ICustomerRepository _customerRepository;
 
		public CustomerController(ICustomerRepository customerRepository)
		{
			_customerRepository = customerRepository;
		}
 
		public ActionResult Index(int id)
		{
			var customer = _customerRepository.Get(id);
			return View(customer);
		}
	}
}

This is a ridiculously simple example, but in a real life application, dependencies would be nested in many levels. For example, our CustomerRepository could have a dependency to a DataService, which in turn may declare dependencies to other services. Autofac will kindly take care of all that mess and deliver what we ask for (as long as all objects involved are properly registered and configured).

Usually, an application may use many services and registering them one by one would be tedious and error prone. But if we use some naming standards for our services we can use assembly scanning and register many at once. For example:

var assembly = Assembly.GetExecutingAssembly();
// Assuming all repository names end with Repository
builder.RegisterAssemblyTypes(assembly)
	.Where(t => t.Name.EndsWith("Repository"))
	.AsImplementedInterfaces();

If you need more control over how a specific service is instantiated, you can specify it:

// Use the connection string named DefaultConnection
builder.Register(d => new Database("DefaultConnection"))
	.As<IDatabase>().InstancePerHttpRequest();

There are many more tips and tricks when using Autofac as your dependency injection container in ASP .NET MVC. Stay tuned.

One thought on “Dependency injection in ASP .NET MVC with Autofac

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s