Multi-Tenancy
PolarSharp.MultiTenant wraps Finbuckle.MultiTenant to give each tenant their own isolated PolarClient with its own access token, circuit breaker, connection pool, and rate limiter.
Installation
dotnet add package PolarSharp.MultiTenant
Configuration
{
"PolarSharp": {
"MultiTenant": {
"Strategy": "Header",
"Header": { "Name": "X-Tenant-ID" },
"Tenants": [
{
"Id": "acme",
"Identifier": "acme",
"Name": "Acme Corp",
"PolarAccessToken": "tok_live_acme",
"Server": "Production"
},
{
"Id": "beta",
"Identifier": "beta",
"Name": "Beta Inc",
"PolarAccessToken": "tok_sandbox_beta",
"Server": "Sandbox"
}
]
}
}
}
Registration
builder.Services
.AddPolarInfrastructure(builder.Configuration)
.AddPolarMultiTenant();
// ...
app.UsePolarInfrastructure(); // calls app.UseMultiTenant() automatically
Tenant resolution strategies
| Strategy | How tenant is identified | Config key |
|---|---|---|
Header (default) |
HTTP request header | PolarSharp:MultiTenant:Header:Name (default: X-Tenant-ID) |
Route |
Route parameter | PolarSharp:MultiTenant:Route:Parameter (default: tenantId) |
Hostname |
Subdomain / hostname | PolarSharp:MultiTenant:Hostname:Template (default: __tenant__.*) |
Claim |
JWT claim value | PolarSharp:MultiTenant:Claim:Type (default: tid) |
Using the per-tenant client
Inject IMultiTenantPolarClientFactory — it resolves the correct PolarClient for the current request's tenant automatically:
app.MapGet("/orders", async (IMultiTenantPolarClientFactory factory, CancellationToken ct) =>
{
var polar = factory.GetClientForCurrentTenant();
var result = await polar.Orders.EmptyPathSegment.GetAsync(cancellationToken: ct);
return Results.Ok(result);
});
Bulkhead isolation
Each tenant gets independent infrastructure:
- Connection pool — one
SocketsHttpHandlerper tenant; one tenant's high throughput doesn't starve others - Circuit breaker — Tenant A's repeated failures open Tenant A's breaker only; Tenant B is unaffected
- Rate limiter — per-tenant concurrency cap
This means a single misbehaving tenant cannot cascade failures to other tenants.
Programmatic tenant registration
For tenants that aren't known at startup:
builder.Services
.AddPolarInfrastructure(builder.Configuration)
.AddPolarMultiTenant(opts =>
{
opts.Strategy = TenantStrategy.Claim;
opts.Claim.Type = "polar_tenant_id";
opts.Tenants.Add(new PolarTenantInfo
{
Id = "enterprise-a",
Identifier = "enterprise-a",
Name = "Enterprise A",
PolarAccessToken = "tok_live_ea",
});
});