Although ASP.NET Core has built-in dependency injection support it is still possible to use dependency injection components by other vendors. ASP.NET Core supports other containers through simple IServiceProvider interface. This blog post explains how to use other containers with ASP.NET Core and shows how to use Structuremap and Autofac with framework level dependency injection.
Framework level dependency injection
ASP.NET Core supports framework level dependency injection. Types are registered during application start-up.
public void ConfigureServices(IServiceCollection services)
{
// Add dependencies
services.AddSingleton<IAlertService>(new AlertService());
// Add framework services.
services.AddMvc();
}
Later these instances can be injected to controllers and view components by simply using controller injection.
public class HomeController : Controller
{
private readonly IAlertService _alertService;
public HomeController(IAlertService alertService)
{
_alertService = alertService;
}
public IActionResult Index()
{
return View();
}
}
This is how to use framework level dependency injection.
Using third-party dependency injection components
But there are many applications that use custom dependency injection containers like StructureMap, Autofac, NInject, Unity etc. These containers all have their own strengths that developers love. Is it possible to use framework level dependency injection with some of these containers?
The answer is almost yes because not all containers have support for ASP.NET Core dependency injection. Some vendors say today that they don’t have any plans to support it because their containers cannot be used in such a primitive manner. Other vendors are considering support for framework level dependency injection and some vendors already support ASP.NET Core.
The common pattern for bringing in other dependency injection containers seems to be returning IServiceProvider implementation from ConfigureServices() method of Startup class like shown below.
public IServiceProvider ConfigureServices(IServiceCollection services)
{
// Add framework services.
// Configure third-party DI container
// return container-specific IServiceProvider implementation
}
In the case of framework level dependency injection the return type of this method is void.
Next sections of this post expect that web application has the following packages included:
- StructureMap.Microsoft.DependencyInjection
- Autofac.Extensions.DependencyInjection
Sample code uses IAlertService interface and AlertService dummy classes to illustrate dependency injection.
public interface IAlertService
{
void SendEmailAlert(string email, string alert);
}
public class AlertService : IAlertService
{
public void SendEmailAlert(string email, string alert)
{
}
}
Using StructureMap
To illustrate better how things work let’s add some dependency injection containers to web application project.
StructureMap uses registry classes for mappings. Here is the sample registry used in sample code.
public class MyStructuremapRegistry : Registry
{
public MyStructuremapRegistry()
{
For<IAlertService>().LifecycleIs(Lifecycles.Container).Use<AlertService>();
}
}
And ConfigureServices() method of Startup class looks like this.
public IServiceProvider ConfigureServices(IServiceCollection services)
{
// Add framework services.
services.AddMvc();
var container = new Container();
container.Configure(config =>
{
config.AddRegistry(new MyStructuremapRegistry());
config.Populate(services);
});
return container.GetInstance<IServiceProvider>();
}
To see how Structuremap is plugged to ASP.NET Core dependency injection one can take look at StructureMapServiceProvider class.
Using Autofac
The code for Autofac is similar but it uses Autofac specifics to initialize dependency injection container.
public IServiceProvider ConfigureServices(IServiceCollection services)
{
// Add framework services.
services.AddMvc();
var builder = new ContainerBuilder();
builder.RegisterType<AlertService>().As<IAlertService>();
builder.Populate(services);
var appContainer = builder.Build();
return new AutofacServiceProvider(appContainer);
}
Most of this code can ideally be moved to some other class but as I’m not very familiar with Autofac I leave it like it is.
Wrapping up
Although framework level dependency injection is good enough for most of web applications there is still option available to use other containers by other vendors. Interfacing is done through IServiceProvider interface and ConfigureServices() method of Startup class. In case of custom container this method must return instance of IServiceProvider to use for resolving dependencies.
View Comments (2)
Hi Gunnar, excellent job! How could I use Autofac and NHibernate together with below strategy?
You can try to combine the code here with one shown here: https://gunnarpeipman.com/aspnet-core-nhibernate/ In my NHibernate post I created extension method that registers session factory and ISession with ASP.NET Core dependency injection. Maybe you can make this code work with Autofac too.