D
Dennis Tretyakov

One instance for various service types in Microsoft Extensions DI

Recently moving away from Autofac to Microsoft Extensions DI I’ve faced a problem that there is no API to register one service implementation instance (singleton, scoped) for various service types.

Autofac behaviour

[Fact]
public void Autofac_ReturnsSameInstance()
{
    var contaienrBuilder = new ContainerBuilder();
    contaienrBuilder.RegisterType<Service>()
        .AsSelf()
        .AsImplementedInterfaces()
        .SingleInstance();

    var container = contaienrBuilder.Build();

    var byInterface = container.Resolve<IService>();
    var byExactType = container.Resolve<Service>();

    Assert.Same(byInterface, byExactType);
}

Microsoft DI behaviour

[Fact]
public void DI_ReturnsDifferentInstances()
{
    var serviceProvider = new ServiceCollection()
        .AddSingleton<Service>()
        .AddSingleton<IService, Service>()
        .BuildServiceProvider();

    var byInterface = serviceProvider.GetRequiredService<IService>();
    var byExactType = serviceProvider.GetRequiredService<Service>();

    Assert.NotSame(byInterface, byExactType);
}

Achieving similar behaviour on Microsoft DI

Autofac allows multiple keys for the same implementation. Microsoft DI is one to one map. To achieve the same behaviour choose the type you will use as the primary key (Service in the example below). For all other types (like IService in the example below) register resolvers that would resolve a service using primary key.

[Fact]
public void DI_ReturnsSameInstace_LikeAutofac()
{
    var serviceProvider = new ServiceCollection()
        .AddSingleton<Service>()
        .AddSingleton<IService>(sp => sp.GetRequiredService<Service>())
        .BuildServiceProvider();

    var byInterface = serviceProvider.GetRequiredService<IService>();
    var byExactType = serviceProvider.GetRequiredService<Service>();

    Assert.Same(byInterface, byExactType);
}

Code on GitHub.

© 2020 - 2024, Dennis Tretyakov