Multiple Interface Implementations In ASP.NET Core

ASP.NET Core has built-in support for dependency injection. However, multiple implementations of an interface in ASP.NET Core is tricky. In this article, I’m going to explain two approaches through which how we can dynamically select a service from such an implementation in ASP.NET Core.

I have used the below tools for preparing this tutorial

  1. VS 2019 Community Edition 16.4.5
  2.  ASP.NET Core 3.1
  3. Swagger for testing and documenting the API

The two approaches which we are going to discuss over here are below

  1. Implement the interface using the func delegate with key
  2. Implement the interface using IEnumberable collection

Using the delegate func

Create a simple Web API project and follow the steps below

Introduce one interface called IShoppingCart

public interface IShoppingCart {
    object GetCart();
}

Introduce three implementation classes as below- three different classes where we have implemented the same interface.

public class ShoppingCartFlipCart: IShoppingCart {
    public object GetCart() {
        return $ " Items from FlipCart";
    }
}
public class ShoppingCartAmazon: IShoppingCart {
    public object GetCart() {
        return $ "grab items from Amazone";
    }
}
public class ShoppingCartEBay: IShoppingCart {
    public object GetCart() {
        return $ "Items from ebay";
    }
}

Introduce an enum –we will be using while resolving and injecting the interface

public enum Carts {
    Amazon,
    Flipcart,
    Ebay
}

 

ASP.NET Core has built-in support for dependency injection. However, multiple implementations of an interface in ASP.NET Core is tricky. In this article, I’m going to explain two approaches through which how we can dynamically select a service from such an implementation in ASP.NET Core.

I have used the below tools for preparing this tutorial

  1. VS 2019 Community Edition 16.4.5
  2.  ASP.NET Core 3.1
  3. Swagger for testing and documenting the API

The two approaches which we are going to discuss over here are below

  1. Implement the interface using the func delegate with key
  2. Implement the interface using IEnumberable collection

Using the delegate func

Create a simple Web API project and follow the steps below

Introduce one interface called IShoppingCart

public interface IShoppingCart {
    object GetCart();
}

Introduce three implementation classes as below- three different classes where we have implemented the same interface.

public class ShoppingCartFlipCart: IShoppingCart {
    public object GetCart() {
        return $ " Items from FlipCart";
    }
}
public class ShoppingCartAmazon: IShoppingCart {
    public object GetCart() {
        return $ "grab items from Amazone";
    }
}
public class ShoppingCartEBay: IShoppingCart {
    public object GetCart() {
        return $ "Items from ebay";
    }
}

Introduce an enum –we will be using while resolving and injecting the interface

public enum Carts {
    Amazon,
    Flipcart,
    Ebay
}

Introduce another interface as below

public interface IShoppingCartRepository {
    object GetCart();
}

Introduce a class where I have implemented the Interface created in step 4

public class ShoppingCartRepository: IShoppingCartRepository {
    private readonly Func < Carts, IShoppingCart > _shoppingCart;
    public ShoppingCartRepository(Func < Carts, IShoppingCart > shoppingCart) {
        this._shoppingCart = shoppingCart;
    }
    public object GetCart() {
        var obj = this._shoppingCart(Carts.Amazon);
        return obj.GetCart();
    }
}

Here I have used a func delegate Func<Carts, IShoppingCart>, this will be registered to container in Startup.cs class.

Let us go ahead and configure these classes and interface into dependency container. In order register the interface, we need to go the Starup.cs class.

In Startup.cs class, we have two methods,

public void ConfigureServices(IServiceCollection services) //this method gets called by runtime. Use this method to add services to the container.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env) //this method gets called by runtime. Use this method to configure the Http request pipeline

I may come up with an article on Startup.cs. Please refer the below links to understand the Startup.cs class and the methods belonging to this class.

In ASP.NET Core 6, Startup.cs will not be created by default.

Without any delay, let us jump into Startup.cs class

Let us register the interface and classes to the container

public void ConfigureServices(IServiceCollection services) {
    services.AddScoped < IShoppingCartRepository, ShoppingCartRepository > ();
    services.AddTransient < ShoppingCartEBay > ();
    services.AddTransient < ShoppingCartFlipCart > ();
    services.AddTransient < ShoppingCartAmazone > ();
    services.AddTransient < Func < Carts, IShoppingCart >> (serviceProvider => key => {
        switch (key) {
            case Carts.Amazon:
                return serviceProvider.GetService < ShoppingCartAmazone > ();
            case Carts.Flipcart:
                return serviceProvider.GetService < ShoppingCartEBay > ();
            case Carts.Ebay:
                return serviceProvider.GetService < ShoppingCartFlipCart > ();
            default:
                throw new NotImplementedException();
        }
    });
    services.AddControllers();
    //Swashbuckle.AspNetCore needs to be installed from NuGet
    services.AddSwaggerGen(c => {
        c.SwaggerDoc("v1", new OpenApiInfo {
            Title = "Interface with Multiple Implementations",
                Version = "v1",
                Description = "Same Interface with Multiple Implementation in ASP.NET Core 3.1",
                Contact = new OpenApiContact {
                    Name = "Prasad Raveendran",
                        Email = string.Empty,
                        Url = new Uri("https://www.c-sharpcorner.com/members/prasad-nair3")
                }
        });
    });
}

Now, let's go ahead and add the swaggerUI to the request pipeline via the method Configure

public void Configure(IApplicationBuilder app, IWebHostEnvironment env) {
    if (env.IsDevelopment()) {
        app.UseDeveloperExceptionPage();
    }
    app.UseHttpsRedirection();
    app.UseRouting();
    app.UseAuthorization();
    app.UseEndpoints(endpoints => {
        endpoints.MapControllers();
    });
    app.UseSwagger();
    app.UseSwaggerUI(sw => {
        sw.SwaggerEndpoint("/swagger/v1/swagger.json", "API V1.0");
    });
}

Add a Controller called MultipleController.cs

[Route("api/[controller]")]
[ApiController]
public class MultipleController: ControllerBase {
    private IShoppingCartRepository _shoppingCartRepository;
    public MultipleController(IShoppingCartRepository shoppingCartRepository) {
            this._shoppingCartRepository = shoppingCartRepository;
        }
        [HttpGet]
    public IEnumerable < string > GetAmazoneProducts() {
        return new string[] {
            "Cart",
            this._shoppingCartRepository.GetCart().ToString()
        };
    }
}

Go ahead and run the application, Swagger UI will be displayed on the browser- now you are good to go and debug the code.

If you execute the api -  https://localhost:1234555/api/Multiple

Port number will be varied.

You will be getting the response as below

[
  "Cart",
  "grab items from Amazone"
]

Which is nothing but the response from the class ShoppingCartAmazon.cs

Using IEnumerable

Create the below enum as below

public enum InstanceEnum {
    First,
    Second
}

Create the below interface as below

public interface IInstance {
    InstanceEnum GetType();
    string GetDetails();
}

Let us create the below implementation classes

FirstInstance class which has been implemented by the interface IInstance

public class FirstInstance: IInstance {
    public string GetDetails() {
        return "From FirstInstance";
    }
    InstanceEnum IInstance.GetType() {
        return InstanceEnum.First;
    }
}

SecondInstance class which has been implemented by interface IInstance

public class SecondInstance: IInstance {
    public string GetDetails() {
        return "From Second Instance";
    }
    InstanceEnum IInstance.GetType() {
        return InstanceEnum.Second;
    }
}

Now let us go ahead and register these two classes into the container using Startup.cs

public void ConfigureServices(IServiceCollection services) {
    services.AddSingleton < IInstance, FirstInstance > ();
    services.AddSingleton < IInstance, SecondInstance > ();
    services.AddControllers();
    services.AddSwaggerGen(c => {
        c.SwaggerDoc("v1", new Microsoft.OpenApi.Models.OpenApiInfo {
            Title = "Multiple Implementation using IEnumberable",
        });
    });
}

Now add the swagger to the pipeline

public void Configure(IApplicationBuilder app, IWebHostEnvironment env) {
    if (env.IsDevelopment()) {
        app.UseDeveloperExceptionPage();
    }
    app.UseRouting();
    app.UseAuthorization();
    app.UseEndpoints(endpoints => {
        endpoints.MapControllers();
    });
    app.UseSwagger();
    app.UseSwaggerUI(sw => {
        sw.SwaggerEndpoint("/swagger/v1/swagger.json", "API V1.0");
    });
}

Now create a control and inject the interface using the IEnumberable as below

[Route("api/[controller]")]
[ApiController]
public class MultipleController: ControllerBase {
    private IInstance _instance;
    public MultipleController(IEnumerable < IInstance > instances) {
            _instance = instances.Where(i => i.GetType() == InstanceEnum.First).FirstOrDefault();
        }
        [HttpGet]
    public string GetFirstInstance() {
        return _instance.GetDetails();
    }
}

Let us go ahead and build the project, and run,

URL : http://localhost:123455/api/Multiple

Port number will be varied based on the workstation

Output will be as below

From FirstInstance

Summary

Here we have gone through the basic understanding on multiple implementations of an interface in ASP.NET Core. Thanks for watching the article. Please do comment your feedbacks.

Introduce another interface as below

 

public interface IShoppingCartRepository {
    object GetCart();
}

Introduce a class where I have implemented the Interface created in step 4

public class ShoppingCartRepository: IShoppingCartRepository {
    private readonly Func < Carts, IShoppingCart > _shoppingCart;
    public ShoppingCartRepository(Func < Carts, IShoppingCart > shoppingCart) {
        this._shoppingCart = shoppingCart;
    }
    public object GetCart() {
        var obj = this._shoppingCart(Carts.Amazon);
        return obj.GetCart();
    }
}

Here I have used a func delegate Func<Carts, IShoppingCart>, this will be registered to container in Startup.cs class.

Let us go ahead and configure these classes and interface into dependency container. In order register the interface, we need to go the Starup.cs class.

In Startup.cs class, we have two methods,

public void ConfigureServices(IServiceCollection services) //this method gets called by runtime. Use this method to add services to the container.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env) //this method gets called by runtime. Use this method to configure the Http request pipeline

I may come up with an article on Startup.cs. Please refer the below links to understand the Startup.cs class and the methods belonging to this class.

In ASP.NET Core 6, Startup.cs will not be created by default.

Without any delay, let us jump into Startup.cs class

Let us register the interface and classes to the container

public void ConfigureServices(IServiceCollection services) {
    services.AddScoped < IShoppingCartRepository, ShoppingCartRepository > ();
    services.AddTransient < ShoppingCartEBay > ();
    services.AddTransient < ShoppingCartFlipCart > ();
    services.AddTransient < ShoppingCartAmazone > ();
    services.AddTransient < Func < Carts, IShoppingCart >> (serviceProvider => key => {
        switch (key) {
            case Carts.Amazon:
                return serviceProvider.GetService < ShoppingCartAmazone > ();
            case Carts.Flipcart:
                return serviceProvider.GetService < ShoppingCartEBay > ();
            case Carts.Ebay:
                return serviceProvider.GetService < ShoppingCartFlipCart > ();
            default:
                throw new NotImplementedException();
        }
    });
    services.AddControllers();
    //Swashbuckle.AspNetCore needs to be installed from NuGet
    services.AddSwaggerGen(c => {
        c.SwaggerDoc("v1", new OpenApiInfo {
            Title = "Interface with Multiple Implementations",
                Version = "v1",
                Description = "Same Interface with Multiple Implementation in ASP.NET Core 3.1",
                Contact = new OpenApiContact {
                    Name = "Prasad Raveendran",
                        Email = string.Empty,
                        Url = new Uri("https://www.c-sharpcorner.com/members/prasad-nair3")
                }
        });
    });
}

Now, let's go ahead and add the swaggerUI to the request pipeline via the method Configure

public void Configure(IApplicationBuilder app, IWebHostEnvironment env) {
    if (env.IsDevelopment()) {
        app.UseDeveloperExceptionPage();
    }
    app.UseHttpsRedirection();
    app.UseRouting();
    app.UseAuthorization();
    app.UseEndpoints(endpoints => {
        endpoints.MapControllers();
    });
    app.UseSwagger();
    app.UseSwaggerUI(sw => {
        sw.SwaggerEndpoint("/swagger/v1/swagger.json", "API V1.0");
    });
}

Add a Controller called MultipleController.cs

[Route("api/[controller]")]
[ApiController]
public class MultipleController: ControllerBase {
    private IShoppingCartRepository _shoppingCartRepository;
    public MultipleController(IShoppingCartRepository shoppingCartRepository) {
            this._shoppingCartRepository = shoppingCartRepository;
        }
        [HttpGet]
    public IEnumerable < string > GetAmazoneProducts() {
        return new string[] {
            "Cart",
            this._shoppingCartRepository.GetCart().ToString()
        };
    }
}

Go ahead and run the application, Swagger UI will be displayed on the browser- now you are good to go and debug the code.

If you execute the api -  https://localhost:1234555/api/Multiple

Port number will be varied.

You will be getting the response as below

[
  "Cart",
  "grab items from Amazone"
]

Which is nothing but the response from the class ShoppingCartAmazon.cs

Using IEnumerable

Create the below enum as below

public enum InstanceEnum {
    First,
    Second
}

Create the below interface as below

public interface IInstance {
    InstanceEnum GetType();
    string GetDetails();
}

Let us create the below implementation classes

FirstInstance class which has been implemented by the interface IInstance

public class FirstInstance: IInstance {
    public string GetDetails() {
        return "From FirstInstance";
    }
    InstanceEnum IInstance.GetType() {
        return InstanceEnum.First;
    }
}

SecondInstance class which has been implemented by interface IInstance

public class SecondInstance: IInstance {
    public string GetDetails() {
        return "From Second Instance";
    }
    InstanceEnum IInstance.GetType() {
        return InstanceEnum.Second;
    }
}

Now let us go ahead and register these two classes into the container using Startup.cs

public void ConfigureServices(IServiceCollection services) {
    services.AddSingleton < IInstance, FirstInstance > ();
    services.AddSingleton < IInstance, SecondInstance > ();
    services.AddControllers();
    services.AddSwaggerGen(c => {
        c.SwaggerDoc("v1", new Microsoft.OpenApi.Models.OpenApiInfo {
            Title = "Multiple Implementation using IEnumberable",
        });
    });
}

Now add the swagger to the pipeline

public void Configure(IApplicationBuilder app, IWebHostEnvironment env) {
    if (env.IsDevelopment()) {
        app.UseDeveloperExceptionPage();
    }
    app.UseRouting();
    app.UseAuthorization();
    app.UseEndpoints(endpoints => {
        endpoints.MapControllers();
    });
    app.UseSwagger();
    app.UseSwaggerUI(sw => {
        sw.SwaggerEndpoint("/swagger/v1/swagger.json", "API V1.0");
    });
}

Now create a control and inject the interface using the IEnumberable as below

[Route("api/[controller]")]
[ApiController]
public class MultipleController: ControllerBase {
    private IInstance _instance;
    public MultipleController(IEnumerable < IInstance > instances) {
            _instance = instances.Where(i => i.GetType() == InstanceEnum.First).FirstOrDefault();
        }
        [HttpGet]
    public string GetFirstInstance() {
        return _instance.GetDetails();
    }
}

Let us go ahead and build the project, and run,

URL : http://localhost:123455/api/Multiple

Port number will be varied based on the workstation

Output will be as below

From FirstInstance

Summary

Here we have gone through the basic understanding on multiple implementations of an interface in ASP.NET Core. Thanks for watching the article. Please do comment your feedbacks.