Search code examples
c#exceptiondependency-injection.net-coreautofac

Injecting a registered named service is not working as expected using Autofac 4.2.1


Background

Autofac 4.2.1(tried with the latest version of Autofac and the issue is still present) , WebApi project .netcore 2.2 Issue : I have two instances of the same service, which I register to the ContainerBuilder with Name:

builder.RegisterType<ServiceOne>().Named<IService>("ServiceOne").SingleInstance();
builder.RegisterType<ServiceTwo>().Named<IService>("ServiceTwo").SingleInstance();

I then inject the named services to my controller classes as required:

builder.Register(c => new KeysController(c.ResolveNamed<IService>("ServiceOne")));
builder.Register(c => new ValuesController(c.ResolveNamed<IService>("ServiceTwo")));

Autofac is not able to resolve the IService for both of my controllers by name.

The Exception

An unhandled exception occurred while processing the request. InvalidOperationException: Unable to resolve service for type 'AutoFacNaming.IService' while attempting to activate 'AutoFacNaming.Controllers.ValuesController'.


Solution

  • By default ASP.net core will not build controller from the container but only its parameters. You can change this by specifying AddControllersAsServices() when you register MVC with the service collection. Doing that will automatically register controller types into the IServiceCollection when the service provider factory calls builder.Populate(services).

    public class Startup
    {
      // Omitting extra stuff so you can see the important part...
      public void ConfigureServices(IServiceCollection services)
      {
        // Add controllers as services so they'll be resolved.
        services.AddMvc().AddControllersAsServices();
      }
    
      public void ConfigureContainer(ContainerBuilder builder)
      {
        // If you want to set up a controller for, say, property injection
        // you can override the controller registration after populating services.
        builder.Register(c => new KeysController(c.ResolveNamed<IService>("ServiceOne")));
        builder.Register(c => new ValuesController(c.ResolveNamed<IService>("ServiceTwo")));
      }
    }
    

    You can read more about it in the Autofac documentation