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.
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;
...
}