ASP.NET Core迁移后AbpSession.Use调用触发UserManager已释放异常
问题:ASP.NET Core 8中使用
AbpSession.Use()时出现UserManager已释放异常 将基于.NET Framework 4.6的ASP.NET Boilerplate 7.4 MVC应用迁移至ASP.NET Core 8后,在MVC控制器中使用AbpSession.Use(...)时触发异常,该问题在原MVC5应用中不存在。
相关代码
控制器代码
public class BookMgmController : AbpController { ... [HttpPost] public async Task<JsonResult> Pay(PayRequestVM input) { ... using (AbpSession.Use(AbpSession.TenantId, myAuthorizedUserIdToAccessOrders)) { // 创建订单并设置为"等待支付"状态 var order = await _orderAppService.CreateAsync(input); // <--- 问题出现处! ... } // using... } }
OrderAppService代码
[AbpAuthorize(PermissionNames.Pages_Orders)] public class OrderAppService : ..., IOrderAppService { ... public override async Task<BasicOrderDto> CreateAsync(CreateOrderDto input) { ... } ... }
异常信息
调用CreateAsync(...)时,ABP抛出异常:
Cannot access a disposed object. Object name: 'GPSoftware.Booking.Authorization.Users.UserManager'
移除OrderAppService上的AbpAuthorize属性后,异常消失。
堆栈跟踪
System.ObjectDisposedException: Cannot access a disposed object. Object name: 'GPSoftware.Booking.Authorization.Users.UserManager'. at Microsoft.AspNetCore.Identity.UserManager`1.FindByIdAsync(String userId) at Abp.Authorization.Users.AbpUserManager`2.<>c__DisplayClass91_0.<<GetUserPermissionCacheItemAsync>b__0>d.MoveNext() --- End of stack trace from previous location --- at Abp.Runtime.Caching.TypedCacheWrapper`2.<>c__DisplayClass21_0.<<GetAsync>b__0>d.MoveNext() --- End of stack trace from previous location --- at Abp.Runtime.Caching.AbpCacheBase`2.GetAsync(TKey key, Func`2 factory) at Abp.Runtime.Caching.TypedCacheWrapper`2.GetAsync(TKey key, Func`2 factory) at Abp.Authorization.Users.AbpUserManager`2.GetUserPermissionCacheItemAsync(Int64 userId) at Abp.Authorization.Users.AbpUserManager`2.IsGrantedAsync(Int64 userId, Permission permission) at Abp.Authorization.Users.AbpUserManager`2.IsGrantedAsync(Int64 userId, String permissionName) at Abp.Authorization.PermissionChecker`2.IsGrantedAsync(Int64 userId, String permissionName) at Abp.Authorization.PermissionChecker`2.IsGrantedAsync(String permissionName) at Abp.Authorization.PermissionCheckerExtensions.IsGrantedAsync(IPermissionChecker permissionChecker, Boolean requiresAll, String[] permissionNames) at Abp.Authorization.PermissionCheckerExtensions.AuthorizeAsync(IPermissionChecker permissionChecker, Boolean requireAll, String[] permissionNames) at Abp.Authorization.AuthorizationHelper.AuthorizeAsync(IEnumerable`1 authorizeAttributes) at Abp.Authorization.AuthorizationHelper.CheckPermissionsAsync(MethodInfo methodInfo, Type type) at Abp.Authorization.AuthorizationHelper.AuthorizeAsync(MethodInfo methodInfo, Type type) at Abp.Authorization.AuthorizationInterceptor.InternalInterceptAsynchronous[TResult](IInvocation invocation) at Abp.Auditing.AuditingInterceptor.InternalInterceptAsynchronous[TResult](IInvocation invocation) at Abp.Auditing.AuditingInterceptor.InternalInterceptAsynchronous[TResult](IInvocation invocation) at GPSoftware.Booking.Web.Controllers.BookMgmController.DoPay(PayShoppingCartRequestVM input) in C:\WA\GPsoftware\PortamiInPista.NET\aspnet-core\src\web\Booking.Web.Mvc\Controllers\BookMgmController.cs:line 165 at GPSoftware.Booking.Web.Controllers.BookMgmController.Pay(PayShoppingCartRequestVM input) in C:\WA\GPsoftware\PortamiInPista.NET\aspnet-core\src\web\Booking.Web.Mvc\Controllers\BookMgmController.cs:line 131
补充信息
- 更新1:大部分对象由ABP框架注入DI,运行时均不为空(包括
UserManager和AbpSession)。 - 更新2:基于ABP模板的简单测试代码未出现该错误。
调试细节
Abp.Authorization.Users.AbpUserManager<TRole, TUser>的私有方法GetUserPermissionCacheItemAsync调用FindByIdAsync和GetRolesAsync时失败:
private async Task<UserPermissionCacheItem> GetUserPermissionCacheItemAsync(long userId) { var cacheKey = userId + "@" + (GetCurrentTenantId() ?? 0); return await _cacheManager.GetUserPermissionCache().GetAsync(cacheKey, async () => { var user = await FindByIdAsync(userId.ToString()); // <= 此处失败 if (user == null) { return null; } var newCacheItem = new UserPermissionCacheItem(userId); foreach (var roleName in await GetRolesAsync(user)) { // <= 此处失败 newCacheItem.RoleIds.Add((await RoleManager.GetRoleByNameAsync(roleName)).Id); } foreach (var permissionInfo in await UserPermissionStore.GetPermissionsAsync(userId)) { if (permissionInfo.IsGranted) { newCacheItem.GrantedPermissions.Add(permissionInfo.Name); } else { newCacheItem.ProhibitedPermissions.Add(permissionInfo.Name); } } return newCacheItem; }); }
重写自定义UserManager的FindByIdAsync方法并注释ThrowIfDisposed()后可正常运行:
public override Task<User> FindByIdAsync(string userId) { //ThrowIfDisposed(); return Store.FindByIdAsync(userId, CancellationToken); }
但重写GetRolesAsync较为复杂,无法继续。
疑问与求助
- 为何会出现该问题?
- 为何模板代码无此异常?
- 求可行的解决方案。
内容的提问来源于stack exchange,提问作者Gianpiero
相关产品推荐
相关产品推荐

