In my code, there is the registration of two different services with the same interface as this:
services.AddSingleton<IServiceResolver, ServiceResolver>();
services.AddSingleton<IService, ServiceA>();
services.AddSingleton<IService, ServiceB>();
The ServiceResolver
is used to pick the correct service based on some circumstances. The ServiceResolver
itself has a constructor like this:
public ServiceResolver(IEnumerable<IService> idServices, ...)
So, any business logic related code should always use the service resolver to pick the correct service to use.
The Problem:
IService
can be injected directly into business code and will then be always ServiceB
since this was the last IService
registered.
Is there a way to prevent injecting a single implementation of an interface that was registered multiple times?
I know that as long as you stick to just injecting IServiceResolver
there will be no problem, but the code would be much safer to use if this simple thing could be prevented somehow.
CodePudding user response:
There may be a way to do this if no other classes need to resolve any of the IService
s. You can set up ServiceResolver
so that it has knowledge about what IService
types exist and then internally it can manually create all the instances using the existing ServiceCollection
. To do this, ServiceResolver
will need IServiceProvider
and you do lose some functionality, like having scope handled automatically for you.
Here's a quick example of what I mean.
The new ServiceResolver
class:
public class ServiceResolver : IServiceResolver
{
public static void Register<TService>() where TService : IService
{
ServiceTypes.Add(typeof(TService));
}
public ServiceResolver(IServiceProvider serviceProvider)
{
_serviceProvider = serviceProvider;
}
private IEnumerable<IService> GetServices()
{
return ServiceTypes.Select(t => ActivatorUtilities.CreateInstance(_serviceProvider, t) as IService);
}
private static List<Type> ServiceTypes = new List<Type>();
private readonly IServiceProvider _serviceProvider;
}
Registering types:
ServiceResolver.Register<ServiceA>();
ServiceResolver.Register<ServiceB>();
services.AddSingleton<IServiceResolver, ServiceResolver>();
I created a working example of this here
A modified version where the IService
s are created as singletons here