如何向DB Context传递全局过滤器参数以实现用户级数据过滤
根本原因
你遇到的报错本质不是连接字符串缺失,而是ASP.NET Core默认依赖注入(DI)容器无法解析你新增的自定义构造参数int Branch。默认DI只会自动注入已注册的服务类型,值类型参数没有对应注册的话,会导致DbContext构造失败,进而触发找不到连接字符串的误导性报错。
正确实现方案
不要直接将值类型作为DbContext构造参数,通过Scoped生命周期的服务存储当前用户分支信息的方式实现需求,具体步骤如下:
- 定义分支信息提供器
创建接口和实现类用来存储当前请求对应的分支值,生命周期设为Scoped,保证每个用户请求周期内值固定:
public interface IBranchProvider { int CurrentBranch { get; set; } } public class BranchProvider : IBranchProvider { public int CurrentBranch { get; set; } }
- 注册服务
在Program.cs中注册提供器和DbContext:
// 注册分支提供器为Scoped生命周期 builder.Services.AddScoped<IBranchProvider, BranchProvider>(); // 原有DbContext注册逻辑保持不变,正确读取配置中的连接字符串 builder.Services.AddDbContext<TimeSheetContext>(options => options.UseSqlServer(builder.Configuration.GetConnectionString("你的连接字符串名称")));
- 注入中间件赋值分支信息
在身份验证中间件之后添加自定义中间件,从当前登录用户信息中读取分支值赋值到提供器中:
// 注意要放在app.UseAuthentication()之后,保证能读取到用户Claims app.Use(async (context, next) => { var branchProvider = context.RequestServices.GetRequiredService<IBranchProvider>(); if (context.User.Identity?.IsAuthenticated == true) { // 这里替换为你实际存储分支值的位置,比如Claims、Session等 var branchClaim = context.User.Claims.FirstOrDefault(c => c.Type == "BranchCode"); if (branchClaim != null && int.TryParse(branchClaim.Value, out var branch)) { branchProvider.CurrentBranch = branch; } } await next(); });
- 修改DbContext构造函数
将分支提供器注入到DbContext中,获取分支值:
private readonly int _branchFilter; public TimeSheetContext(DbContextOptions<TimeSheetContext> options, IBranchProvider branchProvider) : base(options) { _branchFilter = branchProvider.CurrentBranch; }
- 全局查询过滤器逻辑保持不变
modelBuilder.Entity<Branch>().HasQueryFilter(b => b.ContractorCode == _branchFilter);
注意事项
默认DbContext的生命周期就是Scoped,和IBranchProvider生命周期一致,因此每个请求初始化的DbContext都会拿到当前用户对应的分支值,满足你单会话固定、不同用户取值不同的需求。
内容的提问来源于stack exchange,提问作者Colin-G-Davidson
相关产品推荐
相关产品推荐

