snippetcsharpCritical
How to register multiple implementations of the same interface in Asp.Net Core?
Viewed 0 times
netaspregisterhowcoresameimplementationstheinterfacemultiple
Problem
I have services that are derived from the same interface.
Typically, other IoC containers like
In ASP.NET Core, how do I register these services and resolve them at runtime based on some key?
I don't see any
Is the Factory pattern the only option here?
Update1
I have gone though the article here that shows how to use the factory pattern to get service instances when we have multiple concrete implementations. However, it is still not a complete solution. When I call the
For example consider this:
How can
In Unity,
public interface IService { }
public class ServiceA : IService { }
public class ServiceB : IService { }
public class ServiceC : IService { }Typically, other IoC containers like
Unity allow you to register concrete implementations by some Key that distinguishes them.In ASP.NET Core, how do I register these services and resolve them at runtime based on some key?
I don't see any
Add Service methods that take a key or name parameter, which would typically be used to distinguish the concrete implementation.public void ConfigureServices(IServiceCollection services)
{
// How do I register services of the same interface?
}
public MyController:Controller
{
public void DoSomething(string key)
{
// How do I resolve the service by key?
}
}Is the Factory pattern the only option here?
Update1
I have gone though the article here that shows how to use the factory pattern to get service instances when we have multiple concrete implementations. However, it is still not a complete solution. When I call the
_serviceProvider.GetService() method, I cannot inject data into the constructor. For example consider this:
public class ServiceA : IService
{
private string _efConnectionString;
ServiceA(string efconnectionString)
{
_efConnecttionString = efConnectionString;
}
}
public class ServiceB : IService
{
private string _mongoConnectionString;
public ServiceB(string mongoConnectionString)
{
_mongoConnectionString = mongoConnectionString;
}
}
public class ServiceC : IService
{
private string _someOtherConnectionString
public ServiceC(string someOtherConnectionString)
{
_someOtherConnectionString = someOtherConnectionString;
}
}How can
_serviceProvider.GetService() inject the appropriate connection string?In Unity,
Solution
I did a simple workaround using
Firstly declare a shared delegate:
Then in your
And use it from any class registered with DI:
Keep in mind that in this example the key for resolution is a string, for the sake of simplicity and because OP was asking for this case in particular.
But you could use any custom resolution type as key, as you do not usually want a huge n-case switch rotting your code. Depends on how your app scales.
Func when I found myself in this situation.Firstly declare a shared delegate:
public delegate IService ServiceResolver(string key);Then in your
Startup.cs, setup the multiple concrete registrations and a manual mapping of those types:services.AddTransient();
services.AddTransient();
services.AddTransient();
services.AddTransient(serviceProvider => key =>
{
switch (key)
{
case "A":
return serviceProvider.GetService();
case "B":
return serviceProvider.GetService();
case "C":
return serviceProvider.GetService();
default:
throw new KeyNotFoundException(); // or maybe return null, up to you
}
});And use it from any class registered with DI:
public class Consumer
{
private readonly IService _aService;
public Consumer(ServiceResolver serviceAccessor)
{
_aService = serviceAccessor("A");
}
public void UseServiceA()
{
_aService.DoTheThing();
}
}Keep in mind that in this example the key for resolution is a string, for the sake of simplicity and because OP was asking for this case in particular.
But you could use any custom resolution type as key, as you do not usually want a huge n-case switch rotting your code. Depends on how your app scales.
Code Snippets
public delegate IService ServiceResolver(string key);services.AddTransient<ServiceA>();
services.AddTransient<ServiceB>();
services.AddTransient<ServiceC>();
services.AddTransient<ServiceResolver>(serviceProvider => key =>
{
switch (key)
{
case "A":
return serviceProvider.GetService<ServiceA>();
case "B":
return serviceProvider.GetService<ServiceB>();
case "C":
return serviceProvider.GetService<ServiceC>();
default:
throw new KeyNotFoundException(); // or maybe return null, up to you
}
});public class Consumer
{
private readonly IService _aService;
public Consumer(ServiceResolver serviceAccessor)
{
_aService = serviceAccessor("A");
}
public void UseServiceA()
{
_aService.DoTheThing();
}
}Context
Stack Overflow Q#39174989, score: 482
Revisions (0)
No revisions yet.