ASP.NET Core中间件DbContext多线程访问异常原因及解决咨询
问题原因与解决方案
核心原因
ASP.NET Core中中间件默认是单例生命周期,而你的IUserService(及其依赖的DbContext)一般配置为Scoped生命周期(每个请求对应一个实例)。当你在单例中间件的构造函数中注入Scoped服务时,这个Scoped服务会被中间件长期持有,不再随请求释放。当同一个中间件实例处理多个请求(比如浏览器自动发起的/favicon.ico请求、调试时的重复请求),就会导致多个线程同时访问同一个DbContext实例,触发多线程访问错误。
另外,中间件被调用两次的常见场景包括:
- 浏览器自动请求网站图标(
/favicon.ico) - 调试工具或前端框架发起的预检请求
- 代码中重复注册了中间件(你的示例代码中未出现,但需排查)
解决方法
1. 在InvokeAsync方法中注入Scoped服务
不要在中间件构造函数中注入Scoped服务,而是通过InvokeAsync方法的参数注入,ASP.NET Core会自动为每个请求传入对应的Scoped实例:
public class UserIdMiddleware { private readonly RequestDelegate _next; public UserIdMiddleware(RequestDelegate next) { _next = next; } // 直接在方法参数中注入IUserService,框架会自动提供当前请求的Scoped实例 public async Task InvokeAsync(HttpContext context, IUserService userService) { int? userId = await userService.GetUserIdByUid(decodedToken.Uid); await _next(context); } } app.UseMiddleware<UserIdMiddleware>();
2. 排查重复注册问题
检查Program.cs或Startup.cs中是否重复调用了app.UseMiddleware<UserIdMiddleware>(),重复注册会导致每个请求触发多次中间件逻辑。
3. 过滤不必要的请求(可选)
如果是/favicon.ico这类无效请求导致的重复调用,可以在中间件中过滤,避免执行无效业务逻辑:
public async Task InvokeAsync(HttpContext context, IUserService userService) { if (context.Request.Path.Equals("/favicon.ico", StringComparison.OrdinalIgnoreCase)) { await _next(context); return; } int? userId = await userService.GetUserIdByUid(decodedToken.Uid); await _next(context); }
内容的提问来源于stack exchange,提问作者Viacheslav Rud'
相关产品推荐
相关产品推荐

