Doing DI with Autofac in ASP.NET Web API
ASP.NET Web API provides a very similar model to MVC for resolving dependencies using a service locator pattern. What you basically do is to provide the implementation of that service locator to return any of the requested dependencies, and that implementation is typically tied to a DI container.
The service locator can be injected into the Web API runtime using the ServiceResolver entry in the global configuration object (GlobalConfiguration.Configuration.ServiceResolver), which basically supports different overloads.
public void SetResolver(IDependencyResolver resolver);
public void SetResolver(object commonServiceLocator);
public void SetResolver(Func<Type, object> getService, Func<Type, IEnumerable<object>> getServices);
The first overload receives an instance of a IDependencyResolver implementation, which provides two methods for resolving one or multiple dependencies.
public interface IDependencyResolver
{
object GetService(Type serviceType);
IEnumerable<object> GetServices(Type serviceType);
}
GetService should return null if the dependency can not resolved. GetServices should return an empty IEnumerable if the same thing happens.
The second overload uses reflection for invoking the same two methods, GetService and GetServices.
The third overload receives a set of Func delegates for doing the same thing.
Autofac already provides a very smooth integration with ASP.NET Web API through a set of assemblies available in the “Autofac ASP.NET MVC integration” nuget package. The bad news is that you can not use the DepedencyResolver implementation in that package as it is not compatible with the one required by ASP.NET Web API.
The AutofacDepedencyResolver class in that package implements System.Web.Mvc.IDependencyResolver, while ASP.NET Web API expects a System.Web.Http.Services.IDependencyResolver implementation. Nothing that we can not fix with a simple few lines of code. We can reuse the existing implementation through the third overload that receives a set of delegates.
The following code snippet illustrates how you can register all dependencies in the Autofac container and use that for resolving all the Web API dependencies,
ContainerBuilder builder = new ContainerBuilder();
builder.RegisterType<ContactRepository>()
.As<IContactRepository>()
.InstancePerHttpRequest();
builder.RegisterApiControllers(Assembly.GetExecutingAssembly());
IContainer container = builder.Build();
var resolver = new AutofacDependencyResolver(container);
GlobalConfiguration.Configuration.ServiceResolver.SetResolver(
t => resolver.GetService(t),
t => resolver.GetServices(t));
One the things you can do with Autofac is to set the lifetime of the dependencies instances to be equal to a http request lifetime by using the “InstancePerHttpRequest” method. I also created a simple extension method “RegisterApiControllers” to automatically register all the existing Api controllers in the the project into the DI container.
public static class RegistrationExtensions
{
public static IRegistrationBuilder<object, ScanningActivatorData, DynamicRegistrationStyle> RegisterApiControllers(this ContainerBuilder builder, params Assembly[] controllerAssemblies)
{
return
from t in builder.RegisterAssemblyTypes(controllerAssemblies)
where typeof(IHttpController).IsAssignableFrom(t) && t.Name.EndsWith("Controller")
select t;
}
}
Using the code above, you should be able to use a API controller that looks like this (The contact repository is injected as a depedency)
public class ContactController : ApiController
{
IContactRepository repository;
public ContactController(IContactRepository repository)
{
this.repository = repository;
}