Implement dynamic dependency injection in ASP.NET Core 2.2, example with multitenancy scenario
Introduction
You have probably wondered whether it is possible to manipulate different instances of the same service according to a certain context in your application. Well, know that it is possible. I have prepared in this article a concrete example of dynamic dependency injection in a multitenant WebAPI context: for the same service (interface) it is possible to invoke the concrete instance appropriate for the current tenant.
Overview of the solution
Before starting coding anything, it’s important to arrange the project to make easily what we want to do. We need to discover and register easily each interface and its concrete class for each tenant. Then let’s arrange our classes like this:
Discover and register tenant services
Let’s take a look of what are our services look like:
Tenant1Service belongs to Tenant 1 and Tenant2Service belongs to Tenant 2. They both implement ITenantService. We need to select the right instance for the current tenant when a controller for example needs to call a method in ITenantService.
Discover tenant services
Let’s find first all the concrete classes to register:
As I said before, it’s easy to find them, we don’t need to scan the whole application to find classes to register.
Register tenant services
Now it’s time to register our concrete services (classes) with a specified lifetime, in this example I chose “Scoped” lifetime.
We need also to register for each service interface its concrete classes just registered before, For that we will create a function that takes in parameter the tenant name and we will use it to select the right class with. I recommand to register each interface manually, in order to control which interface you want to register as multitenant (you could have some identical services shared with all tenants). To register each interface with its related classes we will build an extension method to IServiceCollection:
We need a one last thing: create a generical service that will serve the right instance for a specified interface throught the functions we registered before. (Instead of injections functions in a Controller for example):
Now let’s see how our ConfigureServices method in Startup.cs looks like:
Demo!
Here is the implemenation of our DemoMultiTenantController:
And let’s play the demo:
I added an instance id to show you that the lifetime I chose worked (Scoped). As a reminder “scoped” lifetime serves a new instance at each request.
Conclusion
This article showed you how to selected the right service to instantiate for a specified interface trought a function (encapsulated in a provider).
This example was implemented with a multitenant scenario, but you can also reuse this example for Api versionning, or better with a combination of Api versionning and multitenancy.
I haven’t showed any example with repository, you can definitely use the same logic to implement multitenant repository
This article was funny to write for me, I hope you will found this useful 🙂