Mellon-MultiTenant-Azure
1.0.30-alpha
See the version list below for details.
dotnet add package Mellon-MultiTenant-Azure --version 1.0.30-alpha
NuGet\Install-Package Mellon-MultiTenant-Azure -Version 1.0.30-alpha
<PackageReference Include="Mellon-MultiTenant-Azure" Version="1.0.30-alpha" />
paket add Mellon-MultiTenant-Azure --version 1.0.30-alpha
#r "nuget: Mellon-MultiTenant-Azure, 1.0.30-alpha"
// Install Mellon-MultiTenant-Azure as a Cake Addin #addin nuget:?package=Mellon-MultiTenant-Azure&version=1.0.30-alpha&prerelease // Install Mellon-MultiTenant-Azure as a Cake Tool #tool nuget:?package=Mellon-MultiTenant-Azure&version=1.0.30-alpha&prerelease
Mellon.MultiTenant by @PubDev
Package | Version | Alpha |
---|---|---|
Mellon-MultiTenant | ||
Mellon-MultiTenant-Base | ||
Mellon-MultiTenant-ConfigServer | ||
Mellon-MultiTenant-Azure | ||
Mellon-MultiTenant-Hangfire |
Why Mellon, mellon is the Sindarin (and Noldorin) word for "friend", yes I'm a big fan of LoR, so let's be friends?
About The Project
This library was created to supply a set of tools to enable the creation of multi-tenant applications using .net.
Built With
- net6
- steeltoe
- Azure App Configuration
- Spring Cloud Config
- The most important, Love โค๏ธ
Getting Started
Installation
With package Manager:
Install-Package Mellon-MultiTenant
With .NET CLI:
dotnet add package Mellon-MultiTenant
Configurations
There are two ways to configure the settings, via config and through the api
Settings
"MultiTenant": {
"ApplicationName": "customer-api",
"HttpHeaderKey": "x-tenant-name",
"CookieKey": "tenant-name",
"QueryStringKey": "tenant-name",
"TenantSource": "Settings",
"Tenants": [
"client-a",
"client-b",
"client-c"
]
}
Property | Description | Default |
---|---|---|
ApplicationName | Application name | IHostEnvironment.ApplicationName |
HttpHeaderKey | HTTP Header key, where the tenant name will be passed | null |
CookieKey | HTTP Cookie key, where the tenant name will be passed | null |
QueryStringKey | HTTP Query String key, where the tenant name will be passed | null |
TenantSource | Where the list of possible tenants will be stored, it can be from two sources: Settings or EnvironmentVariables |
Settings |
Tenants | When the property TenantSource is set to Settings this property must contain the list of tenants |
null |
WithDefaultTenant | When the tenant is not defined by the caller the lib will set the tenant as the tenant defined within this property, use it just when actually needed ๐๐ | null |
When TenantSource
is set to EnvironmentVariables
it will get the tenant list from the environment variable MULTITENANT_TENANTS
, this environment variable must contain the list of possible tenants in a single string, separating the tenants using ,
for example:
$Env:MULTITENANT_TENANTS = 'client-a,client-b,client-c'
Using the API
You can also set the settings using these options while you are adding the services
builder.Services
.AddMultiTenant(options =>
options
.WithApplicationName("customer-api")
.WithHttpHeader("x-tenant-name")
.WithCookie("tenant-name")
.WithQueryString("tenant-name")
.WithDefaultTenant("client-a")
.LoadFromSettings()
);
WithApplicationName(string)
- Set the application name
WithHttpHeader(string)
- Set the HTTP Header key, where the tenant name will be passed
WithCookie(string)
- Set the HTTP Cookie key, where the tenant name will be passed
WithQueryString(string)
- Set the HTTP Query String key, where the tenant name will be passed
WithDefaultTenant(string)
- Set for when the tenant is not defined by the caller the lib will set the tenant as the tenant defined within this property, use it just when needed ๐๐
LoadFromSettings
- Set for when the tenant list will be loaded from the settings MultiTenant:Tenants
LoadFromEnvironmentVariable
- Set for when the tenant list will be loaded from the environment variable MULTITENANT_TENANTS
WithHttpContextLoad(Func<HttpContext, string> func)
- When all the possibilities above do not meet your need you can create a custom "Middleware" to identify the tenant based on a
HttpContext
WithCustomTenantConfigurationSource<T>()
T
must be an implementation of the interfaceITenantConfigurationSource
use it to define new a source of configurations for the tenants, for example, if the tenant settings are stored on XML files you could create something like this:
public class LocalXmlTenantSource : ITenantConfigurationSource
{
private readonly IHostEnvironment _hostEnvironment;
public LocalTenantSource(
IHostEnvironment hostEnvironment)
{
_hostEnvironment = hostEnvironment;
}
public IConfigurationBuilder AddSource(
string tenant,
IConfigurationBuilder builder)
{
builder.AddXmlFile($"appsettings.{tenant}.xml", true);
builder.AddXmlFile($"appsettings.{tenant}.{_hostEnvironment.EnvironmentName}.xml", true);
return builder;
}
}
Local
This is the default source of settings for the tenants, there is no need to enable it, it will search for the settings on the application following this pattern:
appsettings.{tenant}.json
appsettings.{_hostEnvironment.EnvironmentName}.json
It is also worth mentioning that the configurations will also contain:
appsettings.json
appsettings.[environment].json
environment variables
Spring Cloud Config
You can also load the settings from a Spring Cloud Config Server!
To enable the usage you need to install an extra package:
With package Manager:
Install-Package Mellon-MultiTenant-ConfigServer
With .NET CLI:
dotnet add package Mellon-MultiTenant-ConfigServer
Once the package is installed you need to configure its services
builder.Services
.AddMultiTenant()
.AddMultiTenantSpringCloudConfig();
To setup Spring Cloud Config on your environment check this reporitory DotNet-ConfigServer
The application name for spring cloud config will be based on the settings MultiTenant.ApplicationName and the label will be tenant name.
Example: customer-api-client-a.yaml
being:
- customer-api the application name
- client-a the tenant name
Moreover, it is worth mentioning that the settings for each customer will also have the settings of the current files:
- appsettings.json
- appsettings.[environment].json
- environment variables
Azure App Configuration
You can also use it as a source of configuration the Azure App Configuration
With package Manager:
Install-Package Mellon-MultiTenant-Azure
With .NET CLI:
dotnet add package Mellon-MultiTenant-Azure
Once the package is installed you need to configure its services
builder.Services
.AddMultiTenant()
.AddMultiTenantAzureAppConfiguration();
AddMultiTenantAzureAppConfiguration(Action<AzureMultiTenantOptions> action = null)
if the action is not passed, the connection string used to connect on azure will be loaded from AzureAppConfigurationConnectionString
if you want to elaborate more, on how you are going to connect on Azure, you can use the AzureMultiTenantOptions
, there is a property, which is a Func<IServiceProvider, string, Action<AzureAppConfigurationOptions>>
, where the first parameter is the ServiceProvider, where you can extract the services; a string, being the tenant name; and the return of this Func
must be an Action<AzureAppConfigurationOptions>
.
For example:
builder.Services
.AddMultiTenant()
.AddMultiTenantAzureAppConfiguration(options =>
options.AzureAppConfigurationOptions = (serviceProvider, tenant) =>
{
var configuration = serviceProvider.GetRequiredService<IConfiguration>();
return azureOptions => azureOptions
.Connect(configuration["AzureAppConfigurationConnectionString"])
.Select("*", tenant);
}
);
Usage / Samples
You can find some examples of how to use this library in the folder /samples
Web API
To enable it on your api you first need to add the services:
builder.Services.AddMultiTenant();
then you need also to register the middleware used to identify the tenant based on the HttpContext
app.UseMultiTenant();
Once that is done you will be able to use the interface IMultiTenantConfiguration
, this interface will behave the same as the IConfiguration
interface, but contain only the current tenant settings:
Example:
app.MapGet("/", (IMultiTenantConfiguration configuration) =>
{
return new
{
Tenant = configuration.Tenant,
Message = configuration["Message"],
};
});
EF Core Migrations:
To use it with EF Core is quite simple, you need to use the interface IMultiTenantConfiguration
as mentioned above to setup your EF Context
Setup
builder.Services.AddDbContext<DataBaseContext>(
(IServiceProvider serviceProvider, DbContextOptionsBuilder options) =>
{
var configuration = serviceProvider.GetRequiredService<IMultiTenantConfiguration>();
options.UseSqlServer(configuration?["ConnectionStrings:DefaultConnection"]);
});
Migrations
To apply the migrations, you only need to do this:
var tenants = app.Services.GetRequiredService<MultiTenantSettings>();
foreach (var tenant in tenants.Tenants)
{
using (var scope = app.Services.CreateScope())
{
var tenantSettings = scope.ServiceProvider.GetRequiredService<TenantSettings>();
tenantSettings.SetCurrentTenant(tenant);
var db = scope.ServiceProvider.GetRequiredService<DataBaseContext>();
await db.Database.MigrateAsync();
}
}
app.Run();
Extras
We know that settings can be changed all the time, but to get our applications running on with the latest settings we need to restart the application, it caused downtime and it's not very practical. Keeping that in mind, we added also an endpoint that when called will refresh all the settings for all the tenants or a specific tenant:
/refresh-settings
/refresh-settings/{tenantName}
PS: this will work only with AzureAppConfiguration and SpringCloudConfig
Hangfire
[WIP] ๐ฅ
Roadmap
- Add unit tests ๐งช
- Add new Config Source
- Load the Tenants from a web-api request
- Enable the usage with HangFire [WIP] ๐ฅ
See the open issues for a full list of proposed features (and known issues).
Contributing
Contributions are what make the open source community such an amazing place to learn, inspire, and create. Any contributions you make are greatly appreciated.
If you have a suggestion that would make this better, please fork the repo and create a pull request. You can also simply open an issue with the tag "enhancement". Don't forget to give the project a star! Thanks again!
- Fork the Project
- Create your Feature Branch (
git checkout -b feature/AmazingFeature
) - Commit your Changes (
git commit -m 'Add some AmazingFeature'
) - Push to the Branch (
git push origin feature/AmazingFeature
) - Open a Pull Request
Contact
- Humberto Rodrigues - @1bberto - humberto_henrique1@live.com
- Rafael Nagai - @naganaga - rafakenji23@gmail.com
Project Page: https://pub-dev.github.io/Mellon.MultiTenant
Product | Versions Compatible and additional computed target framework versions. |
---|---|
.NET | net6.0 is compatible. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 was computed. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 was computed. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. |
-
net6.0
- Azure.Identity (>= 1.8.0)
- Mellon-MultiTenant-Base (>= 1.0.30-alpha)
- Microsoft.Extensions.Configuration.AzureAppConfiguration (>= 5.2.0)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
Version | Downloads | Last updated |
---|---|---|
3.0.51-alpha | 68 | 10/2/2024 |
3.0.36 | 88 | 10/2/2024 |
2.0.49-alpha | 197 | 11/26/2023 |
2.0.35 | 1,625 | 11/26/2023 |
1.1.48-alpha | 124 | 10/23/2023 |
1.1.46-alpha | 116 | 8/1/2023 |
1.1.45-alpha | 122 | 7/8/2023 |
1.1.44-alpha | 113 | 6/20/2023 |
1.1.43-alpha | 127 | 4/4/2023 |
1.1.42-alpha | 112 | 4/4/2023 |
1.1.41-alpha | 132 | 3/25/2023 |
1.1.34 | 1,038 | 10/23/2023 |
1.1.33 | 1,658 | 8/1/2023 |
1.1.32 | 518 | 7/8/2023 |
1.1.31 | 836 | 6/20/2023 |
1.1.30 | 734 | 4/4/2023 |
1.1.29 | 619 | 3/25/2023 |
1.0.40-alpha | 123 | 2/25/2023 |
1.0.39-alpha | 121 | 2/25/2023 |
1.0.38-alpha | 127 | 2/25/2023 |
1.0.37-alpha | 122 | 2/25/2023 |
1.0.36-alpha | 131 | 2/24/2023 |
1.0.34-alpha | 121 | 2/17/2023 |
1.0.33-alpha | 129 | 1/6/2023 |
1.0.32-alpha | 133 | 1/6/2023 |
1.0.31-alpha | 127 | 1/4/2023 |
1.0.30-alpha | 125 | 1/4/2023 |
1.0.29-alpha | 125 | 1/4/2023 |
1.0.28 | 534 | 2/25/2023 |
1.0.28-alpha | 127 | 1/4/2023 |
1.0.27 | 230 | 2/25/2023 |
1.0.27-alpha | 130 | 1/2/2023 |
1.0.26 | 261 | 2/24/2023 |
1.0.26-alpha | 126 | 1/2/2023 |
1.0.25 | 227 | 2/24/2023 |
1.0.25-alpha | 131 | 1/2/2023 |
1.0.24 | 254 | 2/17/2023 |
1.0.24-alpha | 136 | 1/2/2023 |
1.0.23 | 285 | 1/6/2023 |
1.0.23-alpha | 131 | 1/2/2023 |
1.0.22 | 282 | 1/4/2023 |
1.0.22-alpha | 136 | 1/2/2023 |
1.0.21 | 275 | 1/3/2023 |
1.0.21-alpha | 137 | 1/2/2023 |
1.0.20 | 285 | 1/3/2023 |
1.0.20-alpha | 131 | 1/2/2023 |
1.0.19 | 279 | 1/3/2023 |
1.0.19-alpha | 140 | 1/2/2023 |
1.0.18 | 264 | 1/2/2023 |
1.0.18-alpha | 127 | 1/2/2023 |
1.0.17 | 264 | 1/2/2023 |
1.0.17-alpha | 137 | 1/2/2023 |
1.0.16 | 274 | 1/2/2023 |
1.0.16-alpha | 129 | 1/2/2023 |
1.0.15 | 273 | 1/2/2023 |
1.0.15-alpha | 132 | 1/2/2023 |
1.0.14 | 296 | 1/2/2023 |
1.0.14-alpha | 133 | 1/2/2023 |
1.0.13 | 273 | 12/30/2022 |
1.0.13-alpha | 137 | 1/2/2023 |
1.0.12-alpha | 134 | 1/2/2023 |
1.0.11-alpha | 127 | 12/30/2022 |
1.0.10-alpha | 121 | 12/30/2022 |