Muonroi.Tenancy.Core 1.0.0-alpha.16

This is a prerelease version of Muonroi.Tenancy.Core.
dotnet add package Muonroi.Tenancy.Core --version 1.0.0-alpha.16
                    
NuGet\Install-Package Muonroi.Tenancy.Core -Version 1.0.0-alpha.16
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Muonroi.Tenancy.Core" Version="1.0.0-alpha.16" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Muonroi.Tenancy.Core" Version="1.0.0-alpha.16" />
                    
Directory.Packages.props
<PackageReference Include="Muonroi.Tenancy.Core" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add Muonroi.Tenancy.Core --version 1.0.0-alpha.16
                    
#r "nuget: Muonroi.Tenancy.Core, 1.0.0-alpha.16"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package Muonroi.Tenancy.Core@1.0.0-alpha.16
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=Muonroi.Tenancy.Core&version=1.0.0-alpha.16&prerelease
                    
Install as a Cake Addin
#tool nuget:?package=Muonroi.Tenancy.Core&version=1.0.0-alpha.16&prerelease
                    
Install as a Cake Tool

Muonroi.Tenancy.Core

Runtime building blocks for shared-database multi-tenancy: AsyncLocal-backed tenant context, multi-source tenant ID resolution, per-tenant connection-string mapping, schema selection, quota tracking, and security validation.

NuGet License: Apache 2.0

Muonroi.Tenancy.Core implements the core tenancy services consumed by Muonroi.Tenancy (the ASP.NET middleware layer) and your own application code. It provides TenantContext — an AsyncLocal<string>-backed store for the current tenant ID — alongside a five-source DefaultTenantIdResolver (claim → header → route → path → subdomain), MappingTenantConnectionStringFactory for per-tenant connection strings, TenantSchemaSelector for separate-schema isolation, and TenantQuotaTracker for distributed-cache-backed quota enforcement. It depends on Muonroi.Tenancy.Abstractions for contracts and Muonroi.Quota.Abstractions for quota types.

Installation

dotnet add package Muonroi.Tenancy.Core --prerelease

Quick Start

The services in this package can be registered individually without the license-gated AddTenantContext() helper. The Quickstart.Tenancy sample demonstrates this pattern:

using Muonroi.Tenancy.Abstractions;
using Muonroi.Tenancy.Abstractions.Interfaces;
using Muonroi.Tenancy.Core;

WebApplicationBuilder builder = WebApplication.CreateBuilder(args);

// Bind options consumed by TenantSchemaSelector and MappingTenantConnectionStringFactory.
builder.Services.Configure<MultiTenantOptions>(
    builder.Configuration.GetSection(MultiTenantOptions.SectionName)); // "MultiTenantConfigs"
builder.Services.Configure<TenantConnectionStringsOptions>(
    builder.Configuration.GetSection(TenantConnectionStringsOptions.SectionName)); // "TenantConnectionStrings"

// Ambient tenant context (AsyncLocal-backed).
builder.Services.AddScoped<ITenantContext, TenantContext>();

// HTTP-based tenant ID resolver: claim → header → route → path → subdomain.
builder.Services.AddScoped<ITenantIdResolver, DefaultTenantIdResolver>();

// Schema selector for SeparateSchema isolation.
builder.Services.AddSingleton<TenantSchemaSelector>();

// Per-tenant connection-string factory with a fallback.
builder.Services.AddSingleton<ITenantConnectionStringFactory>(sp =>
{
    IOptions<TenantConnectionStringsOptions> opts =
        sp.GetRequiredService<IOptions<TenantConnectionStringsOptions>>();
    string fallback = builder.Configuration.GetConnectionString("Default")
                      ?? "Host=localhost;Database=app;Username=app;Password=app";
    return new MappingTenantConnectionStringFactory(opts, fallback);
});

// Quota management (distributed-cache-backed tracker + in-memory store).
builder.Services.AddTenantQuotaManagement();

Read the current tenant ID anywhere in your application:

// Via DI (request-scoped):
public class MyService(ITenantContext tenantContext)
{
    public void DoWork()
    {
        string? tenantId = tenantContext.TenantId;
    }
}

// Via static ambient (background jobs, EF filters):
string? tenantId = TenantContext.CurrentTenantId;

For admin/seeding operations that must bypass EF global query filters:

using (new MSeedingScope())
{
    // TenantContext.AllowCrossTenantAccess == true here.
    // EF global filters for ITenantScoped entities are bypassed.
    await SeedDefaultRolesAsync(dbContext);
} // AllowCrossTenantAccess restored to previous value on dispose.

Features

  • TenantContextAsyncLocal<string?>-backed ITenantContext; exposes CurrentTenantId (static, for EF filters) and AllowCrossTenantAccess (static, bypasses EF global filters when true)
  • DefaultTenantIdResolver — resolves tenant ID from JWT claim → X-Tenant-Id header → route value (tenantId/tenant) → URL path segment → subdomain; skips reserved prefixes (api, swagger, health, grpc, v1v3)
  • TenantSchemaSelector — maps tenant ID to a database schema name for SeparateSchema isolation and optionally rewrites PostgreSQL connection strings with SearchPath
  • MappingTenantConnectionStringFactory — looks up a per-tenant connection string from TenantConnectionStringsOptions.ConnectionStrings; falls back to a supplied default
  • DefaultTenantConnectionStringFactory — single-connection-string factory for shared-database setups
  • TenantSecurityValidator — static validator that cross-checks context, claim, and header tenant IDs; returns typed error codes (missing-tenant-context, missing-tenant-claim, tenant-mismatch, header-claim-mismatch)
  • TenantQuotaTracker — distributed-cache-backed ITenantQuotaTracker; checks and increments usage counters keyed by tenant + QuotaType + time window; falls back to TenantQuotaPresets.Free when no quota record is found
  • InMemoryTenantQuotaStore — in-process ITenantQuotaStore for development and testing
  • MSeedingScopeIDisposable scope that sets TenantContext.AllowCrossTenantAccess = true for the duration of database seeding; restores the previous value on dispose
  • ContextMirrorScopeIDisposable scope that mirrors an ISystemExecutionContext into TenantContext.CurrentTenantId, UserContext, and an optional log scope; used by background jobs and message consumers
  • AddTenantQuotaManagement() — registers InMemoryTenantQuotaStore (singleton) and TenantQuotaTracker (scoped)
  • Legacy namespace (Muonroi.Tenancy.Core.Legacy) — preserved MultiTenantConfigs, TenantContextMiddleware, and AddTenantContext() + AddTenantIdResolver<Tr>() helpers for projects that have not yet migrated to the current API

Configuration

MultiTenantOptions (section: "MultiTenantConfigs")

Defined in Muonroi.Tenancy.Abstractions. Consumed by TenantSchemaSelector.

{
  "MultiTenantConfigs": {
    "Strategy": "SharedDatabase"
  }
}

Strategy values: SharedDatabase, SeparateSchema. When SeparateSchema is set, TenantSchemaSelector.ResolveSchema(tenantId) returns a sanitized schema name and ApplyToConnectionString appends SearchPath=<schema> to PostgreSQL connection strings.

TenantConnectionStringsOptions (section: "TenantConnectionStrings")

Consumed by MappingTenantConnectionStringFactory.

{
  "TenantConnectionStrings": {
    "ConnectionStrings": {
      "tenant-a": "Host=pg-a;Database=tenant_a;Username=app;Password=secret",
      "tenant-b": "Host=pg-b;Database=tenant_b;Username=app;Password=secret"
    }
  }
}

Legacy MultiTenantConfigs (section: "MultiTenantConfigs")

Used by Legacy.AddTenantContext() only:

{
  "MultiTenantConfigs": {
    "Enabled": true,
    "RequireTenantClaimForAuthenticatedUser": true
  }
}

AddTenantContext() requires AddLicenseProtection() to be called first and enforces the MultiTenant license feature.

API Reference

Type Purpose
TenantContext ITenantContext implementation; AsyncLocal-backed TenantId and CurrentTenantId; AllowCrossTenantAccess flag for EF filter bypass
DefaultTenantIdResolver ITenantIdResolver — claim → header → route → path → subdomain resolution
MappingTenantConnectionStringFactory ITenantConnectionStringFactory — dictionary lookup with fallback
DefaultTenantConnectionStringFactory ITenantConnectionStringFactory — single connection string, shared-database
TenantSchemaSelector Schema name resolution and PostgreSQL SearchPath injection for separate-schema isolation
TenantSecurityValidator Static TryValidate() — cross-checks context, claim, and header; returns error codes
TenantQuotaTracker ITenantQuotaTrackerCheckQuotaAsync, IncrementUsageAsync, GetUsageAsync, ResetDailyQuotasAsync
InMemoryTenantQuotaStore ITenantQuotaStore — in-memory implementation for dev/test
MSeedingScope IDisposable — enables cross-tenant EF access during database seeding
ContextMirrorScope IDisposable — mirrors ISystemExecutionContext into ambient tenant/user context + log scope
TenantQuotaServiceCollectionExtensions.AddTenantQuotaManagement() Registers InMemoryTenantQuotaStore (singleton) and TenantQuotaTracker (scoped)
Legacy.TenantServiceCollectionExtensions.AddTenantContext() License-gated full registration: context, resolver, middleware (legacy API)
Legacy.TenantServiceCollectionExtensions.AddTenantIdResolver<Tr>() Replaces DefaultTenantIdResolver with a custom resolver (legacy API)

Samples

  • Quickstart.Tenancy — registers TenantContext, DefaultTenantIdResolver, TenantSchemaSelector, and MappingTenantConnectionStringFactory without the license gate; mounts TenantResolutionMiddleware on a branch

Compatibility

  • Target framework: net8.0
  • License: Apache-2.0 (OSS)
  • Muonroi.Tenancy.Abstractions — contracts: ITenantContext, ITenantIdResolver, ITenantConnectionStringFactory, MultiTenantOptions, TenantConnectionStringsOptions
  • Muonroi.Tenancy — ASP.NET integration: TenantResolutionMiddleware and Redis tenant cache
  • Muonroi.Quota.AbstractionsITenantQuotaTracker, ITenantQuotaStore, QuotaType, TenantQuota

License

Apache-2.0. See LICENSE-APACHE for the full text.

Product 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. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages (18)

Showing the top 5 NuGet packages that depend on Muonroi.Tenancy.Core:

Package Downloads
Muonroi.Data.EntityFrameworkCore

Entity Framework Core infrastructure for Muonroi: MDbContext with audit, soft-delete, multi-tenant filters, and repository base.

Muonroi.Caching.Memory

Multi-level in-memory + distributed cache implementation with tenant-aware key isolation and stampede protection.

Muonroi.Tenancy.SiteProfile

Per-site DI registration pattern for schema-divergent multi-tenancy. Wire correct DbContext, services, and mappers per site deployment.

Muonroi.BackgroundJobs.Abstractions

Background job contracts: IBackgroundJob, IScheduledJob, and job context interfaces for Muonroi job scheduler integrations.

Muonroi.Governance

OSS license governance implementation: basic license verification, capability resolution, and no-op implementations for free-tier usage.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.0.0-alpha.16 227 6/22/2026
1.0.0-alpha.15 252 5/31/2026
1.0.0-alpha.14 226 5/15/2026
1.0.0-alpha.13 195 5/2/2026
1.0.0-alpha.12 118 4/2/2026
1.0.0-alpha.11 159 4/2/2026
1.0.0-alpha.9 104 3/30/2026
1.0.0-alpha.8 358 3/28/2026
1.0.0-alpha.7 83 3/27/2026
1.0.0-alpha.5 84 3/27/2026
1.0.0-alpha.4 82 3/27/2026
1.0.0-alpha.3 78 3/27/2026
1.0.0-alpha.2 92 3/26/2026
1.0.0-alpha.1 129 3/8/2026