.NET 6 添加JWT中间件报错:无法从根提供程序解析AGUSContext
问题分析与解决方案
问题根源
System.InvalidOperationException异常的核心原因是:你从根服务提供者(Root Provider)中尝试解析了一个Scoped生命周期的服务AGUSContext。在.NET中,根服务提供者是单例的,而Scoped服务的生命周期绑定到请求作用域,根容器没有请求上下文,无法创建或管理Scoped服务的生命周期。
你的JWT中间件默认是单例生命周期,若在中间件构造函数中注入Scoped服务,或直接从根容器获取Scoped服务,就会触发这个错误。
具体解决方案
1. 修改JwtMiddleware的服务获取方式
不要在中间件构造函数中注入AGUSContext,而是在InvokeAsync方法中通过当前请求的作用域服务提供者获取:
public async Task InvokeAsync(HttpContext context) { // 创建当前请求的临时作用域,获取Scoped服务 using var scope = context.RequestServices.CreateScope(); var dbContext = scope.ServiceProvider.GetRequiredService<AGUSContext>(); // 后续JWT验证逻辑使用dbContext var token = context.Request.Headers["Authorization"].FirstOrDefault()?.Split(" ").Last(); if (!string.IsNullOrEmpty(token)) { ValidateToken(token, dbContext, context); } await _next(context); }
2. 限制中间件构造函数的注入类型
中间件是单例生命周期,构造函数只能注入Singleton服务(比如IConfiguration、单例配置类等),禁止注入Scoped/Transient服务:
// 正确示例:仅注入单例服务 public JwtMiddleware(RequestDelegate next, IConfiguration configuration) { _next = next; _configuration = configuration; } // 错误示例:禁止构造函数注入Scoped服务 // public JwtMiddleware(RequestDelegate next, AGUSContext dbContext)
3. 确认Program.cs中的服务注册
确保AGUSContext是按Scoped生命周期注册(AddDbContext默认就是Scoped):
builder.Services.AddDbContext<AGUSContext>(options => options.UseSqlServer(builder.Configuration.GetConnectionString("AGUSConnection")));
4. 修正授权特性中的服务获取(若涉及)
如果自定义授权特性中也用到了AGUSContext,同样要通过请求作用域获取,不能在构造函数注入:
public class CustomAuthorizeAttribute : Attribute, IAuthorizationFilter { public void OnAuthorization(AuthorizationFilterContext context) { using var scope = context.HttpContext.RequestServices.CreateScope(); var dbContext = scope.ServiceProvider.GetRequiredService<AGUSContext>(); // 授权逻辑... } }
5. 控制器生成Token的代码无需修改
控制器是Scoped生命周期,构造函数直接注入AGUSContext是安全的:
[ApiController] [Route("api/auth")] public class AuthController : ControllerBase { private readonly AGUSContext _dbContext; private readonly IConfiguration _configuration; public AuthController(AGUSContext dbContext, IConfiguration configuration) { _dbContext = dbContext; _configuration = configuration; } [HttpPost("login")] public IActionResult GenerateToken(LoginModel model) { // 使用_dbContext验证用户并生成Token // ... } }
关键原理
- .NET中间件默认是Singleton,只能从构造函数注入Singleton服务;
- Scoped服务绑定到请求上下文,必须通过
HttpContext.RequestServices创建临时作用域获取; - 使用
CreateScope()能确保Scoped服务在请求结束后正确释放。
内容的提问来源于stack exchange,提问作者S S
相关产品推荐
相关产品推荐

