Search code examples
c#asp.netdependency-injection

How to Conditionally Inject Dependencies into Services based on their type in .NET 6?


I got a C# gRPC sln with .NET 6 (not sure if the fact that its grpc matters for this question) with 2 different C# classes which are implemeting the logic of 2 different grpc services which derives from 2 different services defined in 2 different proto files:

public class MyServiceV2 : My_Service.My_ServiceBase
public class MyServiceV3 : My_Service_V3.My_Service_V3Base

These 2 services run side by side at the same time and registered their endpoint.

Both these classes have a constructor with ClassA as a parameter. There are also derived classes from ClassA:

public class ClassAV2 : ClassA
public class ClassAV3 : ClassA

How can I make the DI in the startup file such that MyServiceV2 will be injected with ClassAV2 in the constructor for the ClassA parameter, while MyServiceV3 will be injected with ClassAV3?

Note: The services can't have the parameter as the actual class since there is a different behavior for prod env and non prod env: in prod env the it should be as I wrote above, but for non prod env the parameter should be injected with the base ClassA only. I know how to tell between prod and non prod env, just not how to inject to a specific service when in prod env.

Adding pseudo code to what I want to achieve:

public void ConfigureServices(IServiceCollection services)
{
    if(InProduction()) //already got this
    {
       services.FindService(typeof(MyServiceV2)).AddSingleton<ClassA, ClassAV2>();
    services.FindService(typeof(MyServiceV3)).AddSingleton<ClassA, ClassAV3>();
    }
    else
    {
       services.AddSingleton<ClassA>();
    }
}

Solution

  • What I eventually did was using a factory.

    public class MyFactory
    {
        private readonly IServiceProvider _serviceProvider;
        public MyFactory(IServiceProvider serviceProvider) 
        { 
            _serviceProvider = serviceProvider;
        }
    
        public ClassA GetClassA(ServiceVersion serviceVersion, bool isForProduction)
        {                 
            if(isForProduction) 
            {
                switch(serviceVersion)
                {
                    case ServiceVersion.V2:
                    {
                         return new CLassAV2( _serviceProvider.GetRequiredService<IMyInterface>());
                    }
                    case ServiceVersion.V3:
                    {
                         return new CLassAV3( _serviceProvider.GetRequiredService<IMyInterface>());
                    }
                    default:
                    {
                        throw new NotImplementedException("Unsupported service version");
                    }
                }
            }
            else
            {
                switch (serviceVersion)
                {
                    ...
                }
            }
        }
    }
    

    I then:

    1. made a DI for the factory in the startup file

    2. changed the services themselves to have MyFactory as a parameter to their constructor.

    3. invoked the factory's GetClassA method from the constructor to initialize the correct type for the service