如何修复UserManager引发的‘已有打开的DataReader’异常?
修复“已有打开的DataReader关联此连接”异常问题
我有一个包含UserGuid属性的BaseController,用于便捷访问用户数据,代码如下:
private UserManager<User> UserManager { get { return HttpContext.RequestServices.GetRequiredService<UserManager<User>>(); } } public Guid UserGuid { get { var userGuid = UserManager.FindByNameAsync(User.Identity.Name).Result.Guid; return userGuid; } }
但有时会出现如下异常:
There is already an open DataReader associated with this Connection which must be closed first.
该异常与代码行var userGuid = UserManager.FindByNameAsync(User.Identity.Name).Result.Guid;相关,且UserManager并非我编写的代码,请问该如何修复此问题?
问题根源
同步调用异步方法(使用.Result)会阻塞线程,导致EF Core的DataReader无法及时释放,引发数据库连接上的资源冲突;同时每次访问UserManager都重新获取服务实例,也可能加剧资源竞争。
修复方案
1. 改为异步方法(推荐根本解决)
把同步属性改成异步方法,用await替代.Result,避免线程阻塞:
// 缓存UserManager实例,避免重复获取 private UserManager<User> _userManager; private UserManager<User> UserManager { get { return _userManager ??= HttpContext.RequestServices.GetRequiredService<UserManager<User>>(); } } // 替换原UserGuid属性为异步方法 public async Task<Guid> GetUserGuidAsync() { var user = await UserManager.FindByNameAsync(User.Identity.Name); return user.Guid; }
后续在控制器中调用时,需使用await GetUserGuidAsync()。
2. 启用MultipleActiveResultSets(临时 workaround)
如果暂时无法修改所有调用处的同步代码,可以在数据库连接字符串中添加MultipleActiveResultSets=True,允许同一连接存在多个活跃DataReader。但这只是缓解手段,不能替代异步改造。
3. 缓存用户Guid(优化性能)
在同一请求内缓存用户Guid,避免重复查询数据库:
public async Task<Guid> GetUserGuidAsync() { if (HttpContext.Items.TryGetValue("UserGuid", out var cachedValue)) { return (Guid)cachedValue; } var user = await UserManager.FindByNameAsync(User.Identity.Name); var userGuid = user.Guid; HttpContext.Items["UserGuid"] = userGuid; return userGuid; }
内容的提问来源于stack exchange,提问作者Mohammad Miras
相关产品推荐
相关产品推荐

