C# .Net using Autofac in an MVC4 project

Autofac is a popular IoC container, it’s a little more complex to setup than some other containers available. I’ll describe how to do a simple setup to get up and running quickly.

If you’re new to IoC, it’s simply a mechanism for managing dependencies in your application, it’s now a hot topic in application development so it’s worth doing some research to familiarize yourself with the subject.

1) Create a new MVC4 solution in Visual Studio (2012 in this example).

2) Add the Autofac.MVC4 reference to your project, if you’re using nuget from the command line do:

install-package Autofac.MVC4

3) Add a new class AutofacScopeContainer.cs to your solution:

using System;
using System.Collections.Generic;
using  System.Web.Http.Dependencies;
using Autofac;
using Autofac.Integration.Mvc;

namespace CsharpAutofacDemo
{
    /// <summary>
    /// Autofac Scope Container
    /// </summary>
    public class AutofacScopeContainer : IDependencyScope
    {
        /// <summary>
        /// Private _container field
        /// </summary>
        private readonly AutofacDependencyResolver _container;

        /// <summary>
        /// Initializes a new instance of the <see cref="AutofacScopeContainer"/> class.
        /// </summary>
        /// <param name="container">The container.</param>
        /// <exception cref="System.ArgumentNullException">container</exception>
        protected AutofacScopeContainer(AutofacDependencyResolver container)
        {
            if (container == null)
            {
                throw new ArgumentNullException("container");
            }
            _container = container;
        }

        /// <summary>
        /// Retrieves a service from the scope.
        /// </summary>
        /// <param name="serviceType">The service to be retrieved.</param>
        /// <returns>
        /// The retrieved service.
        /// </returns>
        public object GetService(Type serviceType)
        {
            return _container.ApplicationContainer.IsRegistered(serviceType) ? _container.GetService(serviceType) : null;
        }

        /// <summary>
        /// Retrieves a collection of services from the scope.
        /// </summary>
        /// <param name="serviceType">The collection of services to be retrieved.</param>
        /// <returns>
        /// The retrieved collection of services.
        /// </returns>
        public IEnumerable<object> GetServices(Type serviceType)
        {
            return _container.ApplicationContainer.IsRegistered(serviceType) ? _container.GetServices(serviceType) : new List<object>();
        }

        /// <summary>
        /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
        /// </summary>
        public void Dispose()
        {
            _container.ApplicationContainer.Dispose();
        }

    }

    /// <summary>
    /// Auto FacContainer
    /// </summary>
    public class AutoFacContainer : AutofacScopeContainer, IDependencyResolver
    {
        /// <summary>
        /// Initializes a new instance of the <see cref="AutoFacContainer"/> class.
        /// </summary>
        /// <param name="container">The container.</param>
        public AutoFacContainer(AutofacDependencyResolver container)
            : base(container)
        {
        }

        /// <summary>
        /// Starts a resolution scope.
        /// </summary>
        /// <returns>
        /// The dependency scope.
        /// </returns>
        public IDependencyScope BeginScope()
        {
            return this;
        }
    }
}

4) Add a new class CustomerModel.cs to your solution:

namespace CsharpAutofacDemo.Models
{
    /// <summary>
    /// Customer class 
    /// </summary>
    public class Customer
    {
        public string CustomerId { get; set; }
        public string CustomerName { get; set; }
        public string CustomerAddress { get; set; }
        public string CustomerPhoneNumber { get; set; }
        public string CustomerEmail { get; set; }
    }
}

5) Add a new class CustomerRepository.cs to your solution:

using System.Collections.Generic;
using CsharpAutofacDemo.Models;

namespace CsharpAutofacDemo
{
    /// <summary>
    /// Customer details repository class
    /// </summary>
    public class CustomerRepository : ICustomerRepository
    {
        /// <summary>
        /// Get customer details.
        /// </summary>
        /// <returns></returns>
        public List<Customer> GetCustomerDetails()
        {
            // This is a simple implementation, others could use an ORM or Web service etc.
            
            var customers = new List<Customer>
                          {
                              new Customer()
                                  {
                                      CustomerId = "1",
                                      CustomerName = "Customer one",
                                      CustomerAddress = "Bristol",
                                      CustomerPhoneNumber = "0845000000",
                                      CustomerEmail = "[email protected]",
                                  },
                              new Customer()
                                  {
                                      CustomerId = "2",
                                      CustomerName = "Customer two",
                                      CustomerAddress = "Bath",
                                      CustomerPhoneNumber = "0845000001",
                                      CustomerEmail = "[email protected]",
                                  },
                              new Customer()
                                  {
                                      CustomerId = "3",
                                      CustomerName = "Customer three",
                                      CustomerAddress = "Swindon",
                                      CustomerPhoneNumber = "0845000003",
                                      CustomerEmail = "[email protected]",
                                  }
                          };

            return customers;
        }
    }
}

6) Add a new class ICustomerRepository.cs to your solution:

using System.Collections.Generic;
using CsharpAutofacDemo.Models;

namespace CsharpAutofacDemo
{
    /// <summary>
    /// ICustomerRepository interface
    /// </summary>
    public interface ICustomerRepository
    {
        List<Customer> GetCustomerDetails();
    }
}

7) Update your Global.asax.cs file:

using System.Web.Http;
using System.Web.Mvc;
using System.Web.Optimization;
using System.Web.Routing;
using Autofac;
using Autofac.Integration.Mvc;
using System.Web;

namespace CsharpAutofacDemo
{
    // Note: For instructions on enabling IIS6 or IIS7 classic mode, 
    // visit http://go.microsoft.com/?LinkId=9394801

    public class MvcApplication : HttpApplication
    {
        protected void Application_Start()
        {
            RegisterAutoFac(GlobalConfiguration.Configuration);

            AreaRegistration.RegisterAllAreas();
            WebApiConfig.Register(GlobalConfiguration.Configuration);
            FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
            RouteConfig.RegisterRoutes(RouteTable.Routes);
            BundleConfig.RegisterBundles(BundleTable.Bundles);
            AuthConfig.RegisterAuth();
        }

        void RegisterAutoFac(HttpConfiguration config)
        {
            // Setup the Container Builder
            var builder = new ContainerBuilder();

            // Register the controller in scope 
            builder.RegisterControllers(typeof(MvcApplication).Assembly);

            // Register types
            builder.RegisterType<CustomerRepository>().As<ICustomerRepository>();

            // Build the container
            var container = builder.Build();

            // Setup the dependency resolver
            DependencyResolver.SetResolver(new AutofacDependencyResolver(container));

            config.DependencyResolver = new AutoFacContainer(new AutofacDependencyResolver(container));
        }
    }
}

8) Update your HomeController.cs file:

using System.Web.Mvc;

namespace CsharpAutofacDemo.Controllers
{
    /// <summary>
    /// MVC Controller class
    /// </summary>
    public class HomeController : Controller
    {
        /// <summary>
        /// Private _container field
        /// </summary>
        private readonly ICustomerRepository _customerRepository;

        /// <summary>
        /// Initializes a new instance of the <see cref="HomeController"/> class.
        /// </summary>
        /// <param name="customerRepository">The customer repository.</param>
        public HomeController(ICustomerRepository customerRepository)
        {
            _customerRepository = customerRepository;
        }

        // GET: /Customer/

        /// <summary>
        /// Method for index action.
        /// </summary>
        /// <returns></returns>
        public ActionResult Index()
        {
            [email protected] AutofacDemo.Customer
            var customer = _customerRepository.GetCustomerDetails();

            // View Index.cshtml
            return View(customer);
        }


    }
}

9) Update your index.cs file:

@model  List<CsharpAutofacDemo.Models.Customer>

@{
    ViewBag.Title = "Index";
}
<h2>Index</h2>

@foreach (var customer in Model)
{
    <fieldset>
        <legend>Customer</legend>

        <div class="display-label">
            @Html.DisplayNameFor(model => customer.CustomerId)
        </div>
        <div class="display-field">
            @Html.DisplayFor(model => customer.CustomerId)
        </div>
        <div class="display-label">
            @Html.DisplayNameFor(model => customer.CustomerName)
        </div>
        <div class="display-field">
            @Html.DisplayFor(model => customer.CustomerName)
        </div>
        <div class="display-label">
            @Html.DisplayNameFor(model => customer.CustomerAddress)
        </div>
        <div class="display-field">
            @Html.DisplayFor(model => customer.CustomerAddress)
        </div>
        <div class="display-label">
            @Html.DisplayNameFor(model => customer.CustomerPhoneNumber)
        </div>
        <div class="display-field">
            @Html.DisplayFor(model => customer.CustomerPhoneNumber)
        </div>

        <div class="display-label">
            @Html.DisplayNameFor(model => customer.CustomerEmail)
        </div>
        <div class="display-field">
            @Html.DisplayFor(model => customer.CustomerEmail)
        </div>
    </fieldset>
    <br />
}

10) Build your project and run, you should see the view page with the customer data displayed.

2 thoughts on “C# .Net using Autofac in an MVC4 project”

  1. Nicely done CSharper (who is that masked man?)

    may I, as a mere beginning .NET padewan, ask the master some questions?

    – you’ve shown how to DI a controller constructor using autofac so that a Repository dependency is automatically provided. If we added a Unit Of Work (UoW) component between the controller and the repository then the Controller would depend on the UoW, and the UoW on the Repository. Obviously the controller constructor would change to reference the UoW and Autofac config would specify IUoW->UoW, but how would we specify the Repository dependency on the UoW? Is it as simple as adding it to the UoW constructor and making use of the existing Autofac-config, or is this feature limited to controllers only?

    – I’ve been taught by my betters to use DI/IoC, and this generally results in reduced coupling and improved testability. However can I ask what further gains are achieved by adding an IoC container such as Autofac?

    – how does it work with a class hierarchy? can we have default (or other) ctors on concrete classes with the full dependencies specified only on the base class?

    Ta. I’m off for a bath now: must be at my best tomorrow.

Leave a Reply

Your email address will not be published. Required fields are marked *