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.

comments powered by Disqus

Related