SkillAgentSearch skills...

Mellon.MultiTenant

A library created to help with multi-tenant applications made in net

Install / Use

/learn @Pub-Dev/Mellon.MultiTenant

README

[![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 | Nuget | Nuget | | Mellon.MultiTenant.Base | Nuget | Nuget | | Mellon.MultiTenant.ConfigServer | Nuget | Nuget | | Mellon.MultiTenant.Azure | Nuget | Nuget | | Mellon.MultiTenant.Hangfire | Nuget | Nuget |

Downloads GitHublicense CI

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

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
View on GitHub
GitHub Stars41
CategoryDevelopment
Updated20d ago
Forks6

Languages

C#

Security Score

95/100

Audited on Mar 11, 2026

No findings