Change the implementation of an interface at runtime

Costas

Administrator
Staff member
AddSingleton : shared throughout the entire application lifetime

AddTransient : Transient services are created each time they are requested from the DI container. This means that every time you resolve the service, a new instance is created.

AddScoped : New instance is created for each HTTP request, and the same instance is used throughout that request.

In a console application, the behavior of AddScoped and AddSingleton may seem to behave similarly because the application runs in a single context.


C#:
// src - https://binodmahto.medium.com/use-multiple-implementations-of-an-interface-with-asp-net-core-di-44088e2c9cec
// ref - https://stackoverflow.com/a/66152508

namespace CoreWebAPIDemo.Services
{
    public delegate ILoggerService LoggerServiceResolver(string loggerType);
}

public void ConfigureServices(IServiceCollection services)
{
    services.AddScoped<SerilogFileLoggerService>();
    services.AddScoped<DbLoggerService>();
    services.AddScoped<NullLoggerService>();
    services.AddTransient<LoggerServiceResolver>(serviceProvider => loggerType =>
    {
        switch (loggerType)
        {
            case "SerilogFileLogger":
                return serviceProvider.GetService<SerilogFileLoggerService>();
            case "DbLogger":
                return serviceProvider.GetService<DbLoggerService>();
            default:
                return serviceProvider.GetService<NullLoggerService>();
        }
    });
}
 

Costas

Administrator
Staff member
alternative - Using a Factory Pattern

C#:
//Define a Factory Interface
public interface IkoalaFactory
{
    Ikoala Create();
}

//Implement the Factory
public class KoalaFactory : IkoalaFactory
{
    private readonly IServiceProvider _serviceProvider;

    public KoalaFactory(IServiceProvider serviceProvider)
    {
        _serviceProvider = serviceProvider;
    }

    public Ikoala Create()
    {
        bool useTest2 = /* logic to determine which implementation to use */;

        if (useTest2)
        {
            return _serviceProvider.GetService<Test2>();
        }
        else
        {
            return _serviceProvider.GetService<Test>();
        }
    }
}

//Register the Factory
public void ConfigureServices(IServiceCollection services)
{
    services.AddTransient<Test>();
    services.AddTransient<Test2>();
    services.AddSingleton<IkoalaFactory, KoalaFactory>();
}


//Use the Factory
public class SomeService
{
    private readonly IkoalaFactory _ikoalaFactory;

    public SomeService(IkoalaFactory ikoalaFactory)
    {
        _ikoalaFactory = ikoalaFactory;
    }

    public void SomeMethod()
    {
        Ikoala ikoala = _ikoalaFactory.Create();
        // Use the ikoala instance
    }
}
 
Top