AspnetCore.MultiTenancy is a library for use in a multi-tenanted AspnetCore application.
Your web app/api is used by more than 1 "tenant", or rather, your app/api needs to behave differently for different tenants. However the stock DI for AspnetCore does not let you register different implementations for the same contract/interface.
Eg.1
A controller/service depends on IFooService to do its thing. But Tenant1 needs IFooService to work in a specific manner, but Tenant2 needs this done differently. You could :
- Define
IFooService1andIFooService2both of which inheritIFooService - Implment new types differently, as the tenants require.
- Create a factory to instantiate the type you need at runtime, as determined by the request's tenant
This is quite involved, and is not the best use of dependency injection.
How about registering dependencies in a tenant specific manner? Then for each request, DI will resolve dependencies which are unique to the request's tenant, as well as those dependencies which are not tenant specific.
This library lets you do just that.
-
Install package (publish package, todo)
-
Create an implmentation of
ITenant. The simplest one will be:
public class Tenant : ITenant
{
public Tenant(int id) => Id = id;
public int Id { get; }
}- Create an implementation of
ITenantProvider. Such as
public class DefaultTenantProvider : ITenantProvider
{
public ITenant Get(int tenantId) => new Tenant(tenantId);
}- Your tenant mechanism now comes into play. In the
ConfigureServicesfunction, you need to addservices.AddMultiTenancy(..), but this call needs a collection ofITenant. So first create a collection instance of your application's tenants. InSampleUsage.Startup, you'll see:
var tenants = new List<ITenant>
{
new Tenant(1),
new Tenant(2)
};Which is then used in
services.AddMultiTenancy(tenants);- This is where your tenant-specific bootstrapping logic comes in. Using the
serviceCollection, register dependencies as follow:
serviceCollection.AddTenantScoped(tenant1, typeof(IFooService), typeof(DefaultFooService), ServiceLifetime.Scoped);
serviceCollection.AddTenantScoped(tenant2, typeof(IFooService), typeof(SpecialFooService), ServiceLifetime.Scoped);
//where tenant1 and tenant2 are instances of a type deriving from ITenant- In
Configurefunction, add
app.UseTenantMiddleware();- Each request must have a header having key:
tenantId, and value(integer) is the Id of a tenant used during service registration.
All this is demonstrated in project SampleUsage.