XiHan.Framework.MultiTenancy.InMemory
多租户的默认实现:启动时从配置装载租户,存在进程内存里,有容量上限,运行时可增删。它提供 multitenancy.context@1 与 multitenancy.sharding@1,适用于租户数量少、随配置发布的应用,以及开发与测试。
| 项 | 内容 |
|---|---|
| 包 ID | XiHan.Framework.MultiTenancy.InMemory |
| 环层 | Ring 3(实现) |
| 能力 | 提供 multitenancy.context@1、multitenancy.sharding@1;依赖 kernel.hosting@1 |
| 特性入口 | InMemoryMultiTenancyFeature(清单 xihan.multitenancy.inmemory,role: default) |
| 配置节 | XiHan:MultiTenancy(含 Tenants 与 InMemory 子节) |
| 依赖 | XiHan.Framework.MultiTenancy.Abstractions |
| AOT | 兼容 |
| 稳定性 | Preview |
概述
InMemoryTenantStore 是一张按租户 ID 索引的并发字典,读取无锁,新增与替换在同一把锁里先查容量再写入,并发新增不会越过上限。特性在 Configure 里只为被选中的能力注册:
- 总是注册
MultiTenancyOptions(从配置读取)与作用域服务TenantShardScope(与是否选中分片无关)。 - 租户上下文能力被选中时:
InMemoryMultiTenancyOptions、InMemoryTenantStore与ITenantStore;解析器ClaimTenantResolver→BaggageTenantResolver,注册顺序即解析顺序;Tenant 阶段的TenantResolutionMiddleware;健康项multitenancy.inmemory.capacity,由存储自己同步计算。 - 分片能力被选中时的
TenantStoreShardResolver。
清单角色是 default:装配一个显式的多租户 Provider(如 MultiTenancy.Database)后本包被顶替,不装配、不启动。应用自带的 Provider 只提供 multitenancy.context@1 时,本包只提供分片:存储、解析器、健康项与 Tenant 阶段中间件都由应用的 Provider 注册(它可以复用抽象包的 TenantResolutionMiddleware),分片从它的 ITenantStore 推出。
何时使用
- 租户随配置发布、数量在千级以内,或开发、演示、自动化测试:用本包。
- 租户由管理后台在运行时增删、多实例共享同一份目录:用 MultiTenancy.Database。
安装与启用
dotnet add package XiHan.Framework.MultiTenancy.InMemory --prerelease当前是预览版,安装要带 --prerelease;从源码或本地包源引用见快速上手。Profiles.Standard 与 Profiles.Full 已包含本包;单独装配时:
using XiHan.Framework.Hosting.AspNetCore;
using XiHan.Framework.MultiTenancy.InMemory;
var builder = WebApplication.CreateBuilder(args);
builder.AddXiHan(xihan => xihan.UseFeature<InMemoryMultiTenancyFeature>());
var app = builder.Build();
app.UseXiHan();
app.Run();配置
| 键 | 类型 | 缺省 | 说明 |
|---|---|---|---|
XiHan:MultiTenancy:Tenants:<id>:DisplayName | string | 无 | 显示名;节名 <id> 就是租户 ID,按租户 ID 文法校验 |
XiHan:MultiTenancy:Tenants:<id>:IsEnabled | bool | true | 是否启用;只接受 true / false |
XiHan:MultiTenancy:Tenants:<id>:Properties:<key> | string | 无 | 租户属性,分片键见下表 |
XiHan:MultiTenancy:InMemory:MaxTenants | int | 1000 | 租户上限,正整数 |
DefaultTenant、RequireTenant、ValidateAgainstStore、TenantClaim 四个解析选项也在 XiHan:MultiTenancy 下,见 MultiTenancy.Abstractions。
{
"XiHan": {
"MultiTenancy": {
"RequireTenant": false,
"InMemory": { "MaxTenants": 1000 },
"Tenants": {
"acme": {
"DisplayName": "Acme Corp",
"Properties": {
"ConnectionString": "Host=localhost;Database=acme",
"DatabaseProvider": "postgresql"
}
},
"beta": { "DisplayName": "Beta" },
"globex": { "DisplayName": "Globex", "IsEnabled": false }
}
}
}
}分片能力被选中时,TenantStoreShardResolver 从租户属性推出分片:
| 属性键 | 含义 |
|---|---|
ConnectionString | 有值即该租户分库 |
DatabaseProvider | 数据库提供者名,可选,转成小写 |
Shard.<key> | 去掉前缀后作为 <key> 透传给持久化 Provider |
上例里 acme 分库,beta 与 globex 共库。
主要类型
| 类型 | 说明 |
|---|---|
InMemoryMultiTenancyFeature | 特性入口;HealthName = multitenancy.inmemory.capacity |
InMemoryMultiTenancyOptions | MaxTenants(缺省 1000)、Tenants(启动时装载的租户);FromConfiguration 读取上面的配置 |
InMemoryTenantStore | ITenantStore 与健康项贡献者:Set(tenant) 新增或替换、Remove(tenantId) 删除、Capacity、Count |
使用示例
运行时增删租户。Set 与 Remove 不会自动失效分片缓存,改了租户连接后要调用 ITenantShardResolver.Invalidate:
using XiHan.Framework.MultiTenancy.Abstractions.Sharding;
using XiHan.Framework.MultiTenancy.Abstractions.Tenants;
using XiHan.Framework.MultiTenancy.InMemory;
using XiHan.Framework.Primitives;
public sealed class TenantAdministration(InMemoryTenantStore store, ITenantShardResolver shards)
{
public Result MoveToOwnDatabase(string tenantId, string connectionString)
{
var updated = store.Set(new TenantInfo
{
Id = tenantId,
Properties = new Dictionary<string, string>(StringComparer.Ordinal) { [TenantShardKeys.ConnectionString] = connectionString },
});
// 解析器缓存了旧结果(包括"无分片"),不失效就继续落旧库
if (updated.IsSuccess)
{
shards.Invalidate(tenantId);
}
return updated;
}
}ITenantShardResolver 只在分片能力被选中时注册。本包同时提供两个能力,单独装配本包时两者都由它提供。
行为与限制
- 容量:新增超过
MaxTenants时Set返回MULTITENANCY_UNAVAILABLE_001;替换已有租户不占新容量。配置里的租户超过上限时,构造存储即抛出FrameworkException。 - 健康项
multitenancy.inmemory.capacity:租户数达到上限即 Degraded(原因MULTITENANCY_UNAVAILABLE_001),否则 Ready。 - ID 区分大小写;
ListAsync按 ID 序数排序返回全部租户。 - 数据只在进程内存里:多实例部署时各实例各有一份,运行时的增删不会同步到其他实例,重启后恢复为配置内容。
- 分片缓存容量由
XiHan:MultiTenancy:ShardCacheSize决定,缺省 10000,必须是正整数。
相关
- 多租户
- MultiTenancy.Abstractions
- MultiTenancy.Database
- Profiles.Standard
- 规范:RFC-0007《多租户》;ADR-0018
