Skip to content
alexmg edited this page Jan 22, 2014 · 1 revision

Integrating with ASP.NET MVC 4.0.

Earlier Versions

Autofac is always kept up to date to support the latest version of ASP.NET MVC. If you are using an older version of Autofac and need documentation on how to integrate with older versions of ASP.NET MVC, you can refer to these pages:

Project Setup

To add Autofac ASP.NET MVC integration to your MVC project, at a minimum you need to:

  • Add references to the Autofac assemblies
  • Register your controllers/dependencies
  • Set the DependencyResolver

Add References

The easiest way to add references to the required assemblies is to use !NuGet. The instructions for that are below. If you are unable to use !NuGet, instructions are also provided for manually adding the references

For !NuGet, install the Autofac.Mvc4 package. The appropriate references will be added to your project.

For manual references download Autofac and add references to:

  • Autofac.dll
  • Autofac.Integration.Mvc.dll

Register Dependencies and Set the Dependency Resolver

Detailed usage instructions are found later, but a simple example of registering the controllers and setting the DependencyResolver to get Autofac working in your application looks like this (in Global.asax):

protected void Application_Start()
{
    var builder = new ContainerBuilder();
    builder.RegisterControllers(typeof(MvcApplication).Assembly);
    var container = builder.Build();
    DependencyResolver.SetResolver(new AutofacDependencyResolver(container));

    // Other MVC setup...

ASP.NET MVC Registration and Usage

At a minimum, you need to register your MVC controllers and set the application DependencyResolver at startup. You can optionally do additional interesting things with Autofac MVC integration, outlined below.

Register Controllers

Inside the !Application_Start method in the Global.asax.cs register your controllers and their dependencies.

You can do this manually...

var builder = new ContainerBuilder();
builder.RegisterType<HomeController>().InstancePerHttpRequest();

...or you can use a provided extension method to register all the controllers in an assembly all at once:

var builder = new ContainerBuilder();
builder.RegisterControllers(Assembly.GetExecutingAssembly());

Note that ASP.NET MVC requests controllers by their concrete types, so registering them As<IController>() is incorrect. Also, if you register controllers manually and choose to specify lifetimes, you must register them as InstancePerDependency() or InstancePerHttpRequest() - ASP.NET MVC will throw an exception if you try to reuse a controller instance for multiple requests.

If you have controllers in a "plugin assembly" that isn't referenced by the main application you'll need to register your controller plugin assembly with the ASP.NET BuildManager.

Set the Dependency Resolver

After building your container pass it into a new instance of the AutofacDependencyResolver class. Finally, use the static DependencyResolver.SetResolver method to let ASP.NET MVC know that it should locate services using the AutofacDependencyResolver. This is Autofac's implementation of the new IDependencyResolver interface.

IContainer container = builder.Build();
DependencyResolver.SetResolver(new AutofacDependencyResolver(container));

Register Model Binders

Similar to controllers, model binders (classes that implement IModelBinder) can be registered in Global.asax.cs. You can do this in one hit for an entire assembly:

var builder = new ContainerBuilder();
builder.RegisterModelBinders(Assembly.GetExecutingAssembly());
builder.RegisterModelBinderProvider();

You must also remember to register the AutofacModelBinderProvider using the RegisterModelBinderProvider extension method. This is Autofac's implementation of the new IModelBinderProvider interface.

Because the RegisterModelBinders extension method uses assembly scanning to add the model binders you need to specify what type(s) the IModelBinder class is to be registered for.

This is done by using the Autofac.Integration.Mvc.ModelBinderTypeAttribute, like so:

[ModelBinderType(typeof(string))]
public class StringBinder : IModelBinder
{
    public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
    {
        //do implementation here
    }
}

Multiple instances of the ModelBinderTypeAttribute can be added to a class if it is to be registered for multiple types.

Inject HTTP Abstractions

The MVC Integration includes an Autofac module that will add HTTP request lifetime scoped registrations for the HTTP abstraction classes. The following abstract classes are included:

  • HttpContextBase
  • HttpRequestBase
  • HttpResponseBase
  • HttpServerUtilityBase
  • HttpSessionStateBase
  • HttpApplicationStateBase
  • HttpBrowserCapabilitiesBase
  • HttpCachePolicyBase
  • VirtualPathProvider

To use these abstractions add the AutofacWebTypesModule to the container using the standard RegisterModule method.

builder.RegisterModule(new AutofacWebTypesModule());

Inject Dependencies into View Pages

You can make Property Injection available to your MVC views by adding the ViewRegistrationSource to your ContainerBuilder before building the application container.

builder.RegisterSource(new ViewRegistrationSource());

Your view page must inherit from one of the base classes that MVC supports for creating views. When using the Razor view engine this will be the WebViewPage class.

public abstract class CustomViewPage : WebViewPage
{
    public IDependency Dependency { get; set; }
}

The ViewPage, ViewMasterPage and ViewUserControl classes are supported when using the WebForms view engine.

public abstract class CustomViewPage : ViewPage
{
    public IDependency Dependency { get; set; }
}

Ensure that your actual view page inherits from your custom base class. This can be achieved using the @inherits directive inside your .cshtml file for the Razor view engine.

@inherits Example.Views.Shared.CustomViewPage

When using the WebForms view engine you set the Inherits attribute on the @ Page directive inside you .aspx file instead.

<%@ Page Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="Example.Views.Shared.CustomViewPage"%>

Inject Properties Into !FilterAttributes

To make use of property injection for your filter attributes call the RegisterFilterProvider method on the ContainerBuilder before building your container and providing it to the AutofacDependencyResolver.

ContainerBuilder builder = new ContainerBuilder();
 
builder.RegisterControllers(Assembly.GetExecutingAssembly());
builder.Register(c => new Logger()).As<ILogger>().InstancePerHttpRequest();
builder.RegisterFilterProvider();
 
IContainer container = builder.Build();
DependencyResolver.SetResolver(new AutofacDependencyResolver(container));

Then you can add properties to your filter attributes and any matching dependencies that are registered in the container will be injected into the properties. For example, the action filter below will have the ILogger instance that was registered above injected. Note that the attribute itself does not need to be registered in the container.

public class CustomActionFilter : ActionFilterAttribute
{
    public ILogger Logger { get; set; }
 
    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        Logger.Log("OnActionExecuting");
    }
}

The same simple approach applies to the other filter attribute types such as authorization attributes.

public class CustomAuthorizeAttribute : AuthorizeAttribute
{
    public ILogger Logger { get; set; }
 
    protected override bool AuthorizeCore(HttpContextBase httpContext)
    {
        Logger.Log("AuthorizeCore");
        return true;
    }
}

After applying the attributes to your actions as required your work is done.

[CustomActionFilter]
[CustomAuthorizeAttribute]
public ActionResult Index()
{
    // ...
}

Example Implementation

The Autofac source contains a demo web application project called Remember.Web. It has been upgraded to use ASP.NET MVC 4 and demonstrates many of the aspects of MVC that Autofac is used to inject.

Unit Testing

When unit testing an ASP.NET MVC app that uses Autofac where you have InstancePerHttpRequest components registered, you'll get an exception when you try to resolve those components because there's no HTTP request lifetime during a unit test.

The easiest way to fix this is to use a test-specific stub lifetime scope provider for your unit tests. We have an example in the Autofac source here: https://code.google.com/p/autofac/source/browse/Core/Tests/Autofac.Tests.Integration.Mvc/StubLifetimeScopeProvider.cs

First, create your stub lifetime scope provider. It will look like this:

using System;
using Autofac.Integration.Mvc;

namespace YourNamespace
{
  public class StubLifetimeScopeProvider : ILifetimeScopeProvider
  {
    ILifetimeScope _lifetimeScope;
    readonly ILifetimeScope _container;

    public StubLifetimeScopeProvider(ILifetimeScope container)
    {
      _container = container;
    }

    public ILifetimeScope ApplicationContainer
    {
      get { return _container; }
    }

    public ILifetimeScope GetLifetimeScope(Action<ContainerBuilder> configurationAction)
    {
      return _lifetimeScope ?? (_lifetimeScope = BuildLifetimeScope(configurationAction));
    }

    public void EndLifetimeScope()
    {
      if (_lifetimeScope != null)
          _lifetimeScope.Dispose();
    }

    ILifetimeScope BuildLifetimeScope(Action<ContainerBuilder> configurationAction)
    {
      return (configurationAction == null)
                 ? _container.BeginLifetimeScope(RequestLifetimeScopeProvider.HttpRequestTag)
                 : _container.BeginLifetimeScope(RequestLifetimeScopeProvider.HttpRequestTag, configurationAction);
    }
  }
}

In your unit tests, when you set up your dependency resolver, use this lifetime scope provider instead by manually specifying it:

var builder = new ContainerBuilder();
// Register your dependencies, then...
var container = builder.Build();
var lifetimeScopeProvider = new StubLifetimeScopeProvider(container);
var resolver = new AutofacDependencyResolver(container, lifetimeScopeProvider);
DependencyResolver.SetResolver(resolver);
// Now you can use DependencyResolver.Current in
// tests without getting the web request lifetime exception.

Upgrading from ASP.NET MVC 2

In order to take advantage of the new dependency injection support in ASP.NET MVC 3/4 a number of breaking changes were introduced. These instructions outline how to convert your application to use the new Autofac conventions.

For information on upgrading your actual MVC project please see the "Upgrading an ASP.NET MVC 2 Project to ASP.NET MVC 3" section in the ASP.NET MVC 3 release notes. There is also a MVC 3 Project Upgrade Tool for upgrading both MVC 2 and MVC 3 Beta (or RC) projects, but that currently only supports Visual Studio 2010 projects targeting .NET 4.

Update References

Remove references to Autofac.Integration.Web.dll and Autofac.Integration.Web.Mvc.dll. Add references to the new Autofac assemblies using !NuGet or manually. You can see how to do this above in the Project Setup section.

Remove Old Items

  • Remove IContainerProviderAccessor interface from Global.asax. This implementation is no longer used by ASP.NET MVC integration.
  • Remove references to the AutofacControllerFactory. The new MVC integration uses the MVC DependencyResolver class for integration instead.
  • Remove ASP.NET Autofac HTTP module configuration. Previously there were some Autofac ContainerDisposal and PropertyInjection modules required in your web.config. These should be removed.

Update Changed Items

  • Fix model binder injection. If you were making use of the model binder injection from the previous integration please ensure that you now also register the AutofacModelBinderProvider. Instructions on how to do this can be found under Register Model Binders.
  • Fix filter attribute injection. If you were using the !ExtensibleActionInvoker to perform property injection on filter attributes, you should now use the filter provider outlined in the Inject Properties Into FilterAttributes section below.
Clone this wiki locally