Registering Multiple Implementations of an Interface in ASP.NET Core with Autofac
Full source code here.
A few weeks ago I wrote a post about using dependency injection to pick between two implementations of an interface. It was a solution I was not very happy with because it meant I had to new
up the implementations inside a factory or I had to use service collection to instantiate all implementations of the interface and then use a piece of code to return the one the was wanted.
As of this writing service collection does not natively support choosing between two implementations of a interface, but Autofac does and it can be used in place of service collection, or alongside it.
In this post I’m going to show its use alongside the service collection just for the dependencies that have multiple implementations, I’ll use service collection for dependencies that have a single collections. The examples are for ASP.NET Web Api Core 2.x and Core 3; there are small variations in how to use Autofac in those two versions of Core.
The Scenario
I have three controllers, the NegativeValuesController
and PositiveValuesController
take the same IValuesService
and the third controller ProductsController
takes an IProductsService
.
The NegativeValuesController
should get a NegativeValuesService
and the PositiveValuesController
should get a PositiveValuesService
.
I’m going to use Autofac
to provide the dependency injection for these controllers.
The ProductsController
will use the built in ServiceCollection
to fulfill its dependency.
Core 2.x
Start by adding the Autofac.Extensions.DependencyInjection
package to the application.
Inside Program.cs add add .ConfigureServices(services => services.AddAutofac())
to the CreateWebHostBuilder
statement.
1public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
2 WebHost.CreateDefaultBuilder(args)
3 .ConfigureServices(services => services.AddAutofac())
4 .UseStartup<Startup>();
In Startup.cs add this to the ConfigureServices(..) method -
1services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1)
2 .AddControllersAsServices(); // these two lines have to come before
3services.AddScoped<IProductsService, ProductsService>(); // you populte the builder a below
4
5var builder = new ContainerBuilder();
6builder.Populate(services);
7
8builder.RegisterType<NegativeValuesService>().As<IValuesService>().AsSelf();
9builder.RegisterType<PositiveValuesService>().As<IValuesService>().AsSelf();
10builder.Register(ctx => new NegativeValuesController(ctx.Resolve<NegativeValuesService>()));
11builder.Register(ctx => new PositiveValuesController(ctx.Resolve<PositiveValuesService>()));
12
13AutofacContainer = builder.Build();
14
15return new AutofacServiceProvider(AutofacContainer);
The controllers work in the normal, familar way -
1public NegativeValuesController(IValuesService valuesService)
2{
3 _valuesService = valuesService;
4}
1public PositiveValuesController(IValuesService valuesService)
2{
3 _valuesService = valuesService;
4}
That’s it, you can now choose the implementation you want for a controller.
Core 3
If you want to the same in Core 3, there are few small differences.
As before, start by adding the Autofac.Extensions.DependencyInjection
package to the application.
In Program.cs
add .UseServiceProviderFactory(new AutofacServiceProviderFactory())
to the CreateWebHostBuilder
statement.
Back in Startup.cs add this method -
1public void ConfigureContainer(ContainerBuilder builder)
2{
3 builder.RegisterType<NegativeValuesService>().As<IValuesService>().AsSelf();
4 builder.RegisterType<PositiveValuesService>().As<IValuesService>().AsSelf();
5
6 builder.Register(ctx => new NegativeValuesController(ctx.Resolve<NegativeValuesService>()));
7 builder.Register(ctx => new PositiveValuesController(ctx.Resolve<PositiveValuesService>()));
8}
Edit the ConfigureServices
method to include the following -
1public void ConfigureServices(IServiceCollection services)
2{
3 //snip..
4 services.AddScoped<IProductsService, ProductsService>();
5
6 services.AddControllers();
7 services.AddMvc().AddControllersAsServices();
8}
The usage inside the controllers does not change.
There you go, injecting multiple implementations of a interface in ASP.NET Core 2 and 3.
Full source code here.