- Add state-aware overload to ISimpleStateCheckerSerializer/Contributor
- Features and Permissions contributors recognise their batch checker and emit a per-state record
- PermissionDefinitionSerializer threads the owning permission through
- Pin equality semantics to match the batch runtime (default comparer)
- Replace FormattedStringValueExtracter.Extract with LastIndexOf in
PermissionGrantCacheItem and ResourcePermissionGrantCacheItem to
eliminate repeated string tokenization and object allocations on
every cache key parse (~12,000 calls per request with 4000+ permissions)
- Add fast-path in SimpleStateCheckerManager.InternalIsEnabledAsync to
skip DI scope creation when both StateCheckers and GlobalStateCheckers
are empty, avoiding thousands of unnecessary scope allocations
- Optimize PermissionChecker.IsGrantedAsync(string[]) and
ResourcePermissionChecker.IsGrantedAsync(string[], resourceName, resourceKey)
to load all permission definitions once via GetPermissionsAsync /
GetResourcePermissionsAsync instead of N individual GetOrNullAsync calls,
and use batch StateCheckerManager.IsEnabledAsync for state checking
- Optimize AbpApplicationConfigurationAppService.GetAuthConfigAsync to
pre-load all permission names into a HashSet for O(1) lookup instead
of N async GetOrNullAsync calls inside the loop
- Fix GetResourcePermissionsAsync to deduplicate by (ResourceName, Name)
instead of Name only, matching the actual uniqueness constraint of
resource permissions defined in PermissionDefinitionContext
Production impact (customer with 4000+ permissions): 10s+ -> ~682ms
- Fix ResourcePermissionDefinitions not being populated in DynamicPermissionDefinitionStoreInMemoryCache.FillAsync, causing GetResourcePermissionOrNull and GetResourcePermissions to always return empty
- Fix StaticPermissionSaver incorrectly using newRecords instead of changedRecords when collecting changed permission names for event notification
Introduces `IsAvailableAsync()` to `IResourcePermissionManagementProvider` and `IResourcePermissionProviderKeyLookupService`, allowing providers to opt out in certain contexts.
`ResourcePermissionManager` respects this flag in permission checks, writes, and UI lookup service listing.
OpenIddict and IdentityServer client providers override `IsAvailableAsync()` to return `false` when the current context is a tenant (host-only concept).
When selecting "Select All" for a specific permission group, the "Grant All Permissions"
checkbox should display an indeterminate state if not all permissions are granted.
The issue was that GrantAll and GrantAny were calculated based on _groups (filtered list)
instead of _allGroups (all groups), causing incorrect checkbox state when groups were filtered.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>