Oracle多租户需动态构建DbContextOptions并严格控制中间件顺序:TenantResolutionMiddleware必须紧接UseRouting之后、早于UseAuthentication,且连接字符串须带ApplicationName标识、显式处理大小写与Schema。

Oracle 多租户连接在 ASP.NET Core 中不能靠“一套 DbContext 复用多个连接字符串”硬切,必须让 DbContextOptions 在每次请求时动态构建,且租户识别中间件顺序错不得——否则 DbContext 拿到的永远是上一个租户的连接,或直接 fallback 到默认配置。
租户识别中间件必须早于 UseAuthentication
这是最常踩的坑:把租户解析逻辑放在 Controller 或 Action 里,或者塞进 [FromHeader] 参数绑定,会导致 ITenantService、日志、限流、授权等所有依赖租户上下文的中间件都运行在“无租户”状态。
-
UseRouting()必须先执行,它才把Host/Path/Header解析为稳定上下文 -
TenantResolutionMiddleware必须紧接其后,把X-Tenant-ID或子域名提取出来,存入HttpContext.Items["TenantId"](禁用static string) -
UseAuthentication()必须在其后——因为IDbContextFactory等 Scoped 服务一初始化就会读取租户信息,晚了就来不及
DbContextOptions 工厂注册必须是 Scoped + 动态构造
EF Core 的 DbContextOptions 是只读快照,一旦实例化,ConnectionString 就不可变。试图在 OnConfiguring 里改连接字符串,会引发连接池混用、事务跨库、连接泄漏。
- 在
Program.cs中注册为 Scoped 工厂:services.AddScoped<yourdbcontext>((sp) => { var options = new DbContextOptionsBuilder<yourdbcontext>(); var tenantId = sp.GetRequiredService<itenantservice>().CurrentTenant.Id; var connStr = GetOracleConnStringForTenant(tenantId); options.UseOracle(connStr); return new YourDbContext(options.Options); });</itenantservice></yourdbcontext></yourdbcontext> - 连接字符串中务必带标识:
ApplicationName=tenant-{tenantId},否则 Oracle 监控、AWR 报告、SQL Trace 都无法区分租户 - 不要把所有租户连接字符串硬编码进
appsettings.json;建议用IConfiguration+ISecretsProvider(如 Azure Key Vault)按需拉取,且校验tenantId合法性后再调密钥服务,避免高频 403
Oracle 实体映射必须显式处理大小写和 Schema
Oracle 默认把未加引号的表名/列名转为大写,而 EF Core 默认生成小写蛇形命名,不显式对齐就会报 ORA-00942: table or view does not exist。
- 实体类加
[Table("CUSTSPR")],属性加[Column("CUST")],全部大写匹配 Oracle 字典视图 - 若租户使用独立 Schema(如
tenant1_data),需在连接字符串里指定Current Schema=tenant1_data,或在OnModelCreating中统一前缀:modelBuilder.HasDefaultSchema($"tenant{tenantId}_data"); - 避免用
tnsnames.ora别名——本地开发可能通,但容器化部署时容易因 ORACLE_HOME 或网络路径缺失失败;直接写全Data Source=(DESCRIPTION=(ADDRESS=...))更可靠
多租户下 Oracle 连接池实际是隔离的
很多人误以为 Oracle 连接池会跨租户复用,其实不会:只要 ConnectionString 字符串不同(哪怕只差一个空格或 ApplicationName 值),Oracle.ManagedDataAccess 就视为不同池。这意味着你得接受每个租户独占一组连接,连接数上限要按租户数 × 单租户最大连接数来规划。
- 单租户连接池默认上限是 100,50 个租户就是 5000 连接,数据库侧
processes参数必须同步调高 - 若租户量超 200,建议引入连接池分级策略:高频租户保池,低频租户启用
Connection Lifetime=60主动回收 -
Oracle.ManagedDataAccess.Core不支持Load Balancing和FAN,别指望它自动做 RAC 故障转移;真要高可用,得靠应用层重试 +Oracle.EntityFrameworkCore的健康检查集成


















