0

I want to make multiple implementations of a specific interface accessible through an Abstract Factory in .NET Core. Based on a supplied enum the correct implementation should be returned. This is my current code:

public enum ServiceInstanceEnum { SampleE, SampleD }

// MyServiceFactory
public ISampleC CreateService(ServiceInstanceEnum serviceType)
{
    switch (serviceType)
    {
        case ServiceInstanceEnum.SampleE: return new SampleE();
        case ServiceInstanceEnum.SampleD: return new SampleD();
        default: throw new Exception($" The service is not exist...");
    }
}

My service injections on Startup.cs

services.AddScoped<IMyServiceFactory, MyServiceFactory>();
services.AddScoped<ISampleC, SampleD>();
services.AddScoped<ISampleC, SampleE>();

Controller

private readonly ISampleC _sampleC;

public WeatherForecastController(
    ILogger<WeatherForecastController> logger,
    IMyServiceFactory myServiceFactory)
{
    _logger = logger;
    _sampleC = myServiceFactory.CreateService(ServiceInstanceEnum.SampleD);
}

The problem is that my current MyServiceFactory imeplementation creates the services manually, while I want them to be created and managed by the DI Container.

1
  • Sorry for my bad english. Commented Dec 1, 2023 at 10:31

2 Answers 2

0

This is solved in .NET 8 with keyed services. The key can be any type. There's no need for a factory

builder.Services.AddKeyedSingleton<ICache, BigCache>("big");
builder.Services.AddKeyedSingleton<ICache, SmallCache>("small");

class BigCacheConsumer([FromKeyedServices("big")] ICache cache)
{
    public object? GetData() => cache.Get("data");
}

It should be possible to use enums as keys too:

services.AddKeyedScoped<ISampleC, SampleD>(ServiceInstanceEnum.SampleD);
services.AddKeyedScoped<ISampleC, SampleE>(ServiceInstanceEnum.SampleE);

and inject it into the controller

public class WeatherForecastController: Controller
{
    private readonly ISampleC _sampleC;

    public WeatherForecastController(
        ILogger<WeatherForecastController> logger,
        [FromKeyedServices(ServiceInstanceEnum.SampleE)] ISampleC sampleC)
    {
        _logger = logger;
        _sampleC = sampleC;
    }

Or, using primary constructors, just :

public class WeatherForecastController(
    ILogger<WeatherForecastController> logger,
    [FromKeyedServices(ServiceInstanceEnum.SampleE)] ISampleC sampleC): Controller
{
    private readonly ISampleC _sampleC=sampleC;
    private readonly ILogger<WeatherForecastController> _logger = logger;

    ...
}
Sign up to request clarification or add additional context in comments.

Comments

0

Let your MyServiceFactory depend on IServiceProvider:

public class MyServiceFactory(IServiceProvider container) : IMyServiceFactory
{
    public ISampleC CreateService(ServiceInstanceEnum serviceType)
    {
        switch (serviceType)
        {
            case ServiceInstanceEnum.SampleE:
                return container.GetRequiredInstance<SampleE>();
            case ServiceInstanceEnum.SampleD:
                return container.GetRequiredInstance<SampleD>();
            default: throw new Exception($" The service is not exist...");
        }
    }   
}

services.AddScoped<IMyServiceFactory, MyServiceFactory>();
services.AddScoped<SampleD>();
services.AddScoped<SampleE>();

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.