skip to Main Content

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

2

Answers


  1. Chosen as BEST ANSWER

    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 changed the services themselves to have MyFactory has a parameter to their constructor, made a DI for the factory in the startup file, and then simply invoked the factory from the constructor of the service itself


  2. This might do the trick for you:

    public void ConfigureServices(IServiceCollection services)
    {
        bool isProd = InProduction();
    
        services.AddSingleton<ClassA>();
        services.AddSingleton<ClassAV2>();
        services.AddSingleton<ClassAV3>();
    
        services.AddTransient<MyServiceV2>(sp =>
            ActivatorUtilities.CreateInstance<MyServiceV2>(
                isProd
                    ? sp.GetRequiredService<ClassAV2>()
                    : sp.GetRequiredService<ClassA>()));
    
        services.AddTransient<MyServiceV3>(sp =>
            ActivatorUtilities.CreateInstance<MyServiceV3>(
                isProd
                    ? sp.GetRequiredService<ClassAV3>()
                    : sp.GetRequiredService<ClassA>()));
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search