NetCoreBackend.NArchitecture.Core.MultiTenancy
2.0.1
dotnet add package NetCoreBackend.NArchitecture.Core.MultiTenancy --version 2.0.1
NuGet\Install-Package NetCoreBackend.NArchitecture.Core.MultiTenancy -Version 2.0.1
<PackageReference Include="NetCoreBackend.NArchitecture.Core.MultiTenancy" Version="2.0.1" />
<PackageVersion Include="NetCoreBackend.NArchitecture.Core.MultiTenancy" Version="2.0.1" />
<PackageReference Include="NetCoreBackend.NArchitecture.Core.MultiTenancy" />
paket add NetCoreBackend.NArchitecture.Core.MultiTenancy --version 2.0.1
#r "nuget: NetCoreBackend.NArchitecture.Core.MultiTenancy, 2.0.1"
#:package NetCoreBackend.NArchitecture.Core.MultiTenancy@2.0.1
#addin nuget:?package=NetCoreBackend.NArchitecture.Core.MultiTenancy&version=2.0.1
#tool nuget:?package=NetCoreBackend.NArchitecture.Core.MultiTenancy&version=2.0.1
Core.MultiTenancy
Multi-tenant infrastructure for SaaS applications. It performs tenant detection in order via JWT claim, HTTP header, and subdomain.
Tenant Detection (Priority Order)
1. JWT claim: "tenant_id" → Most secure, available after the token is validated
2. HTTP Header: X-Tenant-ID → For API clients and the development environment
3. Subdomain: acme.yourapp.com → For the production SaaS URL structure
Components
| Component | Description |
|---|---|
Tenant |
The tenant record entity (name, identifier/slug, domain, plan, defaultLocale, isActive) |
ITenantContext |
Interface injected into DI for reading the current tenant |
TenantContext |
Scoped ITenantContext implementation, reset per request |
ITenantService |
The tenant lookup interface that must be implemented in the application |
TenantEntitySetter |
ITenantEntitySetter implementation — automatically sets TenantId on Add operations |
TenantMiddleware |
Middleware that resolves the tenant on every request. Returns 401 when tenant_id is present in the JWT but the tenant does not exist in the DB. |
TenantClaimTypes |
Claim key constants (tenant_id, is_super_admin, is_impersonating) |
Setup
// Program.cs
builder.Services.AddMultiTenancy();
// → ITenantContext, TenantContext, and ITenantEntitySetter are registered automatically
builder.Services.AddScoped<ITenantService, YourTenantService>();
app.UseAuthentication();
app.UseMultiTenancy(); // must come AFTER UseAuthentication
app.UseAuthorization();
Why does middleware order matter?
TenantMiddleware's primary source is thetenant_idclaim in the JWT. This claim can only be read viaHttpContext.UserafterUseAuthentication()has run. If the order is reversed,User.Claimsstays empty, the middleware falls straight through to the header/subdomain fallbacks, and even logged-in users are routed to the wrong tenant (or to no tenant at all).
AddMultiTenancy() registers the following:
TenantContext(scoped)ITenantContext→TenantContext(scoped)ITenantEntitySetter→TenantEntitySetter(scoped) — no need to register it separately
Tenant Entity
public class Tenant : Entity<Guid>
{
public string Name { get; set; }
public string Identifier { get; set; } // slug: "acme"
public string? Domain { get; set; }
public bool IsActive { get; set; }
public TenantPlanType PlanType { get; set; }
public string? DefaultLocale { get; set; } // "tr", "de" — fallback when Accept-Language is absent
}
DefaultLocale: When the client does not send an Accept-Language header, LocalizationMiddleware uses this value as a fallback.
Identifiermust be unique. The framework does not perform a code-level uniqueness check; the DB constraint must be added in the consuming app'sDbContextconfiguration:modelBuilder.Entity<Tenant>().HasIndex(t => t.Identifier).IsUnique(); // Same for Domain (Domain is nullable, multi-tenant) modelBuilder.Entity<Tenant>() .HasIndex(t => t.Domain) .IsUnique() .HasFilter("[Domain] IS NOT NULL");Without this constraint, two Tenant records with the
acmeslug can be created, andGetBySlugAsyncreturns an ambiguous result.
SuperAdmin
A user with is_super_admin: true and tenant_id: null in the JWT can access all tenants' data (the EF Core global filter is bypassed). To switch to a specific tenant, an impersonation token is used.
Detailed documentation: TENANT.md
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net10.0 is compatible. 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. |
-
net10.0
- Microsoft.EntityFrameworkCore (>= 10.0.5)
- Microsoft.EntityFrameworkCore.InMemory (>= 10.0.5)
- Microsoft.EntityFrameworkCore.Relational (>= 10.0.5)
- NetCoreBackend.NArchitecture.Core.Persistence (>= 1.1.2)
- System.Linq.Dynamic.Core (>= 1.7.1)
NuGet packages (3)
Showing the top 3 NuGet packages that depend on NetCoreBackend.NArchitecture.Core.MultiTenancy:
| Package | Downloads |
|---|---|
|
NetCoreBackend.NArchitecture.Core.Security
Provides security utilities for hashing, encryption, JWT, authenticator, and more. |
|
|
NetCoreBackend.NArchitecture.Core.Application
Provide CQRS, Mediation, Pipelines, DTOs, and more for the Application Layer. |
|
|
NetCoreBackend.NArchitecture.Core.Localization.WebApi
Provide localization support for ASP.NET Web API. |
GitHub repositories
This package is not used by any popular GitHub repositories.