Muonroi.Tenancy
1.0.0-alpha.16
dotnet add package Muonroi.Tenancy --version 1.0.0-alpha.16
NuGet\Install-Package Muonroi.Tenancy -Version 1.0.0-alpha.16
<PackageReference Include="Muonroi.Tenancy" Version="1.0.0-alpha.16" />
<PackageVersion Include="Muonroi.Tenancy" Version="1.0.0-alpha.16" />
<PackageReference Include="Muonroi.Tenancy" />
paket add Muonroi.Tenancy --version 1.0.0-alpha.16
#r "nuget: Muonroi.Tenancy, 1.0.0-alpha.16"
#:package Muonroi.Tenancy@1.0.0-alpha.16
#addin nuget:?package=Muonroi.Tenancy&version=1.0.0-alpha.16&prerelease
#tool nuget:?package=Muonroi.Tenancy&version=1.0.0-alpha.16&prerelease
Muonroi.Tenancy
ASP.NET Core runtime layer for multi-tenancy: request-scoped tenant resolution middleware, per-tenant Redis cache, and OpenTelemetry metrics for auth failures.
Muonroi.Tenancy is the ASP.NET Core runtime package of the Muonroi multi-tenancy stack. It provides TenantResolutionMiddleware — which extracts the tenant ID from the HTTP request (header, path segment, or subdomain), validates it against the caller's JWT claim, and propagates it through TenantContext.CurrentTenantId for the duration of the request. The package also ships RedisTenantCache, a Redis wrapper that namespaces all keys under tenant:{tenantId}: for clean per-tenant isolation, and TenantResolutionTelemetry, which emits OTel-native counters for auth failures.
This package depends on Muonroi.Tenancy.Abstractions (contracts) and Muonroi.Tenancy.Core (context propagation and DI helpers).
Installation
dotnet add package Muonroi.Tenancy --prerelease
Quick Start
Register core tenancy services from Muonroi.Tenancy.Core, then add the middleware:
// Program.cs
using Muonroi.Tenancy.Core.Legacy; // AddTenantContext
using Muonroi.Tenancy; // TenantResolutionMiddleware
WebApplicationBuilder builder = WebApplication.CreateBuilder(args);
// Register tenant context and connection-string factory
builder.Services.AddTenantContext(options =>
{
builder.Configuration.GetSection("MultiTenant").Bind(options);
});
WebApplication app = builder.Build();
// Place after UseAuthentication / UseAuthorization so the JWT claim is available
app.UseAuthentication();
app.UseAuthorization();
app.UseMiddleware<TenantResolutionMiddleware>();
app.MapControllers();
app.Run();
After the middleware runs, read the resolved tenant ID anywhere in the request pipeline:
string? tenantId = TenantContext.CurrentTenantId;
Per-tenant Redis cache
// Inject IConnectionMultiplexer (registered via StackExchange.Redis)
IConnectionMultiplexer redis = ConnectionMultiplexer.Connect("localhost:6379");
var cache = new RedisTenantCache(redis, tenantId: "acme");
await cache.SetAsync("settings:theme", "dark", expiry: TimeSpan.FromHours(1));
RedisValue theme = await cache.GetAsync("settings:theme");
Features
- Multi-source tenant resolution: checks the custom request header (
X-Tenant-IdviaCustomHeader.TenantId), then the first URL path segment, then the subdomain — in that order of precedence. - Format validation: tenant IDs must match
^[a-zA-Z0-9][a-zA-Z0-9._-]{0,63}$; malformed input returns400 Bad Request. - JWT claim cross-check: if a resolved tenant ID conflicts with the
tenant_idJWT claim the middleware returns401 Unauthorized; a missing claim also yields401. - AsyncLocal propagation:
TenantContext.CurrentTenantIdis set for the request scope and cleared in thefinallyblock — safe for async code. - OpenTelemetry tracing: tenant ID is written to
Activity.Currentas both a tag (tenant.id) and baggage for distributed trace correlation. - Per-tenant Redis isolation:
RedisTenantCacheprefixes every key withtenant:{tenantId}:and usesSCAN(notKEYS) for bulk enumeration. - OTel metrics:
TenantResolutionTelemetryexposes aCounter<long>instrument (muonroi.tenancy.auth_failures) withfailure_reason,header_tenant_id, andclaim_tenant_iddimensions.
Configuration
Tenant context options live in Muonroi.Tenancy.Core. Bind them from appsettings.json:
{
"MultiTenant": {
"DefaultTenantId": "default",
"ConnectionStrings": {
"acme": "Server=acme-db;Database=acme;...",
"beta": "Server=beta-db;Database=beta;..."
}
}
}
Register in DI using the extension from Muonroi.Tenancy.Core:
builder.Services.AddTenantContext(options =>
builder.Configuration.GetSection("MultiTenant").Bind(options));
API Reference
| Type | Purpose |
|---|---|
TenantResolutionMiddleware |
ASP.NET Core middleware that resolves, validates, and propagates the tenant ID per request |
RedisTenantCache |
Redis wrapper that namespaces all keys under tenant:{tenantId}: to enforce per-tenant isolation |
TenantResolutionTelemetry |
Static helper exposing AuthFailureCounter (Counter<long>) and RecordAuthFailure(reason, header, claim) |
TenantContext (from Muonroi.Tenancy.Core) |
static string? CurrentTenantId — AsyncLocal holder for the active tenant |
Samples
- MultiTenantSaaS — SaaS pricing API demonstrating per-tenant rule evaluation with license-tier enforcement
Compatibility
- Target framework:
net8.0 - Requires:
Microsoft.AspNetCore.Appframework reference,StackExchange.Redis - License: Apache-2.0 (OSS)
Related Packages
Muonroi.Tenancy.Abstractions— contracts:ITenantContext,ITenantIdResolver,MultiTenantOptions, quota interfacesMuonroi.Tenancy.Core— core implementations:TenantContext,DefaultTenantIdResolver,TenantSchemaSelector,AddTenantContextDI extensionMuonroi.Tenancy.SiteProfile— site-profile layer for multi-site deployments with per-site EF Core / Dapper infrastructure
License
Apache-2.0. See LICENSE-APACHE for details.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net8.0 is compatible. 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. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 was computed. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net8.0
- Muonroi.Core.Abstractions (>= 1.0.0-alpha.16)
- Muonroi.Tenancy.Abstractions (>= 1.0.0-alpha.16)
- Muonroi.Tenancy.Core (>= 1.0.0-alpha.16)
- StackExchange.Redis (>= 2.8.37)
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 |
|---|---|---|
| 1.0.0-alpha.16 | 55 | 6/22/2026 |
| 1.0.0-alpha.15 | 72 | 5/31/2026 |
| 1.0.0-alpha.14 | 65 | 5/15/2026 |
| 1.0.0-alpha.13 | 64 | 5/2/2026 |
| 1.0.0-alpha.12 | 80 | 4/2/2026 |
| 1.0.0-alpha.11 | 74 | 4/2/2026 |
| 1.0.0-alpha.9 | 73 | 3/30/2026 |
| 1.0.0-alpha.8 | 158 | 3/28/2026 |
| 1.0.0-alpha.7 | 73 | 3/27/2026 |
| 1.0.0-alpha.5 | 70 | 3/27/2026 |
| 1.0.0-alpha.4 | 68 | 3/27/2026 |
| 1.0.0-alpha.3 | 68 | 3/27/2026 |
| 1.0.0-alpha.2 | 72 | 3/26/2026 |
| 1.0.0-alpha.1 | 84 | 3/8/2026 |