Aspnet Core Dependency Injection – Register Multiple Instance for an Interface

3 minutes to read read

Journey of Dependency Injection

Asp.Net Core is one of the gems (I would say) created by Microsoft that has simplified a lot of things and provides a whole lot of things by default out of the box. It based on dot net core which provides inherent capability to run cross platform but to ease out developer life several optimizations were done to enhance productivity.

One such feature is Dependency Injection. Although lately, but Microsoft did included dependency injection as a part of the core product. I have been working Asp.Net MVC since 2010 (or 2011) and started DI with Ninject which was (or is) a wonderful project. During the time I crossed paths with Unity and Autofac during different projects, but more or less the approach remain same. Create a container system, create ‘sort of’ controller factories and then register dependencies. But during all this time one thing that remain constant was additional overhead of creating this shit. So it was a moment of joy (atleast for me) when i say this in recent versions of MVC. And most importantly it is quite stable and performs well out of the box.

But is default DI Perfect ????

Coming straight to point one of the major use case i encounter frequently is basically to have multiple instances of a class registered against an Interface and then resolve them runtime based on requirement. This resolution is mostly done using a key which is provided at the time of registration. Simple registration should be something like below:

public void ConfigureServices(IServiceCollection services)
{
    services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
    services.AddTransient<IMyInterface, MyInterfaceImplementation>();
}

In the above we simply register one implementation against an interface. But the problem is microsoft ServiceCollection does not provide any option to register multiple implementations against interface. Here is the available methods for adding Transient registrations

DI registration methods

So in this case, basically we need to use a workaround if we want to register it way we want.

Solution

A very simple solution is to register a Func which will basically take in a string (or anything) and will provide the implementation accordingly. So we have the following set of objects that we need to register. Interface IMyInterface has implementations MyInterfaceImplementation and MyAnotherInterfaceImplementation which needs to be registered.

public interface IMyInterface { }

public class MyInterfaceImplementation : IMyInterface
{ }
public class MyAnotherInterfaceImplementation : IMyInterface
{ }

So we register a Func in the Configure Services as below

public void ConfigureServices(IServiceCollection services)
{
    services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
    //services.AddTransient<IMyInterface, MyInterfaceImplementation>();
    services.AddTransient<Func<string, IMyInterface>>(provider => key =>
     {
         switch (key)
         {
             case "simple":
                 return new MyInterfaceImplementation();
             case "complex":
                 return new MyAnotherInterfaceImplementation();
         }

         throw new ArgumentException(key);
     });
}	

This will register the func. Now in the class or controller where it needs to be resolved we simply resolve the func as below.

public class ConsumerClass
{
    readonly IMyInterface myinterface;
    public ConsumerClass(Func<string, IMyInterface> serviceAccessor)
    {
        this.myinterface = serviceAccessor("simple");
    }
}	

Or in case we need to get the desired type at action level, simply register the accessor directly.

public class DynamicConsumer
{
    readonly Func<string, IMyInterface> accessor;
    public DynamicConsumer(Func<string, IMyInterface> serviceAccessor)
    {
        this.accessor = serviceAccessor;
    }

    public void DoSomething()
    {
        var resolvedInstance = accessor("complex");
    }
}

And this shall resolve your problem. Thats all folks for now. Do write in comments for any query or suggestions.

Leave a Reply

Your email address will not be published. Required fields are marked *