Docs
Tenantry CoreAPI reference

ITenantStore<TKey> interface

Namespace: Tenantry · Package: Tenantry.Core · API reference

Persists and retrieves tenant definitions. Implement this interface to back tenants with a database, configuration file, or any other store.

A custom store registered via UseStore<TStore>() is scoped, and Tenantry resolves it per operation from a fresh dependency-injection scope (so singleton/background services can read tenants without capturing it). Implementations may therefore depend on scoped services such as a DbContext, but must not assume a singleton lifetime or cache scope-bound state across calls.

Return every tenant that exists, suspended or inactive ones included, from both methods: tools that maintain each tenant's database, such as migrations, find tenants here. Decide whether a tenant may be served elsewhere: with an access validator for HTTP requests, and in your own code for background work.

public interface ITenantStore<TKey> where TKey : IEquatable<TKey>, IParsable<TKey>

Type parameters

Derived types: InMemoryTenantStore<TKey>.

Methods

FindByIdentifierAsync(string, CancellationToken)

Returns the tenant a request's identifier names, or null if it names none. An identifier is what a resolver reads from a request: the tenant's id, or a name your store maps to a tenant, such as a subdomain (acme), a slug in a route or a custom domain (app.acme.com).

ValueTask<ITenantDescriptor<TKey>?> FindByIdentifierAsync(string identifier, CancellationToken cancellationToken = default)

Parameters:

  • identifier string: The identifier, as the resolver returned it.
  • cancellationToken CancellationToken: Cancels the lookup.

Returns: ValueTask<ITenantDescriptor<TKey>>

By default the identifier is the tenant's id: it is parsed as TKey with the invariant culture and looked up with ITenantStore<TKey>.GetTenantAsync, and an identifier that does not parse, or parses to the key type's default (Empty, 0) or an empty string, names no tenant. Implement it to resolve tenants by another name, for example a Guid-keyed store whose tenants have slugs. A store that wraps another (to log, say) must forward it to the inner store: otherwise it gets this default, which never reaches the inner store's own mapping.

public async ValueTask<ITenantDescriptor<Guid>?> FindByIdentifierAsync(string identifier, CancellationToken ct) =>
    await db.Tenants.SingleOrDefaultAsync(t => t.Slug == identifier, ct);

GetAllTenantsAsync(CancellationToken)

Returns every tenant that exists, suspended or inactive ones included.

ValueTask<IReadOnlyList<ITenantDescriptor<TKey>>> GetAllTenantsAsync(CancellationToken cancellationToken = default)

Parameters:

  • cancellationToken CancellationToken: Cancels the lookup.

Returns: ValueTask<IReadOnlyList<ITenantDescriptor<TKey>>>

GetTenantAsync(TKey, CancellationToken)

Returns the tenant with the given tenantId, or null if no matching tenant exists.

ValueTask<ITenantDescriptor<TKey>?> GetTenantAsync(TKey tenantId, CancellationToken cancellationToken = default)

Parameters:

  • tenantId TKey: The identifier of the tenant to find.
  • cancellationToken CancellationToken: Cancels the lookup.

Returns: ValueTask<ITenantDescriptor<TKey>>

On this page