‹ 首页

abp-multitenancy

@burakdmir · 收录于 昨天 · 上游提交 2 周前

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 安装 校验哈希
npx oh-my-skill add burakdmir/abp-skills/abp-multitenancy
/ 通过 bash 安装
curl -fsSL https://oh-my-skill.com/install.sh | bash -s -- burakdmir/abp-skills/abp-multitenancy
/ 已经装过?验证本机副本,不用重装
npx oh-my-skill verify burakdmir/abp-skills/abp-multitenancy
安装目标可用 --agent / --scope 或 --to 明确指定;省略时只会在唯一已存在的 agent 目录上自动选择,零命中或多命中会停止并提示。content_hash 缺失或不一致均拒装。
13GitHub stars
~1.2K上下文体积 · 单文件
索引托管

怎么用

商店整理自技能原文 · 版本 ce71259 · 表述以原文为准
它做什么

当您询问ABP框架多租户时,Claude会提供配置、IMultiTenant接口、ICurrentTenant用法、租户解析器、数据库隔离等具体代码示例和最佳实践。

什么时候触发

当您提到“ABP multi-tenancy”、“ABP tenant”、“ABP SaaS”、“ABP IMultiTenant”、“ABP ICurrentTenant”等关键词,或询问ABP多租户实现时触发。

装好后可以这样说
Claude会解释数据库架构和配置方法。
技能原文 SKILL.md作者撰写 · MIT · ce71259

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:

  • TenantId is nullable — if null, the entity belongs to the Host
  • ABP automatically applies data filtering for the current tenant
  • TenantId is set automatically (from ICurrentTenant.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)
  1. CurrentUserTenantResolveContributor — From user claims (must always be first)
  2. QueryStringTenantResolveContributor?__tenant=xxx
  3. RouteTenantResolveContributor — From the URL path
  4. HeaderTenantResolveContributor — From the HTTP header (__tenant)
  5. 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
  1. Always implement IMultiTenant — For tenant-specific entities
  2. Use CurrentTenant.Change with using — The previous value is restored outside the scope
  3. Tenant resolver order mattersCurrentUserTenantResolveContributor must always be first
  4. Use CurrentTenant.Change(null) for host-side operations
  5. Use the Tenant Management module — The appsettings.json approach is only for simple scenarios
  6. 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
按 MIT 许可原样转载,未经改动 · 在 GitHub 查看 →

评论

登录即可评论;带「已验证安装」的,是发布者名下有本店的安装或持有记录。