Home > OS >  Is there a way to prevent injecting a single implementation of an interface that was registered mult
Is there a way to prevent injecting a single implementation of an interface that was registered mult

Time:08-10

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 IServices. 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 IServices are created as singletons here

  • Related