We are experiencing significant delay during user login due to a slow response from the following API:
/api/abp/application-configuration?includeLocalizationResources=false
This API call is taking longer than expected and is impacting the overall login performance and user experience. Observed Behavior
- The API call consistently takes longer than expected.
- This results in delayed application loading after login.
- The issue is reproducible across multiple attempts.
Expected Behavior
- The API should respond within an acceptable time (ideally under 500 ms).
- The login and application initialization process should be smooth and fast.
Attachments
Please find the relevant screenshots below demonstrating the issue:
71 Answer(s)
-
0
Hi,
Great progress — 744ms locally is a solid improvement! Now let's find out exactly why production is still 3–4 seconds.
Please enable full debug logging temporarily on production by updating
appsettings.json:{ "Logging": { "LogLevel": { "Default": "Debug" } } }Then make one request to
/api/abp/application-configuration?includeLocalizationResources=falseand send us the full log output. The key things we're looking for:- Does it say
BulkPermissionStore: cache hitorcache missin production? - What is the
Request finishedline's duration (in ms) for that endpoint? This tells us the server-side time vs. browser-measured time. - Any slow operations from
Volo.Abp.PermissionManagementorVolo.Abp.Caching.
Also a few quick questions about your production setup:
- How many microservices are in your solution, and how many of them define their own permissions?
- Is your production Redis in the same data center / availability zone as your application servers, or in a different location?
- Do you have multiple instances of the
application-configurationservice running behind a load balancer?
These details will help us pinpoint whether the slowness is coming from Redis latency, permission definition loading across services, or something else entirely.
Thanks
Markdown supported.Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post) - Does it say
-
0
Sure, we can do that if needed. But before the meeting, could you first share the debug log output from the admin service? That way we can have concrete data to look at together.
Please enable the debug logging in the admin service as mentioned above, make one request to
/api/abp/application-configuration?includeLocalizationResources=falseon the production server, and share the full log output liming.ma@volosoft.com.Thanks
Markdown supported.Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post) -
0
Hello this is log on hard refresh [05:01:40 DBG] Executing AbpApplicationConfigurationAppService.GetAsync()...
[05:01:40 DBG] BulkPermissionStore: cache hit for U:0e3c4557-57fd-31b4-7781-3a1df656b05c.
[05:01:40 DBG] BulkPermissionStore: cache hit for R:admin.
[05:01:40 DBG] BulkPermissionStore: cache hit for C:Angular.
[05:01:40 DBG] Executed AbpApplicationConfigurationAppService.GetAsync().
[05:01:40 INF] Executing ObjectResult, writing value of type 'Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations.ApplicationConfigurationDto'.
[05:01:40 INF] Executed action Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations.AbpApplicationConfigurationController.GetAsync (Volo.Abp.AspNetCore.Mvc) in 680.5212ms
[05:01:40 INF] Executed endpoint 'Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations.AbpApplicationConfigurationController.GetAsync (Volo.Abp.AspNetCore.Mvc)'
[05:01:40 INF] Request finished HTTP/1.1 GET http://adminserver/api/abp/application-configuration?includeLocalizationResources=false - 200 null application/json; charset=utf-8 682.3877ms
[05:01:41 INF] Request starting HTTP/1.1 GET http://adminserver/api/abp/application-localization?cultureName=en-GB&onlyDynamics=false - null null
[05:01:41 INF] CORS policy execution successful.
[05:01:41 INF] Executing endpoint 'Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations.AbpApplicationLocalizationController.GetAsync (Volo.Abp.AspNetCore.Mvc)'
[05:01:41 INF] Route matched with {area = "abp", action = "Get", controller = "AbpApplicationLocalization", page = ""}. Executing controller action with signature System.Threading.Tasks.Task`1[Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations.ApplicationLocalizationDto] GetAsync(Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations.ApplicationLocalizationRequestDto) on controller Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations.AbpApplicationLocalizationController (Volo.Abp.AspNetCore.Mvc).
Can you please connect over a meeting? I want to clarify one thing.
Markdown supported.Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post) -
0
Hi,
Thanks for the logs! The server-side processing time is 682ms, and all three bulk cache lookups are hitting the cache (U, R, C). The optimizations are working well on the server side.
The 996ms in the browser includes network latency between your browser and the production server, which is expected.
Just to confirm — compared to the original 10+ seconds, does this feel like the issue is resolved for you now? Or is there still something you'd like us to look into further?
You also mentioned you wanted to clarify something — what is it?
Thanks
Markdown supported.Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post) -
0
Hi,
What issues are you currently running into? Happy to help here.
If there's any sensitive information you'd prefer not to share publicly, feel free to email me at liming.ma@volosoft.com.
Thanks
Markdown supported.Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post) -
0
Hi,
Just to let you know, we've identified several performance bottlenecks in the framework when dealing with a large number of permissions. We'll be making enhancements in a future version to improve this out of the box.
In the meantime, the workaround files we provided should keep things running smoothly for you.
Thanks
Markdown supported.Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post) -
0
Hi,
Yes, these optimizations will be included in the next ABP release (10.3). Once you upgrade to 10.3, you can remove all 4 files we provided.
For now, please keep the patch files as they are — they're working well and giving you better performance than the framework changes alone (especially the bulk cache optimization for Redis).
Thanks
Markdown supported.Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post) -
0
Hello This api in my other production taking 4 sec
This is log of first login
10:10:14LOG[04:38:41 DBG] BulkPermissionStore: cache miss for U:c90580c7-382d-de83-3b8a-3a1fd52c9d3c, loading from DB. 10:10:14LOG[04:38:41 DBG] BulkPermissionStore: cached 0 granted permissions for U:c90580c7-382d-de83-3b8a-3a1fd52c9d3c. 10:10:14LOG[04:38:41 DBG] BulkPermissionStore: cache miss for R:admin, loading from DB. 10:10:14LOG[04:38:42 DBG] BulkPermissionStore: cached 8389 granted permissions for R:admin. 10:10:14LOG[04:38:42 DBG] BulkPermissionStore: cache miss for C:Angular, loading from DB. 10:10:14LOG[04:38:42 DBG] BulkPermissionStore: cached 0 granted permissions for C:Angular. 10:10:14LOG[04:38:42 DBG] Executed AbpApplicationConfigurationAppService.GetAsync(). 10:10:14LOG[04:38:43 INF] Executing ObjectResult, writing value of type 'Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations.ApplicationConfigurationDto'. 10:10:14LOG[04:38:43 INF] Executed action Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations.AbpApplicationConfigurationController.GetAsync (Volo.Abp.AspNetCore.Mvc) in 3499.4922ms 10:10:14LOG[04:38:43 INF] Executed endpoint 'Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations.AbpApplicationConfigurationController.GetAsync (Volo.Abp.AspNetCore.Mvc)' 10:10:14LOG[04:38:43 INF] Request finished HTTP/1.1 GET http://adminserver/api/abp/application-configuration?includeLocalizationResources=false - 200 null application/json; charset=utf-8 3798.3348ms
This is Log after login any page refresh
10:10:15LOG[04:40:12 DBG] BulkPermissionStore: cache hit for U:c90580c7-382d-de83-3b8a-3a1fd52c9d3c. 10:10:15LOG[04:40:12 DBG] BulkPermissionStore: cache hit for R:admin. 10:10:15LOG[04:40:12 DBG] BulkPermissionStore: cache hit for C:Angular. 10:10:15LOG[04:40:12 DBG] Executed AbpApplicationConfigurationAppService.GetAsync(). 10:10:15LOG[04:40:12 INF] Executing ObjectResult, writing value of type 'Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations.ApplicationConfigurationDto'. 10:10:15LOG[04:40:12 INF] Executed action Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations.AbpApplicationConfigurationController.GetAsync (Volo.Abp.AspNetCore.Mvc) in 1954.0202ms 10:10:15LOG[04:40:12 INF] Executed endpoint 'Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations.AbpApplicationConfigurationController.GetAsync (Volo.Abp.AspNetCore.Mvc)' 10:10:15LOG[04:40:12 INF] Request finished HTTP/1.1 GET http://adminserver/api/abp/application-configuration?includeLocalizationResources=false - 200 null application/json; charset=utf-8 1957.8207ms 10:10:15LOG[04:40:12 INF] Request starting HTTP/1.1 GET http://adminserver/api/abp/application-localization?cultureName=en-GB&onlyDynamics=false - null null
Markdown supported.Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post) -
0
Hi
I can see BulkPermissionStore is working — cache hits are showing correctly. But the warm cache time (1954ms) is still high, which tells me there's more we can optimize.
A few questions about this environment:
This is a different production environment from the one we tested earlier (which showed 682ms), right? How many production environments do you have?
I see 8389 granted permissions for the
R:adminrole — that's significantly more than your other environment. Is this expected? Do different environments have different permission configurations?Did you deploy all 4 files we provided to this environment? Specifically:
BulkPermissionStore.cs(the updated version withIsGrantedAsyncoverride)PermissionGrantBulkCacheItem.csPermissionGrantBulkCacheItemInvalidator.csOptimizedPermissionChecker.cs← this one is critical
The
OptimizedPermissionChecker.cshandles the application-layer optimization. Without it, even with BulkPermissionStore working, 8389 permissions will still cause ~2 seconds of processing overhead. Could you check if this file is included and properly registered?How many microservices are running in this environment? Is it the same architecture as the other production?
What are the server specs (CPU/RAM) for this environment compared to your other production and local?
Could you also share the warm cache log from your first production environment (the one that showed 682ms) for comparison? I want to confirm that environment has all 4 files working.
Thanks
Markdown supported.Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post) -
0
Hello This is a different production environment from the one we tested earlier (which showed 682ms), right? How many production environments do you have?
we have 3 producation
I see 8389 granted permissions for the R:admin role — that's significantly more than your other environment. Is this expected? Do different environments have different permission configurations?
not cause of this producation has less module

Did you deploy all 4 files we provided to this environment? Specifically: yes all 4 files shared
How many microservices are running in this environment? Is it the same architecture as the other production? same architecture but in this we only used hotel module
What are the server specs (CPU/RAM) for this environment compared to your other production and local?
128 GB RAM, 24 Cores (48 Threads) this is of that producation in which taking
and both severs in netherlands
Could you also share the warm cache log from your first production environment (the one that showed 682ms) for comparison? I want to confirm that environment has all 4 files working.
This First time login removing all cookies and all [09:53:14 DBG] BulkPermissionStore: cache miss for U:0162719b-2c7b-adb3-a629-3a1dfef2a46e, loading from DB.
[09:53:14 DBG] BulkPermissionStore: cached 181 granted permissions for U:0162719b-2c7b-adb3-a629-3a1dfef2a46e.
[09:53:14 DBG] BulkPermissionStore: cache miss for R:admin, loading from DB.
[09:53:14 DBG] BulkPermissionStore: cached 4410 granted permissions for R:admin.
[09:53:14 DBG] BulkPermissionStore: cache miss for C:Angular, loading from DB.
[09:53:14 DBG] BulkPermissionStore: cached 0 granted permissions for C:Angular.
[09:53:15 DBG] Executed AbpApplicationConfigurationAppService.GetAsync().
[09:53:15 INF] Executing ObjectResult, writing value of type 'Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations.ApplicationConfigurationDto'.
[09:53:15 INF] Executed action Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations.AbpApplicationConfigurationController.GetAsync (Volo.Abp.AspNetCore.Mvc) in 1200.108ms
THis is after login on page refresh [09:54:27 DBG] Executing AbpApplicationConfigurationAppService.GetAsync()...
[09:54:28 DBG] BulkPermissionStore: cache hit for U:0162719b-2c7b-adb3-a629-3a1dfef2a46e.
[09:54:28 DBG] BulkPermissionStore: cache hit for R:admin.
[09:54:28 DBG] BulkPermissionStore: cache hit for C:Angular.
[09:54:28 DBG] Executed AbpApplicationConfigurationAppService.GetAsync().
[09:54:28 INF] Executing ObjectResult, writing value of type 'Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations.ApplicationConfigurationDto'.
[09:54:28 INF] Executed action Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations.AbpApplicationConfigurationController.GetAsync (Volo.Abp.AspNetCore.Mvc) in 829.4288ms
[09:54:28 INF] Executed endpoint 'Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations.AbpApplicationConfigurationController.GetAsync (Volo.Abp.AspNetCore.Mvc)'
[09:54:28 INF] Request finished HTTP/1.1 GET http://adminserver/api/abp/application-configuration?includeLocalizationResources=false - 200 null application/json; charset=utf-8 833.1524ms
Markdown supported.Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post) -
0
Hi,
Thanks for the detailed logs and screenshots! Let me address everything.
About the warm cache performance (1954ms / 829ms)
Even though BulkPermissionStore is working well (all cache hits), there's still a bottleneck in
GetAuthConfigAsync— it callsGetOrNullAsyncfor every single permission in a loop. With 4410 permissions that's 4410 async calls, with 8389 it's 8389 async calls. This is why the time is proportional to permission count.We have a 5th patch file that fixes this. Please add
OptimizedAppConfigurationAppService.csto your project alongside the other 4 files:using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using Microsoft.AspNetCore.Authorization; using Microsoft.Extensions.Options; using Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations; using Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations.ObjectExtending; using Volo.Abp.Authorization; using Volo.Abp.Authorization.Permissions; using Volo.Abp.DependencyInjection; using Volo.Abp.Features; using Volo.Abp.Localization; using Volo.Abp.MultiTenancy; using Volo.Abp.Settings; using Volo.Abp.Timing; using Volo.Abp.Users; [Dependency(ReplaceServices = true)] [ExposeServices(typeof(IAbpApplicationConfigurationAppService))] public class OptimizedAppConfigurationAppService : AbpApplicationConfigurationAppService { public OptimizedAppConfigurationAppService( IOptions<AbpLocalizationOptions> localizationOptions, IOptions<AbpMultiTenancyOptions> multiTenancyOptions, IServiceProvider serviceProvider, IAbpAuthorizationPolicyProvider abpAuthorizationPolicyProvider, IPermissionDefinitionManager permissionDefinitionManager, DefaultAuthorizationPolicyProvider defaultAuthorizationPolicyProvider, IPermissionChecker permissionChecker, IAuthorizationService authorizationService, ICurrentUser currentUser, ISettingProvider settingProvider, ISettingDefinitionManager settingDefinitionManager, IFeatureDefinitionManager featureDefinitionManager, ILanguageProvider languageProvider, ITimezoneProvider timezoneProvider, IOptions<AbpClockOptions> abpClockOptions, ICachedObjectExtensionsDtoService cachedObjectExtensionsDtoService, IOptions<AbpApplicationConfigurationOptions> options) : base(localizationOptions, multiTenancyOptions, serviceProvider, abpAuthorizationPolicyProvider, permissionDefinitionManager, defaultAuthorizationPolicyProvider, permissionChecker, authorizationService, currentUser, settingProvider, settingDefinitionManager, featureDefinitionManager, languageProvider, timezoneProvider, abpClockOptions, cachedObjectExtensionsDtoService, options) { } protected override async Task<ApplicationAuthConfigurationDto> GetAuthConfigAsync() { var authConfig = new ApplicationAuthConfigurationDto(); var abpAuthorizationPolicyProvider = LazyServiceProvider .LazyGetRequiredService<IAbpAuthorizationPolicyProvider>(); var permissionDefinitionManager = LazyServiceProvider .LazyGetRequiredService<IPermissionDefinitionManager>(); var defaultAuthorizationPolicyProvider = LazyServiceProvider .LazyGetRequiredService<DefaultAuthorizationPolicyProvider>(); var permissionChecker = LazyServiceProvider .LazyGetRequiredService<IPermissionChecker>(); var authorizationService = LazyServiceProvider .LazyGetRequiredService<IAuthorizationService>(); var policyNames = await abpAuthorizationPolicyProvider.GetPoliciesNamesAsync(); var abpPolicyNames = new List<string>(); var otherPolicyNames = new List<string>(); var permissionNameSet = new HashSet<string>( (await permissionDefinitionManager.GetPermissionsAsync()).Select(p => p.Name), StringComparer.Ordinal); foreach (var policyName in policyNames) { if (await defaultAuthorizationPolicyProvider.GetPolicyAsync(policyName) == null && permissionNameSet.Contains(policyName)) { abpPolicyNames.Add(policyName); } else { otherPolicyNames.Add(policyName); } } foreach (var policyName in otherPolicyNames) { if (await authorizationService.IsGrantedAsync(policyName)) { authConfig.GrantedPolicies[policyName] = true; } } var result = await permissionChecker.IsGrantedAsync(abpPolicyNames.ToArray()); foreach (var item in result.Result) { if (item.Value == PermissionGrantResult.Granted) { authConfig.GrantedPolicies[item.Key] = true; } } return authConfig; } }Note: The constructor parameters must match your ABP version (9.2.0). If you get a compile error about constructor parameters, please let me know and I'll adjust.
About the permission count (UI shows ~1800 but cache shows 4410/8389)
The permission count in the cache comes from the
AbpPermissionGrantsdatabase table — it shows how many permissions are granted, not how many are defined. In your screenshot I can see "Grant all permissions" is checked, so all defined permissions get granted.The UI dialog shows permissions from currently registered modules. But the database may contain grants from previously installed modules that were later removed. These orphaned grants are harmless but they increase the cache size. You can verify by running this SQL on both databases:
SELECT COUNT(*) FROM AbpPermissionGrants WHERE ProviderName = 'R' AND ProviderKey = 'admin';About a meeting
I understand the desire for a call, but the bottleneck here is something we can only diagnose through logs and data — a meeting wouldn't give us more visibility than what the debug logs already show. Each round of logs has helped us identify and fix a specific layer of the problem. Please try deploying this 5th file and share the updated logs — I expect a significant improvement.
Thanks
Markdown supported.Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post) -
0
Sorry but I want to understand why there is this much permission in the database and in the UI, not why.
this is log of second environment in which call taking 4 sec. This permission in the tenant database
This permission in host database

I want to make the same permission as in the UI and know this difference also. Why is there so difference between host and tenant
one more thing that why ui permisison count and databse not matching ?
And regarding calls, why am I asking? Because on calls I can show you architecture. and all so in one moment we can solve this
Markdown supported.Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post) -
0
Hi,
Let me explain what's happening with the permission counts.
Why Host (8389) has more than Tenant (4317)
This is expected in ABP multi-tenancy. Each permission definition has a
MultiTenancySideflag — it can beHost,Tenant, orBoth. When you click "Grant all permissions":- On the Host side: it grants all permissions marked as
HostorBoth - On the Tenant side: it grants all permissions marked as
TenantorBoth
Host typically has more permissions because some permissions are host-only (e.g., tenant management, edition management). So the difference between 8389 and 4317 is normal.
Why the database has more than the UI shows (~1810)
The permission management UI only shows currently defined permissions — permissions that your running microservices actively register. But the
AbpPermissionGrantstable stores all grants ever made, including grants for permissions that no longer exist (orphaned grants).This can happen when:
- A module was installed, "Grant all" was clicked, then the module was later removed or replaced
- Permission names were changed in a module update (old grants for old names remain)
- A microservice was previously running and registered permissions, but is no longer active
Important: Don't delete these records
In a microservices architecture, the
AbpPermissionGrantstable might be shared across services. What looks like "orphaned" from the admin service UI might actually be permissions registered by other microservices that aren't visible in the current admin UI. Deleting them could break permission checks in those services.ABP safely ignores grants for undefined permissions at runtime, so they don't cause any functional issues.
How to investigate
You can run these queries to understand the data better. These are read-only queries, just for investigation:
-- 1. How many grants per provider in this database? SELECT ProviderName, ProviderKey, COUNT(*) as GrantCount FROM AbpPermissionGrants GROUP BY ProviderName, ProviderKey ORDER BY GrantCount DESC; -- 2. Find permission names that are granted but might not be currently defined -- Export this list and compare with what you see in the UI SELECT DISTINCT Name FROM AbpPermissionGrants WHERE ProviderName = 'R' AND ProviderKey = 'admin' ORDER BY Name; -- 3. Check if there are duplicate grants (same permission granted multiple times) SELECT Name, COUNT(*) as Cnt FROM AbpPermissionGrants WHERE ProviderName = 'R' AND ProviderKey = 'admin' GROUP BY Name HAVING COUNT(*) > 1;Query #2 will give you the full list of granted permission names. You can compare this with the permissions shown in the UI to identify which ones are "extra". Most likely they belong to modules or services that were previously installed.
About the 5th patch file
Did you get a chance to deploy the
OptimizedAppConfigurationAppService.csfile I shared earlier? That should help with the remaining performance issue. Please share the updated logs after deploying it.Thanks
Markdown supported.Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post) - On the Host side: it grants all permissions marked as
-
0
Hello i did 5th file but took too much time

this server login logs 10:30:51 LOG [04:55:39 DBG] BulkPermissionStore: cache hit for U:8e19f3c2-3cca-01a5-c78a-3a1fd5abe6b6. 10:30:51 LOG [04:55:39 DBG] BulkPermissionStore: cache hit for R:admin. 10:30:51 LOG [04:55:39 DBG] BulkPermissionStore: cache hit for C:Angular. 10:30:51 LOG [04:55:39 DBG] Executed AbpApplicationConfigurationAppService.GetAsync(). 10:30:51 LOG [04:55:39 INF] Executing ObjectResult, writing value of type 'Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations.ApplicationConfigurationDto'. 10:30:51 LOG [04:55:39 INF] Executed action Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations.AbpApplicationConfigurationController.GetAsync (Volo.Abp.AspNetCore.Mvc) in 4423.175ms 10:30:51 LOG [04:55:39 INF] Executed endpoint 'Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations.AbpApplicationConfigurationController.GetAsync (Volo.Abp.AspNetCore.Mvc)' 10:30:51 LOG [04:55:39 INF] Request finished HTTP/1.1 GET http://adminserver/api/abp/application-configuration?includeLocalizationResources=false - 200 null application/json; charset=utf-8 4542.4664ms 10:30:51 LOG [04:55:41 INF] Request starting HTTP/1.1 GET http://adminserver/api/abp/application-localization?cultureName=en&onlyDynamics=false - null null
and this is very random behavior on page refresh 0:46:35 LOG [05:13:51 DBG] BulkPermissionStore: cache hit for U:8e19f3c2-3cca-01a5-c78a-3a1fd5abe6b6. 10:46:35 LOG [05:13:51 DBG] BulkPermissionStore: cache hit for R:admin. 10:46:35 LOG [05:13:51 DBG] BulkPermissionStore: cache hit for C:Angular. 10:46:35 LOG [05:13:56 INF] Executing ObjectResult, writing value of type 'Volo.Abp.PermissionManagement.GetPermissionListResultDto'. 10:46:35 LOG [05:13:56 INF] Executed action Volo.Abp.PermissionManagement.PermissionsController.GetAsync (Volo.Abp.PermissionManagement.HttpApi) in 5119.4761ms 10:46:35 LOG [05:13:56 INF] Executed endpoint 'Volo.Abp.PermissionManagement.PermissionsController.GetAsync (Volo.Abp.PermissionManagement.HttpApi)' 10:46:35 LOG [05:13:56 INF] Request finished HTTP/1.1 GET http://adminserver/api/permission-management/permissions?providerName=R&providerKey=admin - 200 null application/json; charset=utf-8 5159.0171ms 10:46:35 LOG [05:13:57 DBG] Executing HealthCheck collector HostedService. 10:46:35 LOG [05:13:57 INF] Start processing HTTP request GET http://[::]/health-status 10:46:35 LOG [05:13:57 INF] Sending HTTP request GET http://[::]/health-status
Markdown supported.Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post) -
0
Hi,
Thanks for testing. The 3391ms is likely a one-time cold start after restarting the application — the permission definition cache needs to reload from the database on the first request.
Could you please refresh the page once more and share the server log for that second request? We need to compare it with the previous 1954ms to see if the optimization is working.
Also, I've updated the
OptimizedAppConfigurationAppService.cswith timing logs for each step. Please replace the file with this new version — it will tell us exactly where the time is being spent:using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Threading.Tasks; using Microsoft.AspNetCore.Authorization; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations; using Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations.ObjectExtending; using Volo.Abp.Authorization; using Volo.Abp.Authorization.Permissions; using Volo.Abp.DependencyInjection; using Volo.Abp.Features; using Volo.Abp.Localization; using Volo.Abp.MultiTenancy; using Volo.Abp.Settings; using Volo.Abp.Timing; using Volo.Abp.Users; [Dependency(ReplaceServices = true)] [ExposeServices(typeof(IAbpApplicationConfigurationAppService))] public class OptimizedAppConfigurationAppService : AbpApplicationConfigurationAppService { public OptimizedAppConfigurationAppService( IOptions<AbpLocalizationOptions> localizationOptions, IOptions<AbpMultiTenancyOptions> multiTenancyOptions, IServiceProvider serviceProvider, IAbpAuthorizationPolicyProvider abpAuthorizationPolicyProvider, IPermissionDefinitionManager permissionDefinitionManager, DefaultAuthorizationPolicyProvider defaultAuthorizationPolicyProvider, IPermissionChecker permissionChecker, IAuthorizationService authorizationService, ICurrentUser currentUser, ISettingProvider settingProvider, ISettingDefinitionManager settingDefinitionManager, IFeatureDefinitionManager featureDefinitionManager, ILanguageProvider languageProvider, ITimezoneProvider timezoneProvider, IOptions<AbpClockOptions> abpClockOptions, ICachedObjectExtensionsDtoService cachedObjectExtensionsDtoService, IOptions<AbpApplicationConfigurationOptions> options) : base(localizationOptions, multiTenancyOptions, serviceProvider, abpAuthorizationPolicyProvider, permissionDefinitionManager, defaultAuthorizationPolicyProvider, permissionChecker, authorizationService, currentUser, settingProvider, settingDefinitionManager, featureDefinitionManager, languageProvider, timezoneProvider, abpClockOptions, cachedObjectExtensionsDtoService, options) { } protected override async Task<ApplicationAuthConfigurationDto> GetAuthConfigAsync() { var sw = Stopwatch.StartNew(); var authConfig = new ApplicationAuthConfigurationDto(); var abpAuthorizationPolicyProvider = LazyServiceProvider .LazyGetRequiredService<IAbpAuthorizationPolicyProvider>(); var permissionDefinitionManager = LazyServiceProvider .LazyGetRequiredService<IPermissionDefinitionManager>(); var defaultAuthorizationPolicyProvider = LazyServiceProvider .LazyGetRequiredService<DefaultAuthorizationPolicyProvider>(); var permissionChecker = LazyServiceProvider .LazyGetRequiredService<IPermissionChecker>(); var authorizationService = LazyServiceProvider .LazyGetRequiredService<IAuthorizationService>(); var policyNames = await abpAuthorizationPolicyProvider.GetPoliciesNamesAsync(); var abpPolicyNames = new List<string>(); var otherPolicyNames = new List<string>(); var permissionNameSet = new HashSet<string>( (await permissionDefinitionManager.GetPermissionsAsync()).Select(p => p.Name), StringComparer.Ordinal); foreach (var policyName in policyNames) { if (await defaultAuthorizationPolicyProvider.GetPolicyAsync(policyName) == null && permissionNameSet.Contains(policyName)) { abpPolicyNames.Add(policyName); } else { otherPolicyNames.Add(policyName); } } foreach (var policyName in otherPolicyNames) { if (await authorizationService.IsGrantedAsync(policyName)) { authConfig.GrantedPolicies[policyName] = true; } } var result = await permissionChecker.IsGrantedAsync(abpPolicyNames.ToArray()); foreach (var item in result.Result) { if (item.Value == PermissionGrantResult.Granted) { authConfig.GrantedPolicies[item.Key] = true; } } Logger.LogInformation("OptimizedAppConfig: GetAuthConfigAsync took {Elapsed}ms", sw.ElapsedMilliseconds); return authConfig; } protected override async Task<ApplicationFeatureConfigurationDto> GetFeaturesConfigAsync() { var sw = Stopwatch.StartNew(); var result = await base.GetFeaturesConfigAsync(); Logger.LogInformation("OptimizedAppConfig: GetFeaturesConfigAsync took {Elapsed}ms", sw.ElapsedMilliseconds); return result; } protected override async Task<ApplicationLocalizationConfigurationDto> GetLocalizationConfigAsync( ApplicationConfigurationRequestOptions options) { var sw = Stopwatch.StartNew(); var result = await base.GetLocalizationConfigAsync(options); Logger.LogInformation("OptimizedAppConfig: GetLocalizationConfigAsync took {Elapsed}ms", sw.ElapsedMilliseconds); return result; } protected override async Task<TimingDto> GetTimingConfigAsync() { var sw = Stopwatch.StartNew(); var result = await base.GetTimingConfigAsync(); Logger.LogInformation("OptimizedAppConfig: GetTimingConfigAsync took {Elapsed}ms", sw.ElapsedMilliseconds); return result; } }After deploying, please make two requests (first login + one page refresh) and share the full server logs. We'll see something like:
OptimizedAppConfig: GetAuthConfigAsync took XXms OptimizedAppConfig: GetFeaturesConfigAsync took XXms OptimizedAppConfig: GetLocalizationConfigAsync took XXms OptimizedAppConfig: GetTimingConfigAsync took XXmsThis will tell us exactly which part is slow.
About the permission count in the database
Host (8389) vs Tenant (4317): This is expected. ABP permissions have a
MultiTenancySidesetting — some permissions are host-only (like tenant management). When you click "Grant all permissions" on the host side, it grants more permissions than on the tenant side. So the difference is normal.Database (4317) vs UI (~1810): The
AbpPermissionGrantstable stores all grants ever made. The UI only shows permissions that are currently defined by your running microservices. The difference could be from:- Modules or microservices that were previously installed and had "Grant all" clicked, but were later removed
- Microservices that registered permissions but are no longer connected to the admin service
- Permission names that changed in module updates (old grants remain)
These extra grants in the database are harmless — ABP ignores them at runtime. They don't affect functionality or security. I would not recommend deleting them, especially in a microservices setup where other services might still reference those permissions.
To check if there are grants for permissions that no longer have a definition record:
SELECT pg.Name FROM AbpPermissionGrants pg WHERE pg.ProviderName = 'R' AND pg.ProviderKey = 'admin' AND pg.Name NOT IN (SELECT Name FROM AbpPermissions) ORDER BY pg.Name;Note: ABP also keeps old permission definitions in the
AbpPermissionstable even after a module is removed, so this query might not find all the "extra" ones. The difference between the UI count and the database count is mostly due to how ABP accumulates data over time across all your microservices.Thanks
Markdown supported.Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post) -
0
Hello Here' logs
10:59:26 LOG [05:28:58 DBG] Executing AbpApplicationConfigurationAppService.GetAsync()... 10:59:26 LOG [05:29:01 DBG] BulkPermissionStore: cache hit for U:8e19f3c2-3cca-01a5-c78a-3a1fd5abe6b6. 10:59:26 LOG [05:29:01 DBG] BulkPermissionStore: cache hit for R:admin. 10:59:27 LOG [05:29:01 DBG] BulkPermissionStore: cache hit for C:Angular. 10:59:27 LOG [05:29:01 INF] OptimizedAppConfig: GetAuthConfigAsync took 3474ms 10:59:27 LOG [05:29:02 INF] OptimizedAppConfig: GetFeaturesConfigAsync took 29ms 10:59:27 LOG [05:29:02 INF] OptimizedAppConfig: GetLocalizationConfigAsync took 0ms 10:59:27 LOG [05:29:02 INF] OptimizedAppConfig: GetTimingConfigAsync took 1ms 10:59:27 LOG [05:29:02 DBG] Executed AbpApplicationConfigurationAppService.GetAsync(). 10:59:27 LOG [05:29:02 INF] Executing ObjectResult, writing value of type 'Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations.ApplicationConfigurationDto'. 10:59:27 LOG [05:29:02 INF] Executed action Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations.AbpApplicationConfigurationController.GetAsync (Volo.Abp.AspNetCore.Mvc) in 3517.6511ms 10:59:27 LOG [05:29:02 INF] Executed endpoint 'Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations.AbpApplicationConfigurationController.GetAsync (Volo.Abp.AspNetCore.Mvc)' 10:59:27 LOG [05:29:02 INF] Request finished HTTP/1.1 GET http://adminserver/api/abp/application-configuration?includeLocalizationResources=false - 200 null application/json; charset=utf-8 3523.1263ms 10:59:27 LOG [05:29:02 INF] Request starting HTTP/1.1 GET http://adminserver/api/abp/application-localization?cultureName=en&onlyDynamics=false - null null
Markdown supported.Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post)

