abp-multitenancy
ABP Framework v10.x (10.4/10.5) multi-tenancy: tenant resolver, ICurrentTenant, IMultiTenant, database isolation, tenant-based data filtering. Use when working with SaaS, multi-tenancy, or tenant management in ABP.
适合你,如果你用 ABP 框架构建多租户 SaaS 应用
npx oh-my-skill add burakdmir/abp-skills/abp-multitenancycurl -fsSL https://oh-my-skill.com/install.sh | bash -s -- burakdmir/abp-skills/abp-multitenancynpx oh-my-skill verify burakdmir/abp-skills/abp-multitenancy怎么用
商店整理自技能原文 · 版本 ce71259 · 表述以原文为准当您询问ABP框架多租户时,Claude会提供配置、IMultiTenant接口、ICurrentTenant用法、租户解析器、数据库隔离等具体代码示例和最佳实践。
当您提到“ABP multi-tenancy”、“ABP tenant”、“ABP SaaS”、“ABP IMultiTenant”、“ABP ICurrentTenant”等关键词,或询问ABP多租户实现时触发。
技能原文 SKILL.md
ABP Framework — Multi-Tenancy
ABP Framework v10.x (10.4/10.5) multi-tenancy (SaaS) implementation guide. Tenant resolver, IMultiTenant, ICurrentTenant, database isolation.
Trigger
- "ABP multi-tenancy"
- "ABP tenant"
- "ABP SaaS"
- "ABP IMultiTenant"
- "ABP ICurrentTenant"
- "ABP tenant resolver"
- "ABP subdomain tenant"
- "ABP database per tenant"
Terminology
- Tenant: A customer of the SaaS application
- Host: The company that manages the application
- Multi-Tenancy: A single instance, multiple customers
Configuration
Configure<AbpMultiTenancyOptions>(options =>
{
options.IsEnabled = true;
});
In the startup templates this is controlled from a single point via the MultiTenancyConsts class.
Database Architectures
| Approach | Description | |---|---| | Single Database | All tenants in the same DB, separated by TenantId | | Database per Tenant | Each tenant has its own DB | | Hybrid | Some tenants share a DB, others have a separate DB |
IMultiTenant Interface
public class Product : AggregateRoot<Guid>, IMultiTenant
{
public Guid? TenantId { get; set; } // From the IMultiTenant interface
public string Name { get; set; }
public float Price { get; set; }
}
Important:
TenantIdis nullable — ifnull, the entity belongs to the Host- ABP automatically applies data filtering for the current tenant
TenantIdis set automatically (fromICurrentTenant.Id)
ICurrentTenant
// Properties
CurrentTenant.Id // Guid? — Current tenant ID
CurrentTenant.Name // string — Current tenant name
CurrentTenant.IsAvailable // bool — true if ID is not null
// Changing the tenant (scoped)
using (CurrentTenant.Change(tenantId))
{
// Within this scope, operations are performed on behalf of the specified tenant
var count = await _productRepository.GetCountAsync();
}
// Switch to the host context
using (CurrentTenant.Change(null))
{
// Operation in the host context
}
Data Filtering — Disabling the Multi-Tenancy Filter
public class ProductManager : DomainService
{
private readonly IRepository<Product, Guid> _productRepository;
private readonly IDataFilter _dataFilter;
public ProductManager(IRepository<Product, Guid> productRepository, IDataFilter dataFilter)
{
_productRepository = productRepository;
_dataFilter = dataFilter;
}
public async Task<long> GetAllProductCountAsync()
{
using (_dataFilter.Disable<IMultiTenant>())
{
return await _productRepository.GetCountAsync();
}
}
}
Tenant Resolvers
Default Resolvers (In Order)
- CurrentUserTenantResolveContributor — From user claims (must always be first)
- QueryStringTenantResolveContributor —
?__tenant=xxx - RouteTenantResolveContributor — From the URL path
- HeaderTenantResolveContributor — From the HTTP header (
__tenant) - CookieTenantResolveContributor — From the cookie (
__tenant)
Changing the Tenant Key
Configure<AbpAspNetCoreMultiTenancyOptions>(options =>
{
options.TenantKey = "MyTenantKey";
});
Subdomain/Domain Tenant Resolver
// Subdomain: mytenant.mydomain.com
Configure<AbpTenantResolveOptions>(options =>
{
options.AddDomainTenantResolver("{0}.mydomain.com");
});
// OpenIddict wildcard domain (if a separate Auth Server is used)
PreConfigure<AbpOpenIddictWildcardDomainOptions>(options =>
{
options.EnableWildcardDomainSupport = true;
options.WildcardDomainsFormat.Add("https://{0}.mydomain.com");
});
Custom Tenant Resolver
public class MyCustomTenantResolveContributor : TenantResolveContributorBase
{
public override string Name => "Custom";
public override Task ResolveAsync(ITenantResolveContext context)
{
// Set context.TenantIdOrName
// Use DI via context.ServiceProvider
return Task.CompletedTask;
}
}
// Registration
Configure<AbpTenantResolveOptions>(options =>
{
options.TenantResolvers.Add(new MyCustomTenantResolveContributor());
});
Fallback Tenant
Configure<AbpTenantResolveOptions>(options =>
{
options.FallbackTenant = "acme"; // Used when no tenant is found
});
Multi-Tenancy Middleware
app.UseAuthentication(); app.UseMultiTenancy(); // Immediately after authentication
Already configured in the startup templates.
Tenant Store
Tenant Management Module (Recommended)
Included in the startup templates. The ITenantStore implementation fetches tenant information from the DB.
Configuration Data Store (Alternative)
// appsettings.json
"Tenants": [
{
"Id": "446a5211-3d72-4339-9adc-845151f8ada0",
"Name": "tenant1",
"NormalizedName": "TENANT1"
},
{
"Id": "25388015-ef1c-4355-9c18-f6b6ddbaf89d",
"Name": "tenant2",
"NormalizedName": "TENANT2",
"ConnectionStrings": {
"Default": "...tenant2's connection string..."
}
}
]
Host vs Tenant DbContext
[IgnoreMultiTenancy] // Always uses the host DB
public class TenantManagementDbContext : AbpDbContext<TenantManagementDbContext> { }
Other Multi-Tenancy Infrastructure
In ABP, the following services are designed to be multi-tenancy-aware:
- BLOB Storing
- Caching
- Data Filtering
- Data Seeding
- Authorization
- Settings
Best Practices
- Always implement
IMultiTenant— For tenant-specific entities - Use
CurrentTenant.Changewithusing— The previous value is restored outside the scope - Tenant resolver order matters —
CurrentUserTenantResolveContributormust always be first - Use
CurrentTenant.Change(null)for host-side operations - Use the Tenant Management module — The
appsettings.jsonapproach is only for simple scenarios - In the separate DB approach, cross-tenant queries must be implemented yourself
Related
- [EF Core](../abp-efcore/SKILL.md) — tenant connection string, IgnoreMultiTenancy
- [MongoDB](../abp-mongodb/SKILL.md) — tenant isolation with MongoDB
- [Authorization](../abp-authorization/SKILL.md) — permissions with MultiTenancySides
- [Settings & Features](../abp-settings-features/SKILL.md) — tenant-based feature/setting
- ABP Docs: https://abp.io/docs/latest/framework/architecture/multi-tenancy