Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Dependency injection resolving by name

How can I inject different implementation of object for a specific class?

For example, in Unity, I can define two implementations of IRepository

container.RegisterType<IRepository, TestSuiteRepositor("TestSuiteRepository"); container.RegisterType<IRepository, BaseRepository>();  

and call the needed implementation

public BaselineManager([Dependency("TestSuiteRepository")]IRepository repository) 
like image 965
Ilya Avatar asked Aug 22 '16 05:08

Ilya


People also ask

How can dependency injection be resolved?

Resolve dependencies using IServiceProvider You can use the IServiceCollection interface to create a dependency injection container. Once the container has been created, the IServiceCollection instance is composed into an IServiceProvider instance. You can use this instance to resolve services.

How do you dispose of resources using dependency injection?

When you make it explicit, you've got basically two options: 1. Configure the DI to return transient objects and dispose these objects yourself. 2. Configure a factory and instruct the factory to create new instances.


2 Answers

In addition to @adem-caglin answer I'd like to post here some reusable code I've created for name-based registrations.

UPDATE Now it's available as nuget package.

In order to register your services you'll need to add following code to your Startup class:

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

Then you can use it via IServiceByNameFactory interface:

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

Or you can use factory registration to keep the client code clean (which I prefer)

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

Full code of the extension is in github.

like image 43
neleus Avatar answered Oct 03 '22 17:10

neleus


As @Tseng pointed, there is no built-in solution for named binding. However using factory method may be helpful for your case. Example should be something like below:

Create a repository resolver:

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>();     }  } 

Register needed services in ConfigureServices.cs

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

Finally use it in any class:

public class BaselineManager {     private readonly IRepository _repository;      public BaselineManager(IRepositoryResolver repositoryResolver)     {         _repository = repositoryResolver.GetRepositoryByName("TestSuiteRepository");     } } 
like image 76
adem caglin Avatar answered Oct 03 '22 15:10

adem caglin