Skip to main content
Version: Current

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.

Maturity: Stable

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.

Isolation model scope

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

GoalStart withWhat it proves
Fastest first successVerified .NET QuickstartThe shortest supported ASP.NET Core setup, aligned to current-run middleware and regression tests.
Full package setupIntegration GuidePackage registration, middleware order, EF Core enforcement, rate limiting, entitlements, and management endpoints.
Architecture boundaries before rolloutEnterprise Gap AnalysisWhat is in scope, what is application-owned, and where production teams still need extra platform work.
Compose with auth and RBACCombined .NET IntegrationThe 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 Unauthorized when 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 TenantId on Added entities and blocks cross-tenant mutations (Modified, Deleted).
  • Automatic TenantId population on new entities through ITenantOwnedEntity.
  • Structured audit sink (ITenantAuditSink) — emitted on isolation blocks, lifecycle changes, rate-limit hits, and cross-tenant write attempts. Default sink writes to ILogger.
  • 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 where HttpContext is unavailable.
  • AmbientTenantContextAccessorITenantContextAccessor implementation for background workers; sources values from TenantQueryFilterProvider rather than HttpContext.
  • 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 PerTierEntitlements with TenantEntitlementDenied audit 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

ConceptDescription
TenantContextThe current tenant identity for the request or execution scope.
TenantResolutionResultThe resolved TenantContext plus the strategy source that produced it.
ITenantContextAccessorThe service your application reads to get the current tenant.
ITenantResolverThe orchestrator that runs the registered resolution strategies in order.
ITenantResolutionStrategyThe per-source contract for claims, headers, routes, subdomain, or custom resolution.
ITenantMembershipStoreThe membership source used for active-tenant resolution and membership-validated selection.
ITenantOwnedEntityThe EF Core marker interface that enables automatic TenantId enforcement.
ITenantAuditSinkThe structured audit hook for isolation, lifecycle, entitlement, and rate-limit events.
TenantExecutionContextThe snapshot helper for carrying tenant state into background work.
ITenantResourceIsolationPolicyThe contract for tenant-safe naming rules outside relational storage.

Resolution strategy priority

Built-in strategies are evaluated in order. The first successful result wins.

PriorityStrategySource
1ClaimsTenantResolutionStrategyJWT claim (TenantClaimType, default tid)
2HeaderTenantResolutionStrategyHTTP header (TenantHeaderName, default X-Tenant-Id) — accepts at face value; see trust-boundary note in the Integration Guide
3RouteTenantResolutionStrategyRoute value (TenantRouteKey, default tenantId)
4SubdomainTenantResolutionStrategyHTTP host subdomain (opt-in via EnableSubdomainResolution)
5DefaultMembershipTenantResolutionStrategyActive 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

PackagePurpose
PrimusSaaS.MultiTenancyCore contracts, resolver, and resolution strategies
PrimusSaaS.MultiTenancy.AspNetCoreASP.NET Core middleware and HttpContext accessor
PrimusSaaS.MultiTenancy.EFCoreEF Core write interceptor and ModelBuilder schema extension
PrimusSaaS.MultiTenancy.InMemoryIn-Memory membership store for development and testing

Current validated evidence

  • dotnet test sdk/dotnet/tests/PrimusSaaS.MultiTenancy.Tests/PrimusSaaS.MultiTenancy.Tests.csproj --no-restore --nologo Current run: 399/399 passed across net8.0, net9.0, and net10.0.
  • dotnet test sdk/dotnet/tests/PrimusSaaS.MultiTenancy.Tests/PrimusSaaS.MultiTenancy.Tests.csproj --framework net9.0 --filter FullyQualifiedName~Regression /p:CollectCoverage=false --nologo Current run: 36/36 passed.
  • sdk/dotnet/tests/PrimusSaaS.MultiTenancy.Tests/Integration/TenantIsolationMiddlewareTests.cs Current implementation returns 401 Unauthorized when an authenticated request has no tenant context. Suspended tenants still return 403 Forbidden, and deleted tenants return 404 Not Found.
  • sdk/dotnet/src/PrimusSaaS.MultiTenancy/DependencyInjection/MultiTenancyProductionValidationHostedService.cs Current implementation fails production startup when header-based tenant selection is used without membership validation in a production-style host.