Keyed Dependency Injection in .NET 8

Keyed dependency injection is a crucial feature in the .NET ecosystem that allows developers to resolve services based on a specific key. Introduced in .NET 8, this feature enhances flexibility and facilitates scenarios where multiple implementations of the same service interface are required. Let's delve deeper into what keyed dependency injection is and how it's implemented in .NET 8.

What is Keyed Dependency Injection?

In traditional dependency injection, services are registered and resolved based on their types. However, in certain scenarios, you might have multiple implementations of the same interface. This is where keyed dependency injection becomes invaluable. It allows you to register multiple implementations of an interface, each associated with a unique key, and then resolve the specific implementation based on that key.

Restriction In Usage

Currently you can only use this feature in Windows and not on a macos. This feature is packaged with .NET 8, which is not yet supported by Visual Studio for MacOs. So even though you will be able to install .NET 8 on macos, you will not be able to use it in Visual Studio for Mac.

Implementation in .NET 8

Let's explore a basic example using .NET 8 and C#. Assume we have an interface IStorage representing different storage implementations.

public interface IStorage
{
    void StoreData(string data);
}

Now, let's create two concrete implementations of this interface—LocalStorage and CloudStorage.

public class LocalStorage : IStorage
{
    public void StoreData(string data)
    {
        Console.WriteLine("Storing data locally: " + data);
    }
}

public class CloudStorage : IStorage
{
    public void StoreData(string data)
    {
        Console.WriteLine("Storing data in the cloud: " + data);
    }
}

Next, register these implementations with keyed services using IServiceCollection in the Startup.cs file.

public void ConfigureServices(IServiceCollection services)
{
    services.AddSingleton<IStorage>("local", new LocalStorage());
    services.AddSingleton<IStorage>("cloud", new CloudStorage());
}

Now, to resolve these services based on keys, you can use the IServiceProvider in your application.

public class DataProcessor
{
    private readonly IServiceProvider _serviceProvider;

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

    public void ProcessData(string data, string storageType)
    {
        var storage = _serviceProvider.GetRequiredService<IStorage>(storageType);
        storage.StoreData(data);
    }
}

In this example, the DataProcessor class takes in the IServiceProvider in its constructor, allowing it to resolve the IStorage service based on the provided key (storageType) using GetRequiredService<T>.

Finally, in your application logic, you can use DataProcessor to process data and specify the storage type.

public static void Main(string[] args)
{
    var serviceProvider = new ServiceCollection()
        .AddSingleton<DataProcessor>()
        .BuildServiceProvider();

    var dataProcessor = serviceProvider.GetRequiredService<DataProcessor>();
    
    // Process data using local storage
    dataProcessor.ProcessData("Sample data", "local");

    // Process data using cloud storage
    dataProcessor.ProcessData("Sensitive data", "cloud");
}

Conclusion

Keyed dependency injection in .NET 8 provides a powerful mechanism to manage and resolve multiple implementations of an interface. It allows developers to select a specific implementation based on a provided key, enabling more flexible and efficient application design. This feature significantly enhances the versatility of dependency injection in .NET, making it a valuable addition to the toolkit of any .NET developer.


Similar Articles