.NET Core 6中如何将HttpContext传入DbConnectionInterceptor获取用户信息
解决方案
核心问题修复
你遇到的编译错误是因为在配置AddDbContext阶段直接实例化EFConnectionInterceptor时,服务容器尚未构建完成,无法注入IHttpContextAccessor。正确的做法是将拦截器注册为服务,通过服务提供者延迟解析实例。
步骤1:注册拦截器为服务
在Program.cs中,先将EFConnectionInterceptor注册为Scoped服务(与IHttpContextAccessor的生命周期匹配):
builder.Services.AddHttpContextAccessor(); // 注册拦截器到服务容器 builder.Services.AddScoped<EFConnectionInterceptor>();
步骤2:通过服务提供者添加拦截器
修改AddDbContext的配置,使用AddInterceptors的重载方法,从服务容器中获取拦截器实例:
builder.Services.AddDbContext<MyContext>(options => options .UseSqlServer(builder.Configuration.GetConnectionString("myconnstring")) // 延迟从服务容器解析拦截器 .AddInterceptors(provider => provider.GetRequiredService<EFConnectionInterceptor>()) );
步骤3:优化拦截器代码(可选但推荐)
将同步执行的ExecuteNonQuery改为异步方法,避免阻塞线程,并确保调用基类方法:
public class EFConnectionInterceptor : DbConnectionInterceptor { private readonly IHttpContextAccessor _httpContextAccessor; public EFConnectionInterceptor(IHttpContextAccessor httpContextAccessor) { _httpContextAccessor = httpContextAccessor; } public override async Task ConnectionOpenedAsync(DbConnection connection, ConnectionEndEventData eventData, CancellationToken cancellationToken = default) { var username = _httpContextAccessor.HttpContext?.User?.Identity?.Name; if (!string.IsNullOrEmpty(username)) { using var cmd = connection.CreateCommand(); cmd.CommandText = "EXEC sp_set_session_context @key=N'Username', @value=@Username"; var param = cmd.CreateParameter(); param.ParameterName = "@Username"; param.Value = username; cmd.Parameters.Add(param); await cmd.ExecuteNonQueryAsync(cancellationToken); } // 调用基类方法确保后续逻辑正常执行 await base.ConnectionOpenedAsync(connection, eventData, cancellationToken); } }
关键说明
- 该方案无需修改DB First生成的
MyContext,完全通过拦截器实现全局会话上下文设置。 - 仅在HTTP请求上下文存在且用户已认证时,才会执行
sp_set_session_context,兼容后台任务等非HTTP场景(此类场景下会跳过执行)。 - 拦截器的Scoped生命周期确保每个请求都能获取到当前用户的身份信息。
内容的提问来源于stack exchange,提问作者Kevin Fizz
相关产品推荐
相关产品推荐

