Activities of "alexander.nikonov"

Hi.

I've read the thread which you advice. But this solution looks like a trick. Would be great if the logic was contained inside "Volo.Abp.AuditLogging" and there was no need to make external solution modifications. We use ABP framework for developing a lot of services. What will happen, when ABP team changes the logic and structure of AuditLog tables in some new release?

We would prefer to truncate an error message for AuditLog instead of changing the corresponding DB field size. What is a proper way of doing this?

Hi. Here is the reproducable situation in the test project attached. Let's say I'm trying to access http://localhost:4200/dashboard via typing the address in a browser and the logged user does not have access to this page. IAuthorizationMiddlewareResultHandlerimplementation is even not triggered - straight away default 403 forbidden is shown.

P.S. Could you please add possibility to attach code zip archives to a message? It's not user-friendly to create cloud links each time.

Answer

Ah, OK. What about ABP Permission Grant Cache? Should I use Redis to share one cache between two apps (hosted as separate IIS apps eventually) (or my approach - exchanging messages via bus and refreshing the cache in dependent apps?)

Answer

Please specify where I broke ABP design: both applications 1 and applications 2 - are ABP-framework-based. Permissions are set in application 1, since it's a "main" application. The issue was that the permissions set in application 1 were not applied to application 2. I found "workaround", but my question in the first place would be: "Why they are not applied to application 2? They are not applied even if a distributed cache key is not set in both applications. Is it because the cache in both applications is separate? Is using Redis cache a way to go then?"

Answer

I understood my mistake in the code: I am missing setting current tenant before changing cache. I am going to send tenant GUID from RabbitMq sender.

Anyway, here's the override of PermissionAppServicein back-end 1:

    using Volo.Abp.PermissionManagement;
    using System.Threading.Tasks;
    using Volo.Abp.Authorization.Permissions;
    using Microsoft.Extensions.Options;
    using System.Linq;
    using Volo.Abp.DependencyInjection;
    using AbxEps.RabbitMq.Client;
    using AbxEps.RabbitMq.Client.Messages;
    using AbxEps.Fines;

    namespace AbxEps.CentralTools
    {
        [Dependency(ReplaceServices = true)]
        [ExposeServices(typeof(IPermissionAppService))]
        public class CentralToolsPermissionAppService : PermissionAppService
        {
            private readonly IRabbitMqManager _rabbitMqManager;

            public CentralToolsPermissionAppService(
                IPermissionManager permissionManager,
                IPermissionDefinitionManager permissionDefinitionManager,
                IOptions<PermissionManagementOptions> options,
                IPermissionStateManager permissionStateManager,
                IRabbitMqManager rabbitMqManager)

                : base(permissionManager, permissionDefinitionManager, options, permissionStateManager)
            {
                _rabbitMqManager = rabbitMqManager;
            }

            public override async Task UpdateAsync(string providerName, string providerKey, UpdatePermissionsDto input)
            {
                await base.UpdateAsync(providerName, providerKey, input);

                var cacheRabbitMqInput = new CacheRabbitMqInput(input.Permissions.Select(x => x)
                    .ToDictionary(x => PermissionGrantCacheItem.CalculateCacheKey(x.Name, providerName, providerKey), x => x.IsGranted));

                await _rabbitMqManager.CreateSender().SendAsync(new RabbitMqMessage<CacheRabbitMqInput>
                {
                    RoutingKey = "AbxEps-Abp-Caching",
                    Body = cacheRabbitMqInput
                });
            }
        }
    }

Here's the triggered RabbitMq subscription in back-end 2:

    using Volo.Abp.PermissionManagement;
    using Volo.Abp.DependencyInjection;
    using Volo.Abp.EventBus.Distributed;
    using System.Threading.Tasks;
    using Volo.Abp.Caching;
    using System.Collections.Generic;
    using AbxEps.RabbitMq.Client.Receivers;
    using RabbitMQ.Client.Events;
    using System;
    using Microsoft.Extensions.DependencyInjection;
    using AbxEps.RabbitMq.Client.Extensions;
    using System.Linq;

    namespace AbxEps.Fines
    {
        public class FinesRabbitMqReceiver : RabbitMqReceiverBase
        {
            private readonly IServiceProvider _serviceProvider;

            public FinesRabbitMqReceiver(IServiceProvider serviceProvider) : base("AbxEps-Abp-Caching")
            {
                _serviceProvider = serviceProvider;
            }

            public override async Task<object> Received(BasicDeliverEventArgs @event)
            {
                using var scope = _serviceProvider.CreateScope();
                
                var permissionGrantCache = scope.ServiceProvider.GetService<IDistributedCache<PermissionGrantCacheItem>>();

                var permissions = @event.ToDataObject<Dictionary<string, bool>>();

                await permissionGrantCache.SetManyAsync(
                    permissions.Select(permission =>
                        new KeyValuePair<string, PermissionGrantCacheItem>(permission.Key, new PermissionGrantCacheItem(permission.Value))));

                return Task.FromResult<object>(null);
            }
        }            
    }

Does this approach to refresh permissions in another app looks OK or I'm missing a better ABP approach?

Answer

UPDATE: i've used RabbitMq to notify Angular 2 about permission changes in Angular 1. I am now trying to modify Angular 2 permission cache via SetManyAsync - it adds the values to the cache in Angular 2, but it still does not reflect the changes on page refresh...

Answer

I am running two Angular apps: https://localhost:4200 (Permissions are assigned and consumed here) and https://localhost:4201 (Permissions are only consumed here). Each of these two Angular apps have own HTTP API host (and own full-fledged ABP-based solution) and they share the same Identity Server. To control full set of permission in app Angular 1, I have Nuget package of Application.Contracts project from Solution 2 in Application.Contracts project of Solution 1:

So far so good. I can see and change role permissions:

The problem is that the changes made in Angular 1 are not reflected in Angular 2 - I still can see or not see the protected pages after page reload or re-login:

I've tried to override and play with IDistributedCache<PermissionGrantCacheItem>, but it does not work - most likely because both hosts have separate caches. But how to resolve the described issue then?

I am sorry, but I am now allowed to share the project. What I can do is just to show some informational screendumps, send logs and separate code files... Please let me know if I can measure some additional timings somewhere, etc. Now - just some thoughts: when I use Postman to send API requests - first TTFB is large, that's right, second and further - 10 and more times decreased. That would explain DI initialization. But in real situation, when I refresh the same page in Angular app - I am getting almost the same big timings. For instance, first run ~5-6sec per lookup API request. Next run ~1.5-3sec. Next run - about the same time... Next run - attention - ~4sec again!! Even retrieving refresh tokens at IdentityServer takes ages:

UPDATE: I've updated my controllers - removing all appservices instantiation at all. There is no DB access to retrieve data now anywhere, empty data is returned:

    [HttpGet]
    [Route("values/owners/{languageCode?}")]
    public virtual async Task&lt;PagedResultDto&lt;LookupItemDto&lt;int&gt;>> GetOwnerAsync([FromRoute] string languageCode = null)
    {
        return new PagedResultDto&lt;LookupItemDto&lt;int&gt;> { Items = new List&lt;LookupItemDto&lt;int&gt;>(), TotalCount = 0 };
    }

Also, made all API calls anonymous and without audit logging. And TTFB is still unsasisfactory. Any ideas?

DB resides on Azure cloud. Everything the rest - on localhost. Just in case: I won't be able to create local copy of DB if it is needed for a deeper testing. But as I already mentioned, sometimes there are unexplained lags even if I don't access DB.

I returned from vacation and keep on testing. I am not sure now it's a DB thing. I run API GET request from DB via appservice and TTFB was about 3-4s. Then I replaced the AbpController code which accesses DB via appservice with already mentioned above List<int> data:

        [HttpGet]
        [Route("values/module-types/{languageCode?}")]
        public virtual async Task<List<int>> GetModuleTypeAsync([FromRoute] string languageCode = null)
        {
            return new List<int>
            {
                0, 1, 2, 3, 4, 5, 6, 7, 999, 10000
            };
            // AppService DB request is commented!!!
        }

And TTFB still is 3s!

What do you suggest? Probably it has something to do with appservice DI instantiation in AbpControllers? I tried to run it in several mins when writing to you - and the time is about 50-60ms! Another API request - with appservice engaged, run straight after this, is 200-300ms...

So in other words - sometimes TTFS is more or less OK. But sometimes it is inacceptibly slow. I need to find a root cause. Emphasizing - everything is tested on localhost, VS 2020 / 2022.

I took a look at the log, trying to find information for the case when TTFB was about 3s. Please have a look at this:

2021-09-07 18:01:35.693 +03:00 [INF] Route matched with {area = "app", controller = "FixCodeValue", action = "GetModuleType", page = ""}. Executing controller action with signature System.Threading.Tasks.Task1[Volo.Abp.Application.Dtos.PagedResultDto1[AbxEps.CT.Core.Shared.LookupItemDto`1[System.Int32]]] GetModuleTypeAsync(System.String) on controller AbxEps.CentralTools.Controllers.FixCodeValues.FixCodeValueController (AbxEps.CentralTools.HttpApi). 2021-09-07 18:01:38.816 +03:00 [INF] Executing action method AbxEps.CentralTools.Controllers.FixCodeValues.FixCodeValueController.GetModuleTypeAsync (AbxEps.CentralTools.HttpApi) - Validation state: "Valid" 2021-09-07 18:01:38.996 +03:00 [INF] Executed action method AbxEps.CentralTools.Controllers.FixCodeValues.FixCodeValueController.GetModuleTypeAsync (AbxEps.CentralTools.HttpApi), returned result Microsoft.AspNetCore.Mvc.ObjectResult in 180.5069ms.

  • about 3s between "executing controller action" and "executing action method"... What those 3s in-between were spent for? Indeed, the method execution itself took only 180ms...

UPDATE: for better understanding, I'm attaching zipped log file, where logging level was set to "Debug". This time I tried to run my problematic Details page again. Could you please have a look at the log, probably it will give you some idea?

https://1drv.ms/u/s!AhWdpZddvifTtxGBMcuy35NOzw31?e=fSMRYs

On some next run, those times could be 2-3 times less (about 1.5-2sec), which is still pretty much...

UPDATE 2: cold run today, audit and authorization is turned off - debug log displays the gap between those 2 entries:

2021-09-08 11:31:11.624 +03:00 [DBG] Executing controller factory for controller AbxEps.CentralTools.Controllers.FreeCodeValues.FreeCodeValueController (AbxEps.CentralTools.HttpApi) 2021-09-08 11:31:13.063 +03:00 [DBG] Executed controller factory for controller AbxEps.CentralTools.Controllers.FreeCodeValues.FreeCodeValueController (AbxEps.CentralTools.HttpApi)

What is happening in-between? Again, next run of this request takes 255ms, so could look like a DB stuff (and now the data is cached)... But yesterday I saw big time without DB query involved.

Showing 251 to 260 of 345 entries
Boost Your Development
ABP Live Training
Packages
See Trainings
Mastering ABP Framework Book
The Official Guide
Mastering
ABP Framework
Learn More
Mastering ABP Framework Book
Made with ❤️ on ABP v10.1.0-preview. Updated on November 04, 2025, 06:41