0
alirizaadiyahsi created
- ABP Framework version: v5.2.2
- UI type: Angular
- DB provider: EF Core
- Tiered (MVC) or Identity Server Separated (Angular): microservice/angular
EventHandler Implementation
public class AccessRequestApprovedHandler : IDistributedEventHandler<AccessRequestApprovedEto>, ITransientDependency
{
private readonly IdentityUserManager _userManager;
private readonly ICustomIdentityRoleRepository _customIdentityRoleRepository;
private readonly ILogger<AccessRequestApprovedHandler> _logger;
public AccessRequestApprovedHandler(IdentityUserManager userManager, ICustomIdentityRoleRepository customIdentityRoleRepository, ILogger<AccessRequestApprovedHandler> logger)
{
_userManager = userManager;
_customIdentityRoleRepository = customIdentityRoleRepository;
_logger = logger;
}
[UnitOfWork]
public async Task HandleEventAsync(AccessRequestApprovedEto eventData)
{
try
{
var user = await _userManager.GetByIdAsync(eventData.UserId);
var roles = await _customIdentityRoleRepository.GetListByIdsAsync(eventData.RoleIds);
// Exception is thrown here.
var identityResult = await _userManager.SetRolesAsync(user, roles.Select(r => r.Name).ToArray());
if (!identityResult.Succeeded)
{
_logger.LogError($"Error occured while setting roles for user: {user.UserName}");
foreach (var error in identityResult.Errors)
{
_logger.LogError($"Error: {error.Code} - {error.Description}");
}
}
}
catch (Exception e)
{
Console.WriteLine(e);
throw;
}
}
}
Exception Message (even though I am using UnitOfWork
attribute) : A DbContext can only be created inside a unit of work!
at Volo.Abp.Uow.EntityFrameworkCore.UnitOfWorkDbContextProvider`1.GetDbContextAsync()
at Volo.Abp.Domain.Repositories.EntityFrameworkCore.EfCoreRepository`2.EnsureCollectionLoadedAsync[TProperty](TEntity entity, Expression`1 propertyExpression, CancellationToken cancellationToken)
at Volo.Abp.Domain.Repositories.RepositoryExtensions.EnsureCollectionLoadedAsync[TEntity,TKey,TProperty](IBasicRepository`2 repository, TEntity entity, Expression`1 propertyExpression, CancellationToken cancellationToken)
at Volo.Abp.Identity.IdentityUserStore.AddToRoleAsync(IdentityUser user, String normalizedRoleName, CancellationToken cancellationToken)
at Microsoft.AspNetCore.Identity.UserManager`1.AddToRolesAsync(TUser user, IEnumerable`1 roles)
at Castle.DynamicProxy.AsyncInterceptorBase.ProceedAsynchronous[TResult](IInvocation invocation, IInvocationProceedInfo proceedInfo)
at Volo.Abp.Castle.DynamicProxy.CastleAbpMethodInvocationAdapterWithReturnValue`1.ProceedAsync()
at Volo.Abp.Uow.UnitOfWorkInterceptor.InterceptAsync(IAbpMethodInvocation invocation)
at Volo.Abp.Castle.DynamicProxy.CastleAsyncAbpInterceptorAdapter`1.InterceptAsync[TResult](IInvocation invocation, IInvocationProceedInfo proceedInfo, Func`3 proceed)
at Volo.Abp.Identity.IdentityUserManager.SetRolesAsync(IdentityUser user, IEnumerable`1 roleNames)
at Castle.DynamicProxy.AsyncInterceptorBase.ProceedAsynchronous[TResult](IInvocation invocation, IInvocationProceedInfo proceedInfo)
at Volo.Abp.Castle.DynamicProxy.CastleAbpMethodInvocationAdapterWithReturnValue`1.ProceedAsync()
at Volo.Abp.Uow.UnitOfWorkInterceptor.InterceptAsync(IAbpMethodInvocation invocation)
at Volo.Abp.Castle.DynamicProxy.CastleAsyncAbpInterceptorAdapter`1.InterceptAsync[TResult](IInvocation invocation, IInvocationProceedInfo proceedInfo, Func`3 proceed)
at Daisy.IdentityService.EventHandlers.AccessRequests.AccessRequestApprovedHandler.HandleEventAsync(AccessRequestApprovedEto eventData) in C:\Users\aliriza\Documents\Projects\GitHub\Daisy\services\identity\src\Daisy.IdentityService.Application\EventHandlers\AccessRequests\AccessRequestApprovedHandler.cs:line 34
BTW, here is repo method implementation:
public async Task<List<IdentityRole>> GetListByIdsAsync(Guid[] ids, CancellationToken cancellationToken = default)
{
var query = await GetQueryableAsync();
query = query.Where(r => ids.Contains(r.Id)).OrderBy(x => x.Name);
return await query.ToListAsync(cancellationToken);
}
I think it is coming from here: UnitOfWorkDbContextProvider.cs. it seems it can not use the current unit of work.
IdentityUserManager
- SetRolesAsync
- AddToRolesAsync
- userRoleStore.AddToRoleAsync
- UserRepository.EnsureCollectionLoadedAsync
- GetDbContextAsync()
- _dbContextProvider.GetDbContextAsync()
UPDATE:
I also try IUnitOfWorkEnable
interface or inherite from ApplicationService
but no luck.
It is only working when I manage uow manually. Following is working:
public async Task HandleEventAsync(AccessRequestApprovedEto eventData)
{
_logger.LogInformation("Event name: {@eventName}. User id: {@userId}. Role ids: {@roleIds}", AccessRequestConsts.EventNames.Approved, eventData.UserId, eventData.RoleIds);
using var uow = _unitOfWorkManager.Begin();
var user = await _userManager.GetByIdAsync(eventData.UserId);
var roles = await _customIdentityRoleRepository.GetListByIdsAsync(eventData.RoleIds);
var identityResult = await _userManager.SetRolesAsync(user, roles.Select(r => r.Name).ToArray());
if (!identityResult.Succeeded)
{
_logger.LogError($"Error occured while setting roles for user: {user.UserName}");
foreach (var error in identityResult.Errors)
{
_logger.LogError($"Error: {error.Code} - {error.Description}");
}
}
await uow.CompleteAsync();
}
But I cant understand why [UnitOfWork]
attribute is not working?
2 Answer(s)
-
0
hi
You forgot the
virtual
.[UnitOfWork] public virtual async Task HandleEventAsync(AccessRequestApprovedEto eventData)
-
0
It worked. Thanks @maliming.