Activities of "alirizaadiyahsi"

  • ABP Framework version: v5.3.0
  • UI type: Angular
  • DB provider: EF Core
  • Tiered (MVC) or Identity Server Separated (Angular): Angular Microservice

I added a new microservice that named FileManagerService and added database blob storing to it by using this command: abp add-module Volo.Abp.BlobStoring.Database.

All looks fine but when I trying to save files, provider is using AdminstrationServiceDB.

[Authorize(FileManagerServicePermissions.FileManager.Files.FilesDefault)]
public class FileAppService : ApplicationService, IFileAppService
{
    private IBlobContainer _fileContainer;
    private readonly IBlobContainerFactory _blobContainerFactory;

    public FileAppService(IBlobContainerFactory blobContainerFactory)
    {
        _blobContainerFactory = blobContainerFactory;
    }

    public async Task<BlobDto> GetBlobAsync(GetBlobRequestDto input)
    {
        var blob = await _fileContainer.GetAllBytesAsync(input.Name);

        return new BlobDto
        {
            Name = input.Name,
            Content = blob
        };
    }

    [Authorize(FileManagerServicePermissions.FileManager.Files.Create)]
    [Authorize(FileManagerServicePermissions.FileManager.Files.Edit)]
    public async Task SaveBlobAsync(CreateBlobInput input)
    {
        _fileContainer = _blobContainerFactory.Create("microservice-name");
        await _fileContainer.SaveAsync(input.Name, input.Content, true);
    }

How I configure blobContainer to use file-manager connection string, instead of using administration-service connection string?

And this is the file-manager-service connection strings in appsettings.json.

And DB

It worked. Thanks @maliming.

  • 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?

Hi @liangshiwei, actually I am extending/overriding the end-point in identity-service microservice itself. And it is different then yours.

But yes it doesn't matter. I got your your point. I just ask for better way. Using RestService can be solution. Now, I created a library for identity and generated proxies in it.

I just have concerns about using it this way, if there are drawbacks.

  • ABP Framework version: v5.2.2
  • UI type: Angular
  • DB provider: EF Core
  • Tiered (MVC) or Identity Server Separated (Angular): no, Microservice

Identity API

I am customizing Identity module according to this document: Customizing the Application Modules I extended IdentityRoles service/repository/contoller so I have a method _roleService.GetListByIds(Guid[] ids). Everything is ok, so far. The end-point is working like expected.

Identity Angular

Question: I am creating ng-library for my each microservice to generate proxies, separately (reference:Microservice Proxy Generation). To use my new method that is in IdentityRoleService, should I create an ng-library for identity and generate identity proxies in it? So, as I understand, I will use these proxies instead of using them from abp/ng.core?

Any suggestion would be appreciated! Thanks...

Hi @muhammedaltug, your advice worked for me. It should be in Microservice documentation.

Showing 11 to 16 of 16 entries
Made with ❤️ on ABP v8.2.0-preview Updated on March 25, 2024, 15:11