Finbuckle.
ASP.NET Core Integration
MultiTenant provides first-class support for ASP.NET Core through a dedicated package that adds middleware,
HttpContext helpers, and several ASP.NET Core-specific strategies.
Package Installation
For most ASP.NET Core apps install the Finbuckle.MultiTenant.AspNetCore package:
dotnet add package Finbuckle.MultiTenant.AspNetCore
This package depends on Finbuckle.MultiTenant and transitively brings in everything needed for
ASP.NET Core integration, including ASP.NET Core-specific strategies.
Configuring the Middleware
Service Registration
Register MultiTenant services in Program.cs using AddMultiTenant<TTenantInfo> along with at least one
strategy and one store:
using Finbuckle.MultiTenant;
var builder = WebApplication.CreateBuilder(args);
// ...add other app services
builder.Services.AddMultiTenant<TenantInfo>()
.WithHostStrategy()
.WithConfigurationStore();
var app = builder.Build();
See Configuration and Usage for more details on AddMultiTenant and its builder methods.
Adding the Middleware
Call UseMultiTenant() to add the middleware to the request pipeline.
// add the MultiTenant middleware
app.UseMultiTenant();
// ...add other middleware
app.Run();
Middleware ordering is important. Place
UseMultiTenant()before any middleware that requires per-tenant behavior, such asUseAuthentication(),UseAuthorization(), and any other components that read per-tenant options or services.
If UseRouting() is explicitly called in the pipeline it must come before UseMultiTenant() when
using the Route Strategy.
ASP.NET Core Strategies
The following strategies are provided by Finbuckle.MultiTenant.AspNetCore and work with the ASP.NET Core
request pipeline. See MultiTenant Strategies for full documentation of all strategies, including
general-purpose strategies available in the base package.
| Strategy | Description |
|---|---|
| Host Strategy | Uses subdomains or other host segments to identify the tenant. |
| Route Strategy | Uses a route parameter (e.g. {__tenant__}) in the URL path. |
| Base Path Strategy | Uses the first URL path segment as the tenant identifier. |
| Header Strategy | Uses an HTTP request header to identify the tenant. |
| Claim Strategy | Uses a claim on the authenticated user's principal. |
| Session Strategy | Uses the ASP.NET Core session to store the resolved identifier. |
| HttpContext Strategy | Uses a delegate accepting HttpContext for custom logic. |
| Remote Authentication Callback Strategy | Used internally by per-tenant authentication for remote auth flows. |
Getting the Current Tenant in ASP.NET Core
HttpContext Extension Methods
The following extension methods are available on HttpContext for web apps:
GetMultiTenantContext<TTenantInfo>
Returns the MultiTenantContext<TTenantInfo> instance for the current request. This is the preferred way to
access the current tenant in ASP.NET Core (rather than IMultiTenantContextAccessor) because it always
reflects the state set by the middleware, even in post-endpoint processing.
var tenantInfo = HttpContext.GetMultiTenantContext<TenantInfo>().TenantInfo;
if (tenantInfo != null)
{
var tenantId = tenantInfo.Id;
var identifier = tenantInfo.Identifier;
var name = tenantInfo.Name;
}
SetTenantInfo<TTenantInfo>
For most cases the middleware sets the TenantInfo automatically and this method is not needed. Use only if
explicitly overriding the TenantInfo set by the middleware.
Sets the current tenant to the provided TenantInfo. Optionally resets the service provider scope so that
any scoped services already resolved will be resolved again under the current tenant. This has no effect on
singleton or transient services. Setting the TenantInfo with this method sets both the StoreInfo and
StrategyInfo properties on the MultiTenantContext<TTenantInfo> to null.
var newTenantInfo = new TenantInfo { Id = "new-id", Identifier = "new-identifier" };
HttpContext.SetTenantInfo(newTenantInfo, resetServiceProviderScope: true);
// This will be the new tenant.
var tenant = HttpContext.GetMultiTenantContext<TenantInfo>().TenantInfo;
// This will regenerate the options class.
var optionsProvider = HttpContext.RequestServices.GetService<IOptions<MyScopedOptions>>();
For dependency injection-based access to the current tenant outside of a controller or middleware, see
IMultiTenantContextAccessorin Configuration and Usage.
Bypassing Tenant Resolution
Bypassing prevents the middleware from performing tenant resolution for a request entirely and passes it directly to the next middleware in the pipeline.
Bypassing runs before tenant resolution. Short circuiting runs after resolution.
Exclude Specific Endpoints
For scenarios where individual, known endpoints should never trigger tenant resolution, annotate them at registration time.
Using the IEndpointConventionBuilder extension ExcludeFromMultiTenantResolution:
var app = builder.Build();
// Exclude OpenApi endpoints.
app.MapOpenApi()
.ExcludeFromMultiTenantResolution();
// Exclude a specific endpoint.
app.MapGet("/oops", () => "Oops! An error happened.")
.ExcludeFromMultiTenantResolution();
// Exclude a group of endpoints.
app.MapGroup("api/v{version:apiVersion}/dashboard")
.ExcludeFromMultiTenantResolution();
// Exclude static asset endpoints.
app.MapStaticAssets()
.ExcludeFromMultiTenantResolution();
app.Run();
Using the ExcludeFromMultiTenantResolutionAttribute attribute on controllers and action methods:
// Exclude an entire controller.
[ExcludeFromMultiTenantResolution]
public class DashboardController : Controller
{
// Or exclude just a specific action.
[ExcludeFromMultiTenantResolution]
public ActionResult Index()
{
return View();
}
}
Bypass When No Endpoint Is Matched
Call BypassWhenEndpointNotResolved() after AddMultiTenant<TTenantInfo> to skip tenant resolution
entirely when the current request has no matched endpoint. This is especially useful when requests arrive
that do not match any route.
This bypass does not require the route strategy.
builder.Services.AddMultiTenant<TenantInfo>()
.WithRouteStrategy()
.WithConfigurationStore()
.BypassWhenEndpointNotResolved();
Bypass When a Custom Condition Is Met
Use BypassWhen() to bypass resolution based on any condition derived from HttpContext:
// Bypass resolution for health check requests.
builder.Services.AddMultiTenant<TenantInfo>()
.WithRouteStrategy()
.WithConfigurationStore()
.BypassWhen(options =>
{
options.Predicate = ctx => ctx.Request.Path.StartsWithSegments("/health");
});
Short Circuiting
The MultiTenantMiddleware can be configured to short circuit a request pipeline when no tenant is found
or when some custom condition is met.
Short-circuiting the request pipeline does not return an HTTP error code — it simply stops calling further middleware.
Bypassing runs before tenant resolution. Short circuiting runs after resolution.
Short Circuit When Tenant Not Resolved
Call ShortCircuitWhenTenantNotResolved() after AddMultiTenant<TTenantInfo> to halt further processing
when no tenant can be found. An overload accepts a URI to redirect to when no tenant is found.
If you short circuit when tenant not resolved, and you have endpoints that do not require a tenant, then excluding those endpoints becomes a necessity; otherwise they would never be reached.
// Simply short circuit the request, ending request handling.
builder.Services.AddMultiTenant<TenantInfo>()
.WithHostStrategy()
.WithConfigurationStore()
.ShortCircuitWhenTenantNotResolved();
// Short circuit and redirect to a specific Uri.
builder.Services.AddMultiTenant<TenantInfo>()
.WithHostStrategy()
.WithConfigurationStore()
.ShortCircuitWhenTenantNotResolved(new Uri("/tenant/notfound", UriKind.Relative));
Short Circuit When a Custom Condition Is Met
Use the ShortCircuitWhen() extension on MultiTenantBuilder<TTenantInfo> for advanced short-circuiting:
// Advanced short circuiting: if an obsolete strategy was used or when tenant not resolved.
builder.Services.AddMultiTenant<TenantInfo>()
.WithHostStrategy()
.WithConfigurationStore()
.ShortCircuitWhen(config =>
{
config.Predicate = context => context.StrategyInfo is IMyCustomObsoleteStrategy || !context.IsResolved;
});
// Including a redirect.
builder.Services.AddMultiTenant<TenantInfo>()
.WithHostStrategy()
.WithConfigurationStore()
.ShortCircuitWhen(config =>
{
config.Predicate = context => context.StrategyInfo is IMyCustomObsoleteStrategy || !context.IsResolved;
config.RedirectTo = new Uri("/tenant/notfound", UriKind.Relative);
});
Per-Tenant Authentication
MultiTenant provides built-in support for isolating tenant authentication so that login sessions are scoped to the current tenant. This includes per-tenant cookie validation, challenge schemes, login/logout paths, and OpenID Connect settings.
See Per-Tenant Authentication for full details.
Per-Tenant Options
MultiTenant integrates with the standard ASP.NET Core Options pattern so that options can be configured differently for each tenant. Any options class used by ASP.NET Core or your own code can be customized per tenant with minimal changes.
See Per-Tenant Options for full details.
Data Isolation
Entity Framework Core
MultiTenant can automatically filter EF Core queries by tenant using a global query filter. This removes
the need to add WHERE TenantId = ... clauses throughout your app.
See Data Isolation with Entity Framework Core for full details.
ASP.NET Core Identity
MultiTenant has dedicated support for data isolation when using ASP.NET Core Identity with EF Core, including multi-tenant identity context base classes and support for passkeys (WebAuthn).
See Data Isolation with ASP.NET Core Identity for full details.