-
Notifications
You must be signed in to change notification settings - Fork 0
Mvc Integration
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:
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
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
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...
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.
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.
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));
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.
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());
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"%>
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()
{
// ...
}
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.
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.
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.
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
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 MVCDependencyResolver
class for integration instead. -
Remove ASP.NET Autofac HTTP module configuration. Previously there were some Autofac
ContainerDisposal
andPropertyInjection
modules required in yourweb.config
. These should be removed.
-
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.