.NET API
AmbientTenantScope
Tracon.Abstractions.dllThe ambient passing mechanism for running an operation executed in the background (outside an HTTP request) as a specific tenant.
public static class AmbientTenantScope- Inheritance
- object ← AmbientTenantScope
- Inherited Members
- object.GetType(), object.MemberwiseClone(), object.ToString(), object.Equals(object?), object.Equals(object?, object?), object.ReferenceEquals(object?, object?), object.GetHashCode()
Remarks
Section titled “Remarks”The ITenantContext implementations (the single-tenant
default, the HTTP-based multi-tenant resolver) are singletons and read the
tenant either from a fixed default or from HttpContext. Which
tenant a scheduled job runs for is neither fixed nor lives in an HTTP
context — it is carried inside JobRecord.TenantId. This class
provides a pass-through using the same Threading.AsyncLocal pattern
IHttpContextAccessor uses: while the value is set, both
ITenantContext implementations check it before their own default resolution.
Properties
Section titled “Properties”Current
Section titled “ Current”The current ambient tenant if set right now; null otherwise.
public static string? Current { get; }Property Value
Section titled “Property Value”Methods
Section titled “Methods”Begin(string)
Section titled “ Begin(string)”Sets the ambient tenant for the duration of the scope.
public static IDisposable Begin(string tenantId)Parameters
Section titled “Parameters”tenantId string
The tenant identifier to use for the duration of the scope.
Returns
Section titled “Returns”An object that restores the previous value when IDisposable.Dispose is called. Nested use is safe.
Remarks
Section titled “Remarks”The value is stored in the form AmbientTenantScope.Normalize returns, so AmbientTenantScope.Current is always canonical whatever letter case the caller wrote.
Exceptions
Section titled “Exceptions”tenantId is empty or whitespace only.
Normalize(string)
Section titled “ Normalize(string)”Returns the canonical form a tenant identifier is compared and stored in.
public static string Normalize(string tenantId)Parameters
Section titled “Parameters”tenantId string
The tenant identifier as written by the caller.
Returns
Section titled “Returns”The canonical (invariant lower-case) form.
Remarks
Section titled “Remarks”The tenant identifier is the product’s primary isolation key, and it is matched case-insensitively. Every layer that compares or persists one applies this first: the tenant context, the allow-list check, the endpoint filter, and every store.
Normalizing the value (rather than comparing case-insensitively
at query time) is deliberate, and it is the same choice
TenantProviderBinding.NormalizeProviderName makes: a bare
= predicate then behaves identically on PostgreSQL, SQLite and
SQL Server whatever their collation, the primary key keeps rejecting
duplicates on all three, and the index stays usable. Without it the
authorization layer and the storage layer disagree about whether
acme and Acme are one tenant — on SQL Server’s
case-insensitive default collation they are one, on PostgreSQL and
SQLite they are two.
A consumer that implements ITenantContext or a store itself must apply this to the value it returns, writes and queries with. A store that skips it is case-sensitive while the rest of the system is not.
Exceptions
Section titled “Exceptions”tenantId is null, empty or whitespace only.
NormalizeOrNull(string?)
Section titled “ NormalizeOrNull(string?)”Returns the canonical form of an optional tenant identifier.
public static string? NormalizeOrNull(string? tenantId)Parameters
Section titled “Parameters”tenantId string?
The tenant identifier, or null.
Returns
Section titled “Returns”The canonical form; null when tenantId
is null.
Remarks
Section titled “Remarks”A null tenant means “every tenant” in the query types that accept one, so it passes through unchanged.
Exceptions
Section titled “Exceptions”tenantId is empty or whitespace only.