Mellon.MultiTenant
A library created to help with multi-tenant applications made in net
Install / Use
/learn @Pub-Dev/Mellon.MultiTenantREADME
[![Contributors][contributors-shield]][contributors-url] [![Forks][forks-shield]][forks-url] [![Stargazers][stars-shield]][stars-url] [![Issues][issues-shield]][issues-url] [![LinkedIn][linkedin-shield]][linkedin-url] [![LinkedIn][linkedin-shield]][linkedin2-url]
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
- net8
- 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",
"SkipTenantCheckPaths": ["^/swagger.*"],
"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 |
| SkipTenantCheckPaths | Endpoints which the tenant do not need to be identified, for example: Swagger endpoints, you can use a regex string ^/swagger.* | 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 😉👍
WithSkipTenantCheckPaths(string)
- Add a path that will be skipped during the tenant identification
WithSkipTenantCheckPaths(params string[])
- Add paths that will be skipped during the tenant identification
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
LoadFromEndpoint(Func<EndpointSettings, IConfiguration, string[]> func) and LoadFromEndpoint<T>(Func<T, string> func)
- Define a Func or pass a type to define how the tenant list will be loaded from a http endpoint, to make it work you need to pass a new set of properties on the app settings
"MultiTenant": {
// other settings...
"Endpoint": {
"Url": "[endpoint]",
"Method": "GET",
"Authorization": "Basic $user $password"
},
// other settings...
}
If the endpoint has authorization you can set the credencials on the property Authorization
You can pass the Func and do what you see fit when getting the list of tenants
Example:
services
.AddMultiTenant(options => options.LoadFromEndpoint((endpointOptions, configuration) =>
{
var request = new HttpRequestMessage()
{
RequestUri = new Uri(endpointOptions.Url),
Method = new HttpMethod(endpointOptions.Method),
};
if (!string.IsNullOrEmpty(endpointOptions.Authorization))
{
request.Headers.Add("Authorization", endpointOptions.Authorization);
}
using (var client = new HttpClient())
{
var result = client.Send(request);
if (result.IsSuccessStatusCode)
{
var data = result.Content.ReadFromJsonAsync<IEnumerable<Tenant>>().GetAwaiter().GetResult();
return data!.Select(x => x.Id).ToArray();
}
else
{
var statusCode = result.StatusCode;
var reason = result.ReasonPhr
