One need in multitenant applications is injecting dependencies based on tenant configuration. It can be actually more complex as instances may need constructor parameters. Here is my example of dynamic injection of multiple file clients in ASP.NET Core multi-tenant web application.
- Global query filters in Entity Framework Core 2.0
- Implementing tenant providers on ASP.NET Core
- Implementing database per tenant strategy on ASP.NET Core
- Handling missing tenants in ASP.NET Core
- Unit testing multi-tenant database provider
- Defensive database context for multi-tenant ASP.NET Core applications
- Tenant-based dependency injection in multi-tenant ASP.NET Core applications
- Using configurable composite command in multi-tenant ASP.NET Core application
Source code available! Source code for all my ASP.NET Core multi-tenant application posts is available at public Github repository gpeipman/AspNetCoreMultitenant.
The case of file client
We are living in cloud era. It means that customers of our multitenant application may use different cloud services for their files. Of course, some customers want us to take care of everything. So, how to handle this situation? One customers wants files to be stored on Azure Blob Storage and another wants to go with Google Drive.
We can go with IFileClient generalization I have introduced in my previous posts.
NB! To keep things mininal I’m using dummy IFileClient and implementing classes in this blog post. The main focus here is on tenant based dependency injection.
Dummy file clients
Here are the dummy file clients I’m using for this post.
public interface IFileClient
public class AzureBlobStorageFileClient : IFileClient
public AzureBlobStorageFileClient(string connectionString)
public class GoogleDriveFileClient : IFileClient
public GoogleDriveFileClient(string connectionString)
They don’t have any members besides constructor that takes storage connection string as an argument.
I will go with JSON-file tenants provider from my blog post Implementing tenant providers on ASP.NET Core. Notice that all tenants have storage type and storage connection string specified in their configuration.
"Name": "Small biz 1",
"StorageConnectionString": "<storage connection string 1>"
"Name": "Small biz 2",
"StorageConnectionString": "<storage connection string 2>"
"Name": "Big corp",
"StorageConnectionString": "<storage connection string 3>"
Tenant 1 with host name sme1 uses Google Drive for files and tenants 3 with host name bigcorp uses Azure blob storage.
Tenant-based dependency injection
It’s time to head to application Startup class and make dependency injection of IFileClient consider also current tenant. I will use implementation factory function to return correct file client instance from dependency injection.
var provider = service.GetRequiredService<ITenantProvider>();
var tenant = provider.GetTenant();
if(tenant.StorageType == "GoogleDrive")
return new GoogleDriveFileClient(tenant.ConnectionString);
if(tenant.StorageType == "AzureBlob")
return new AzureBlobStorageFileClient(tenant.ConnectionString);
For unknown and missing file clients my code returns null. It’s not perfect joice but works for this demo.
Trying out file client injection
To see if file clients are injected correctly I will try file client injection out with sme1 and bigcorp tenants.
Both tenants get the correct type of instance as expected.
It’s possible to have more complex cases when dynamic dependency injection is needed in multi-tenant application. There are some interesting works to check out:
- Multi-tenant Dependency Injection in ASP.NET Core by Ben Foster
- Implement dynamic dependency injection in ASP.NET Core 2.2, example with multitenancy scenario by Anthony Giretti
- Multitenant Applications (Autofac)
Using my previous works on multi-tenant ASP.NET Core applications and IFileClient generalization we were able to define file client type and connection string in tenants configuration. Using implementation factory method and tenant provider we were able to inject correct instance of file client based on current tenant to ASP.NET Core controller.