# AmbientTenantScope

> Tracon documentation. Tracon is a .NET package family that adds a control
> plane on Microsoft Agent Framework, published as NuGet packages that run
> inside your own ASP.NET Core application.
>
> Page: https://tracon.dev/api/tracon.ambienttenantscope/
> Summary: AmbientTenantScope: The ambient passing mechanism for running an operation executed in the background (outside an HTTP request) as a specific tenant.

<div class="api-provenance">Namespace Tracon · Assembly <code>Tracon.Abstractions.dll</code></div>

The ambient passing mechanism for running an operation executed in the
background (outside an HTTP request) as a specific tenant.

```csharp
public static class AmbientTenantScope
```

<dl class="api-relations"><dt>Inheritance</dt><dd><a href="https://learn.microsoft.com/dotnet/api/system.object">object</a> ← <a href="/api/tracon.ambienttenantscope/">AmbientTenantScope</a></dd><dt>Inherited Members</dt><dd><a href="https://learn.microsoft.com/dotnet/api/system.object.gettype">object.GetType()</a>, <a href="https://learn.microsoft.com/dotnet/api/system.object.memberwiseclone">object.MemberwiseClone()</a>, <a href="https://learn.microsoft.com/dotnet/api/system.object.tostring">object.ToString()</a>, <a href="https://learn.microsoft.com/dotnet/api/system.object.equals#system-object-equals(system-object)">object.Equals(object?)</a>, <a href="https://learn.microsoft.com/dotnet/api/system.object.equals#system-object-equals(system-object-system-object)">object.Equals(object?, object?)</a>, <a href="https://learn.microsoft.com/dotnet/api/system.object.referenceequals">object.ReferenceEquals(object?, object?)</a>, <a href="https://learn.microsoft.com/dotnet/api/system.object.gethashcode">object.GetHashCode()</a></dd></dl>

## Remarks

The [ITenantContext](/api/tracon.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](/api/tracon.itenantcontext/) implementations check it before their own default resolution.

## Properties

### <a id="Tracon_AmbientTenantScope_Current"></a> Current

The current ambient tenant if set right now; [null](https://learn.microsoft.com/dotnet/csharp/language-reference/keywords/null) otherwise.

```csharp
public static string? Current { get; }
```

#### Property Value

 [string](https://learn.microsoft.com/dotnet/api/system.string)?

## Methods

### <a id="Tracon_AmbientTenantScope_Begin_System_String_"></a> Begin\(string\)

Sets the ambient tenant for the duration of the scope.

```csharp
public static IDisposable Begin(string tenantId)
```

#### Parameters

`tenantId` [string](https://learn.microsoft.com/dotnet/api/system.string)

The tenant identifier to use for the duration of the scope.

#### Returns

 [IDisposable](https://learn.microsoft.com/dotnet/api/system.idisposable)

An object that restores the previous value when
[IDisposable.Dispose](https://learn.microsoft.com/dotnet/api/system.idisposable) is called. Nested use is safe.

#### Remarks

The value is stored in the form [AmbientTenantScope.Normalize](/api/tracon.ambienttenantscope/#Tracon_AmbientTenantScope_Normalize_System_String_) returns, so
[AmbientTenantScope.Current](/api/tracon.ambienttenantscope/#Tracon_AmbientTenantScope_Current) is always canonical whatever letter case the
caller wrote.

#### Exceptions

 [ArgumentException](https://learn.microsoft.com/dotnet/api/system.argumentexception)

`tenantId` is empty or whitespace only.

### <a id="Tracon_AmbientTenantScope_Normalize_System_String_"></a> Normalize\(string\)

Returns the canonical form a tenant identifier is compared and stored in.

```csharp
public static string Normalize(string tenantId)
```

#### Parameters

`tenantId` [string](https://learn.microsoft.com/dotnet/api/system.string)

The tenant identifier as written by the caller.

#### Returns

 [string](https://learn.microsoft.com/dotnet/api/system.string)

The canonical (invariant lower-case) form.

#### 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](/api/tracon.tenantproviderbinding/#Tracon_TenantProviderBinding_NormalizeProviderName_System_String_) 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](/api/tracon.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

 [ArgumentException](https://learn.microsoft.com/dotnet/api/system.argumentexception)

`tenantId` is null, empty or whitespace only.

### <a id="Tracon_AmbientTenantScope_NormalizeOrNull_System_String_"></a> NormalizeOrNull\(string?\)

Returns the canonical form of an optional tenant identifier.

```csharp
public static string? NormalizeOrNull(string? tenantId)
```

#### Parameters

`tenantId` [string](https://learn.microsoft.com/dotnet/api/system.string)?

The tenant identifier, or [null](https://learn.microsoft.com/dotnet/csharp/language-reference/keywords/null).

#### Returns

 [string](https://learn.microsoft.com/dotnet/api/system.string)?

The canonical form; [null](https://learn.microsoft.com/dotnet/csharp/language-reference/keywords/null) when `tenantId`
is [null](https://learn.microsoft.com/dotnet/csharp/language-reference/keywords/null).

#### Remarks

A [null](https://learn.microsoft.com/dotnet/csharp/language-reference/keywords/null) tenant means "every tenant" in the query types
that accept one, so it passes through unchanged.

#### Exceptions

 [ArgumentException](https://learn.microsoft.com/dotnet/api/system.argumentexception)

`tenantId` is empty or whitespace only.
