Overview
Use Multi-Tenancy when your application needs tenant context resolution, request isolation, and tenant-aware data protection inside a shared application host. PrimusSaaS resolves tenant identity from configured sources and carries that context through middleware, EF Core enforcement, and background work helpers.
Current workspace validation supports a stable release posture for the Multi-Tenancy core and shipped integration packages. The stability claim applies to the documented pooled shared-table model, not to dedicated-database orchestration or a full tenancy platform.
This module implements pooled, shared-table isolation: all tenants share the same database schema with a TenantId discriminator column on each table. Dedicated-database isolation and partitioned-schema (separate schema per tenant) are outside the scope of this package. Apply your own database-level controls if your compliance program requires physical data separation.
Use this module when
- You need a tenant ID resolved from claims, headers, routes, subdomain, or membership.
- You need authenticated requests without tenant context blocked by default.
- You need EF Core write enforcement for tenant-owned entities.
- You need tenant-aware rate limiting, entitlements, or lifecycle checks in the same host.
- You need a composable tenant context that can flow into RBAC or background jobs.
Do not start here if
- You need separate databases or separate schemas per tenant. This package does not implement that model.
- You do not yet have authentication in place. Start with Identity Validator.
- You need a full cross-module onboarding path first. Use Combined .NET Integration.
- You are looking for an admin portal. The package exposes APIs and hooks, not a first-party UI.
Start here
| Goal | Start with | What it proves |
|---|---|---|
| Fastest first success | Verified .NET Quickstart | The shortest supported ASP.NET Core setup, aligned to current-run middleware and regression tests. |
| Full package setup | Integration Guide | Package registration, middleware order, EF Core enforcement, rate limiting, entitlements, and management endpoints. |
| Architecture boundaries before rollout | Enterprise Gap Analysis | What is in scope, what is application-owned, and where production teams still need extra platform work. |
| Compose with auth and RBAC | Combined .NET Integration | The recommended combined path for Identity Validator, Multi-Tenancy, and RBAC in one host. |
What this module does
- Five built-in resolution strategies evaluated in fixed registration order.
MembershipValidatedTenantResolutionStrategy— validates explicit tenant selection against caller membership before accepting it, closing the trust gap in header-only resolution.- Subdomain-based tenant resolution (opt-in).
- Membership-based resolution via
ITenantMembershipStore. - Isolation middleware — returns
401 Unauthorizedwhen an authenticated request has no tenant context. - Per-tenant rate limiting with a configurable window and request cap.
- Tier-based feature gating with
UsePrimusTenantEntitlements()+RequirePrimusFeature(...). - EF Core interceptor that enforces
TenantIdonAddedentities and blocks cross-tenant mutations (Modified,Deleted). - Automatic
TenantIdpopulation on new entities throughITenantOwnedEntity. - Structured audit sink (
ITenantAuditSink) — emitted on isolation blocks, lifecycle changes, rate-limit hits, and cross-tenant write attempts. Default sink writes toILogger. - Tenant provisioning hook (
ITenantProvisioningHandler) — called once on first tenant creation; default is a no-op. TenantExecutionContext— captures current tenant state and restores it in background jobs / hosted services whereHttpContextis unavailable.AmbientTenantContextAccessor—ITenantContextAccessorimplementation for background workers; sources values fromTenantQueryFilterProviderrather thanHttpContext.- Tenant management API includes list/search, summary metrics, and hard-delete in addition to lifecycle operations.
- Tier-aware rate-limiting via
PerTierRateLimits(fallback after per-tenant overrides). - Tier entitlement mapping via
PerTierEntitlementswithTenantEntitlementDeniedaudit events on denied access. - Resource isolation policy contract for blob/file/search naming validation (
ITenantResourceIsolationPolicy). - RBAC scope composition helper to forward tenant identity to the RBAC module.
- Store abstraction with In-Memory and EF Core adapters.
Core concepts
| Concept | Description |
|---|---|
TenantContext | The current tenant identity for the request or execution scope. |
TenantResolutionResult | The resolved TenantContext plus the strategy source that produced it. |
ITenantContextAccessor | The service your application reads to get the current tenant. |
ITenantResolver | The orchestrator that runs the registered resolution strategies in order. |
ITenantResolutionStrategy | The per-source contract for claims, headers, routes, subdomain, or custom resolution. |
ITenantMembershipStore | The membership source used for active-tenant resolution and membership-validated selection. |
ITenantOwnedEntity | The EF Core marker interface that enables automatic TenantId enforcement. |
ITenantAuditSink | The structured audit hook for isolation, lifecycle, entitlement, and rate-limit events. |
TenantExecutionContext | The snapshot helper for carrying tenant state into background work. |
ITenantResourceIsolationPolicy | The contract for tenant-safe naming rules outside relational storage. |
Resolution strategy priority
Built-in strategies are evaluated in order. The first successful result wins.
| Priority | Strategy | Source |
|---|---|---|
| 1 | ClaimsTenantResolutionStrategy | JWT claim (TenantClaimType, default tid) |
| 2 | HeaderTenantResolutionStrategy | HTTP header (TenantHeaderName, default X-Tenant-Id) — accepts at face value; see trust-boundary note in the Integration Guide |
| 3 | RouteTenantResolutionStrategy | Route value (TenantRouteKey, default tenantId) |
| 4 | SubdomainTenantResolutionStrategy | HTTP host subdomain (opt-in via EnableSubdomainResolution) |
| 5 | DefaultMembershipTenantResolutionStrategy | Active membership from ITenantMembershipStore |
For multi-tenant user flows (one user, multiple tenants) replace the header strategy with MembershipValidatedTenantResolutionStrategy (registered via AddPrimusMultiTenancyMembershipValidatedSelection()). It validates the requested tenant against the caller's active memberships before accepting it.
Packages
| Package | Purpose |
|---|---|
PrimusSaaS.MultiTenancy | Core contracts, resolver, and resolution strategies |
PrimusSaaS.MultiTenancy.AspNetCore | ASP.NET Core middleware and HttpContext accessor |
PrimusSaaS.MultiTenancy.EFCore | EF Core write interceptor and ModelBuilder schema extension |
PrimusSaaS.MultiTenancy.InMemory | In-Memory membership store for development and testing |
Current validated evidence
dotnet test sdk/dotnet/tests/PrimusSaaS.MultiTenancy.Tests/PrimusSaaS.MultiTenancy.Tests.csproj --no-restore --nologoCurrent run:399/399passed acrossnet8.0,net9.0, andnet10.0.dotnet test sdk/dotnet/tests/PrimusSaaS.MultiTenancy.Tests/PrimusSaaS.MultiTenancy.Tests.csproj --framework net9.0 --filter FullyQualifiedName~Regression /p:CollectCoverage=false --nologoCurrent run:36/36passed.sdk/dotnet/tests/PrimusSaaS.MultiTenancy.Tests/Integration/TenantIsolationMiddlewareTests.csCurrent implementation returns401 Unauthorizedwhen an authenticated request has no tenant context. Suspended tenants still return403 Forbidden, and deleted tenants return404 Not Found.sdk/dotnet/src/PrimusSaaS.MultiTenancy/DependencyInjection/MultiTenancyProductionValidationHostedService.csCurrent implementation fails production startup when header-based tenant selection is used without membership validation in a production-style host.
Related modules
- RBAC for role-based access control scoped by tenant.
- Identity Validator for JWT authentication.
- Combined .NET Integration for the recommended cross-module onboarding path.