Dependency Injection
Web API 2 has a hook for dependency injection — IDependencyResolver — but no container of its own. Plug in Autofac (or Unity, Ninject, Simple Injector) and controllers can receive their services through the constructor.
On this page · 6 min · Intermediate
On this page
- Learning objectives
- Explanation
- Syntax
- Code example
- Step by step
- Real-world use
- Common mistakes
- Best practices
- Remember this
- Practice exercise
- Mini quiz
- Related topics
- My notes
- Reading time
- 6 min
- Difficulty
- Intermediate
- Updated
- Oct 28, 2026
Related tutorials
Learning objectives#
- Explain why Web API 2 needs a third-party container
- Register controllers and services with Autofac
- Choose InstancePerRequest, SingleInstance and InstancePerDependency
- Fix “parameterless public constructor” errors
Explanation#
By default Web API creates controllers with their parameterless constructor. If a controller asks for IProductService, you get the error “Make sure that the controller has a parameterless public constructor”.
A DI container fixes this. Install the Autofac.WebApi2 NuGet package, register types, build the container and set config.DependencyResolver.
builder.RegisterApiControllers(Assembly.GetExecutingAssembly()) registers every controller. builder.RegisterType<ProductService>().As<IProductService>() maps an interface to a class.
Lifetimes: InstancePerRequest — one per HTTP request (DbContext, repositories, services). SingleInstance — one for the whole app (configuration, caches, clocks). InstancePerDependency — a new one every time it is injected.
Configure the container once at startup (Global.asax or WebApiConfig). ASP.NET Core later made this built in with builder.Services.
Syntax#
var builder = new ContainerBuilder();
builder.RegisterApiControllers(Assembly.GetExecutingAssembly());
builder.RegisterType<ProductService>().As<IProductService>().InstancePerRequest();
config.DependencyResolver = new AutofacWebApiDependencyResolver(builder.Build());
Code example: Autofac in a Web API 2 project#
using System;
using System.Reflection;
using System.Web;
using System.Web.Http;
using Autofac;
using Autofac.Integration.WebApi;
public interface IClock
{
DateTime UtcNow { get; }
}
public class SystemClock : IClock
{
public DateTime UtcNow => DateTime.UtcNow;
}
public interface IGreetingService
{
string Greet(string name);
}
public class GreetingService : IGreetingService
{
private readonly IClock _clock;
public GreetingService(IClock clock) { _clock = clock; }
public string Greet(string name)
{
return (_clock.UtcNow.Hour < 12 ? "Good morning, " : "Hello, ") + name;
}
}
// App_Start/AutofacConfig.cs
public static class AutofacConfig
{
public static void Register(HttpConfiguration config)
{
var builder = new ContainerBuilder();
builder.RegisterApiControllers(Assembly.GetExecutingAssembly());
builder.RegisterType<SystemClock>().As<IClock>().SingleInstance();
builder.RegisterType<GreetingService>().As<IGreetingService>().InstancePerRequest();
config.DependencyResolver = new AutofacWebApiDependencyResolver(builder.Build());
}
}
// Global.asax.cs
public class WebApiApplication : HttpApplication
{
protected void Application_Start()
{
GlobalConfiguration.Configure(config =>
{
config.MapHttpAttributeRoutes();
AutofacConfig.Register(config);
});
}
}
// The controller just asks for what it needs
public class GreetingsController : ApiController
{
private readonly IGreetingService _greetings;
public GreetingsController(IGreetingService greetings)
{
_greetings = greetings;
}
[HttpGet, Route("api/greetings/{name}")]
public IHttpActionResult Get(string name)
{
return Ok(_greetings.Greet(name));
}
}
GET /api/greetings/Asha (at 09:00 UTC) → 200 "Good morning, Asha"
GET /api/greetings/Asha (at 15:00 UTC) → 200 "Hello, Asha"
Without AutofacConfig.Register:
→ 500 "An error occurred when trying to create a controller of type 'GreetingsController'.
Make sure that the controller has a parameterless public constructor."This example is illustrative. Copy or download it and run it in your own environment; the expected output is shown above.
Step-by-step explanation#
- GreetingService depends on IClock, and the controller depends on IGreetingService — nobody uses new for services.
- RegisterApiControllers lets Autofac create every controller.
- SystemClock is a singleton: one shared, stateless instance.
- GreetingService is created once per HTTP request and disposed at the end of it.
- Setting config.DependencyResolver tells Web API to ask Autofac for controllers and their dependencies.
Real-world use case#
A Web API 2 service registers ShopDbContext, repositories and services InstancePerRequest, so every request gets one DbContext shared by all its repositories — and unit tests can pass mocks into controller constructors.
Common mistakes#
A single DbContext shared by all requests is not thread-safe and grows forever. Use InstancePerRequest.
Autofac cannot build controllers it does not know about, so you still get the parameterless constructor error.
Calling the container from inside classes (service locator) hides dependencies. Use constructor injection.
Best practices#
- Configure the container once at startup
- Inject interfaces through constructors
- Use InstancePerRequest for anything holding a DbContext
- Keep singletons stateless or thread-safe
Remember this#
Web API 2 has the DI hook (IDependencyResolver), not the container.
Autofac: RegisterApiControllers + RegisterType<T>().As<I>().
Per request for DbContext; single instance for stateless helpers.
Practice exercise#
Your task: Register an ITaxCalculator (implemented by GstCalculator, 18%) as SingleInstance, and write a TaxController that receives it and returns the tax for GET api/tax/{amount}.
Need a hint?
Show solution
using System.Web.Http;
using Autofac;
public interface ITaxCalculator { decimal TaxFor(decimal amount); }
public class GstCalculator : ITaxCalculator { public decimal TaxFor(decimal amount) => amount * 0.18m; }
public static class TaxRegistrations
{
public static void Add(ContainerBuilder builder)
{
builder.RegisterType<GstCalculator>().As<ITaxCalculator>().SingleInstance();
}
}
public class TaxController : ApiController
{
private readonly ITaxCalculator _tax;
public TaxController(ITaxCalculator tax) { _tax = tax; }
[HttpGet, Route("api/tax/{amount:decimal}")]
public IHttpActionResult Get(decimal amount) => Ok(_tax.TaxFor(amount)); // GET api/tax/100 → 18.00
}
Mini quiz#
Which property tells Web API 2 to use a DI container?
Want more? Practise all ASP.NET Web API MCQs · ASP.NET Web API interview questions
My notes#
Saved in this browser.