Inyección de dependencia resolviendo por nombre

Inyección de dependencia resolviendo por nombre

Además de la respuesta de @adem-caglin, me gustaría publicar aquí un código reutilizable que he creado para registros basados ​​en nombres.

ACTUALIZAR Ahora está disponible como paquete nuget.

Para registrar sus servicios, deberá agregar el siguiente código a su Startup clase:

        services.AddTransient<ServiceA>();
        services.AddTransient<ServiceB>();
        services.AddTransient<ServiceC>();
        services.AddByName<IService>()
            .Add<ServiceA>("key1")
            .Add<ServiceB>("key2")
            .Add<ServiceC>("key3")
            .Build();

Entonces puedes usarlo a través de IServiceByNameFactory interfaz:

public AccountController(IServiceByNameFactory<IService> factory) {
    _service = factory.GetByName("key2");
}

O puede usar el registro de fábrica para mantener limpio el código del cliente (que prefiero)

_container.AddScoped<AccountController>(s => new AccountController(s.GetByName<IService>("key2")));

El código completo de la extensión está en github.


Como señaló @Tseng, no hay una solución integrada para el enlace con nombre. Sin embargo, usar el método de fábrica puede ser útil para su caso. El ejemplo debería ser algo como lo siguiente:

Cree un resolutor de repositorio:

public interface IRepositoryResolver
{
    IRepository GetRepositoryByName(string name);
}

public class RepositoryResolver : IRepositoryResolver 
{
    private readonly IServiceProvider _serviceProvider;
    public RepositoryResolver(IServiceProvider serviceProvider)
    {
        _serviceProvider = serviceProvider;
    }
    public IRepository GetRepositoryByName(string name)
    {
         if(name == "TestSuiteRepository") 
           return _serviceProvider.GetService<TestSuiteRepositor>();
         //... other condition
         else
           return _serviceProvider.GetService<BaseRepositor>();
    }

}

Registre los servicios necesarios en ConfigureServices.cs

services.AddSingleton<IRepositoryResolver, RepositoryResolver>();
services.AddTransient<TestSuiteRepository>();
services.AddTransient<BaseRepository>(); 

Finalmente úsalo en cualquier clase:

public class BaselineManager
{
    private readonly IRepository _repository;

    public BaselineManager(IRepositoryResolver repositoryResolver)
    {
        _repository = repositoryResolver.GetRepositoryByName("TestSuiteRepository");
    }
}

No puede hacerlo con el contenedor ASP.NET Core IoC integrado.

Esto es por diseño . El contenedor integrado se mantiene intencionalmente simple y fácilmente extensible, por lo que puede conectar contenedores de terceros si necesita más funciones.

Tienes que usar un contenedor de terceros para hacer esto, como Autofac (ver documentos).

public BaselineManager([WithKey("TestSuiteRepository")]IRepository repository)