a multitenancy library for .NET Core
supports .NET 5.0, .NET Core 3.1, and .NET Core 2.1
Detect tenants using built-in or custom strategies.
Separate tenant data using a single or multiple databases.
Support for most authentication schemes and Identity.
Configure application behavior uniquely for each tenant.
Source code available on GitHub under the Apache 2.0 license.
Use standard ASP.NET Core conventions and patterns.
Finbuckle.MultiTenant is designed to be easy to use and follows standard .NET Core conventions as much as possible. This guide assumes a standard ASP.NET Core use case
Install the Finbuckle.MultiTenant.AspNetCore NuGet package.
.NET Core CLI
$ dotnet add package Finbuckle.MultiTenant.AspNetCore
Configure the services by calling AddMultiTenant<T>
followed by its builder methods in the app's ConfigureServices
method. Here we are using the basic TenantInfo
implementation, the host strategy and the configuration store.
Finbuckle.MultiTenant comes with several other multitenant strategies and stores.
The TenantInfo
class holds basic details about a tenant and is used throughout the library. See Core Concepts for more information.
public void ConfigureServices(IServiceCollection services)
{
...
services.AddMultiTenant<TenantInfo>()
.WithHostStrategy()
.WithConfigurationStore()
...
}
Configure the middleware by calling UseMultiTenant
in the app's Configure
method. Be sure to call it before calling UseMvc
and other middleware which will use per-tenant functionality.
public void Configure(IApplicationBuilder app)
{
...
app.UseMultiTenant(); // Before UseMvc!
...
app.UseMvc();
}
With the services and middleware configured, access information for the current tenant from the TenantInfo
property on the MultiTenantContext
object accessed from the GetMultiTenantContext
extension method. If the current tenant could not be determined then TenantInfo
will be null. The type of the TenantInfo
property depends on the type passed when calling
AddMultiTenant<T>
during configuration.
var tenantInfo = HttpContext.GetMultiTenantContext().TenantInfo;
if(tenantInfo != null)
{
var tenantId = tenantInfo.Id;
var identifier = tenantInfo.Identifier;
var name = tenantInfo.Name;
}
From the command line clone the git repository, cd
into the new directory, and compile with dotnet build
.
$ git clone https://github.com/Finbuckle/Finbuckle.MultiTenant.git
$ cd Finbuckle.MultiTenant
Cloning into 'Finbuckle.MultiTenant'...
<output omitted>
$ cd Finbuckle.MultiTenant
$ dotnet build
Run the unit tests from the command line with dotnet test
from the solution directory.
$ dotnet test
Finbuckle.MultiTenant relies on three key component to drive its functionality:
strategies, stores, and the TenantInfo
object.
A multitenant strategy is responsible identifying the current
tenant. An app can use
one or more strategies, each one tried in the order configured until tenant is identified.
For example, the BasePathStrategy
uses the first segment in the path of an http request.
Finbuckle.MultiTenant includes a variery of strategies, and custom strategies are easily
implemented.
A multitenant store holds tenant information and returns the details for the tenant identified by a strategy—if a match is found. Multiple stores can be configured, and strategies will try to resolve their identified tenant with each store in the order configured. Finbuckle.MultiTenant includes a variery of stores, and custom stores are easily implemented.
The middleware uses all registered strategies and stores to resolve
the tenant for the current request. The result is an ITenantInfo instance containing
details for the current tenant. The default ITenantInfo
implementation contains only basic
information, but a custom implementation
containing extra information can be defined.
With the tenant succesfully resolved an app can adjust its behavior
accordingly. The TenantInfo
can be obtained via dependency
injection or through the HttpContext.GetMultiTenantContext<T>()
extension method.
In addition, Funbuckle.MultiTenant provides tenant-aware behavior such as:
Check out the docs for all the details!