.NET 5升级后使用ASP.NET Boilerplate遇UserManagerProxy已释放访问错误
我之前在升级到.NET 5 + 旧版ASP.NET Boilerplate(非ABP Framework)的时候,也碰到过一模一样的问题!当时调试的时候直接跳错误,完全摸不着头脑,后来折腾了好一阵才找到几个可行的解决方向,分享给你:
可能的原因
这个错误本质上是UserManagerProxy对象在还需要使用的时候就被DI容器给释放了,通常和异步操作的上下文管理、UnitOfWork范围或者依赖注入的生命周期配置有关。
具体解决方案
1. 调整代码执行顺序,提前初始化UserManager
你现在是在循环添加角色之后才调用InitializeOptionsAsync,建议把这个初始化操作提前到最开头,确保UserManager在整个操作过程中都处于可用状态:
// 提前初始化UserManager选项,放在所有操作之前 await _userManager.InitializeOptionsAsync(AbpSession.TenantId); // 先获取默认角色,避免在UserManager操作中途调用其他Manager的异步方法 var defaultRoles = await _roleManager.Roles.Where(r => r.IsDefault).ToListAsync(); // 再创建用户对象 var user = new User { TenantId = tenant.Id, Name = name, Surname = surname, EmailAddress = emailAddress, IsActive = true, UserName = userName, IsEmailConfirmed = isEmailConfirmed, Roles = new List<UserRole>() }; user.SetNormalizedNames(); foreach (var defaultRole in defaultRoles) { user.Roles.Add(new UserRole(tenant.Id, user.Id, defaultRole.Id)); } user.IsEmailConfirmed = isEmailConfirmed; user.ShouldChangePasswordOnNextLogin = true; CheckErrors(await _userManager.CreateAsync(user, plainPassword)); await CurrentUnitOfWork.SaveChangesAsync(); // 推荐用异步版本的SaveChanges
2. 显式包裹UnitOfWork范围
如果这段代码不在一个已有的UnitOfWork上下文中(比如在一个没有标记[UnitOfWork]的方法里),可以手动开启一个UnitOfWork,确保DbContext和相关Manager不会被提前释放:
using (var uow = UnitOfWorkManager.Begin()) { await _userManager.InitializeOptionsAsync(AbpSession.TenantId); var defaultRoles = await _roleManager.Roles.Where(r => r.IsDefault).ToListAsync(); var user = new User { /* 你的用户属性 */ }; user.SetNormalizedNames(); foreach (var defaultRole in defaultRoles) { user.Roles.Add(new UserRole(tenant.Id, user.Id, defaultRole.Id)); } user.IsEmailConfirmed = isEmailConfirmed; user.ShouldChangePasswordOnNextLogin = true; CheckErrors(await _userManager.CreateAsync(user, plainPassword)); await CurrentUnitOfWork.SaveChangesAsync(); await uow.CompleteAsync(); }
3. 检查依赖注入的生命周期配置
确保你的UserManager和RoleManager是注册为Scoped生命周期的(旧版ABP默认应该是这样,但升级过程中可能被误改)。如果被注册成Singleton,会导致它依赖的DbContext提前被释放,进而引发这个错误。
4. 检查自定义UserManagerProxy的实现
如果你项目里有自定义的UserManagerProxy类,一定要检查它的Dispose方法,有没有在不该释放的时候提前释放了内部的UserManager实例。比如有些自定义实现会在Dispose里直接释放内部对象,但如果DI容器还在使用它,就会触发这个错误。
额外提醒
升级到.NET5的时候,一定要跟着旧版ABP的官方迁移指南走,.NET5对异步操作和DI容器的生命周期管理更严格,很多之前“能用”的代码在.NET5里会暴露出资源释放的问题。另外,尽量避免在异步方法里使用同步阻塞的调用(比如.Result或者.Wait()),这也是导致上下文被提前释放的常见原因。
内容的提问来源于stack exchange,提问作者Ivan Sager

