ASP.NET Core 6中自定义类使用HttpContextAccessor时HttpContext为空求助
问题:HttpContextAccessor获取HttpContext始终为null
在自定义BLL类UserPermisionConfig中注入IHttpContextAccessor后,初始化成功但HttpContext始终为null,相关代码如下:
Program.cs 代码
builder.Services.AddSingleton<IUserPermissionConfig, UserPermisionConfig>(); builder.Services.AddHttpContextAccessor(); var app = builder.Build(); var setUserPermission = app.Services.GetRequiredService<IUserPermissionConfig>(); setUserPermission.SetUserPermissionsSession(UserConstants.SYSTEM_ID);
UserPermisionConfig 代码
private readonly IHttpContextAccessor _httpContextAccessor; public UserPermisionConfig(IHttpContextAccessor httpContextAccessor) { _permisionServiceClient = new PermissionServiceClient(); _httpContextAccessor = httpContextAccessor ?? throw new Exception("Http context accessor is null."); } public async Task SetUserPermissionsSession(int systemId) { string userName = _httpContextAccessor.HttpContext. User.Identity.Name; //此处HttpContext始终为空 UserPermissionsModel userPermissionModel = await GetUserPermission(systemId, userName); _httpContextAccessor.HttpContext.Session.Set(UserConstants.SESSION_USER_PERMISSIOS, ByteArrayExtensions.ToByteArray(userPermissionModel)); }
问题原因
- 启动阶段无请求上下文:你在
Program.cs中直接通过app.Services.GetRequiredService()获取实例并调用方法,此时程序处于启动初始化阶段,没有任何HTTP请求正在处理,HttpContext仅在请求管道处理请求的过程中存在,自然无法获取到。 - 生命周期不匹配:
UserPermisionConfig被注册为Singleton单例服务,而IHttpContextAccessor本质上依赖请求作用域(Scoped)的上下文存储,单例服务依赖Scoped服务会导致上下文无法正确绑定,甚至引发生命周期冲突。
解决方案
1. 调整服务生命周期并移至请求流程中调用
首先将UserPermisionConfig改为Scoped生命周期,确保和请求上下文的作用域匹配,然后在控制器、中间件等请求处理环节调用方法:
修改Program.cs
// 将Singleton改为Scoped builder.Services.AddScoped<IUserPermissionConfig, UserPermisionConfig>(); builder.Services.AddHttpContextAccessor(); var app = builder.Build(); // 移除启动时直接调用的代码,避免无上下文场景 // var setUserPermission = app.Services.GetRequiredService<IUserPermissionConfig>(); // setUserPermission.SetUserPermissionsSession(UserConstants.SYSTEM_ID); // 确保启用Session(如果需要操作Session) app.UseSession(); app.UseAuthentication(); app.UseAuthorization(); app.MapControllers(); app.Run();
在控制器中注入调用
public class HomeController : Controller { private readonly IUserPermissionConfig _permissionConfig; public HomeController(IUserPermissionConfig permissionConfig) { _permissionConfig = permissionConfig; } public async Task<IActionResult> Index() { // 仅在用户认证后执行 if (User.Identity.IsAuthenticated) { await _permissionConfig.SetUserPermissionsSession(UserConstants.SYSTEM_ID); } return View(); } }
2. 使用中间件全局初始化权限
如果需要对每个认证后的请求自动初始化权限,可以编写自定义中间件:
编写中间件类
public class PermissionInitMiddleware { private readonly RequestDelegate _next; private readonly IUserPermissionConfig _permissionConfig; public PermissionInitMiddleware(RequestDelegate next, IUserPermissionConfig permissionConfig) { _next = next; _permissionConfig = permissionConfig; } public async Task InvokeAsync(HttpContext context) { // 仅在用户已认证时执行权限初始化 if (context.User.Identity.IsAuthenticated) { await _permissionConfig.SetUserPermissionsSession(UserConstants.SYSTEM_ID); } // 继续执行后续中间件 await _next(context); } }
在Program.cs中注册中间件
builder.Services.AddScoped<IUserPermissionConfig, UserPermisionConfig>(); builder.Services.AddHttpContextAccessor(); builder.Services.AddSession(options => { options.IdleTimeout = TimeSpan.FromMinutes(30); options.Cookie.HttpOnly = true; options.Cookie.IsEssential = true; }); var app = builder.Build(); app.UseSession(); app.UseAuthentication(); app.UseAuthorization(); // 将权限初始化中间件放在认证之后 app.UseMiddleware<PermissionInitMiddleware>(); app.MapControllers(); app.Run();
内容的提问来源于stack exchange,提问作者So_oP
相关产品推荐
相关产品推荐

