Is there an existing issue for this?
Is your feature request related to a problem? Please describe the problem.
When implementing dynamic permissions, settings, or features that extend existing modules, I noticed that the current implementation of IPermissionDefinitionManager.GetGroupsAsync (and similar managers for settings and features) filters out definitions that share the same name as statically defined ones.
Specifically, when a user extends a module without using plugins or direct references, and adds custom permissions, these custom definitions are silently discarded during the GetGroupsAsync call because the system assumes that any definition with a duplicate name is a duplicate entry and should be skipped. This makes it impossible to extend built-in modules with additional permission, setting, or feature definitions in a clean way when the extension is not integrated through standard module referencing mechanisms.
This behavior is not documented and creates a hidden limitation for modular extension scenarios.
Describe the solution you'd like
I propose that the ABP framework should support aggregating dynamic and static definitions for permissions, settings, and features.
Expected behavior:
When GetGroupsAsync is called, it should return a combined set of definitions from both static registration and dynamic providers.
If the dynamic definition has the same name as the static definition, the framework should merge or override it based on the dynamic option strategy (for example, the dynamic option takes precedence over the static one, or an exception is thrown and clear guidance is provided).
This should be consistent across PermissionDefinitionManager, SettingDefinitionManager, and FeatureDefinitionManager.
Additional context
|
public virtual async Task<IReadOnlyList<FeatureGroupDefinition>> GetGroupsAsync() |
|
{ |
|
var staticGroups = await StaticStore.GetGroupsAsync(); |
|
var staticGroupNames = staticGroups |
|
.Select(p => p.Name) |
|
.ToImmutableHashSet(); |
|
|
|
var dynamicGroups = await DynamicStore.GetGroupsAsync(); |
|
|
|
/* We prefer static groups over dynamics */ |
|
return staticGroups.Concat( |
|
dynamicGroups.Where(d => !staticGroupNames.Contains(d.Name)) |
|
).ToImmutableList(); |
|
} |
Example of Combined Permissions:
public virtual async Task<IReadOnlyList<PermissionGroupDefinition>> GetGroupsAsync()
{
var staticGroups = await _staticStore.GetGroupsAsync();
var dynamicGroups = await _dynamicStore.GetGroupsAsync();
var mergedGroups = new Dictionary<string, PermissionGroupDefinition>();
foreach (var staticGroup in staticGroups)
{
mergedGroups[staticGroup.Name] = staticGroup;
}
foreach (var dynamicGroup in dynamicGroups)
{
if (mergedGroups.TryGetValue(dynamicGroup.Name, out var existingGroup))
{
MergeGroupPermissions(existingGroup, dynamicGroup);
}
else
{
mergedGroups[dynamicGroup.Name] = dynamicGroup;
}
}
return mergedGroups.Values.ToImmutableList();
}
// Implement MergeGroupPermissions
Is there an existing issue for this?
Is your feature request related to a problem? Please describe the problem.
When implementing dynamic permissions, settings, or features that extend existing modules, I noticed that the current implementation of IPermissionDefinitionManager.GetGroupsAsync (and similar managers for settings and features) filters out definitions that share the same name as statically defined ones.
Specifically, when a user extends a module without using plugins or direct references, and adds custom permissions, these custom definitions are silently discarded during the GetGroupsAsync call because the system assumes that any definition with a duplicate name is a duplicate entry and should be skipped. This makes it impossible to extend built-in modules with additional permission, setting, or feature definitions in a clean way when the extension is not integrated through standard module referencing mechanisms.
This behavior is not documented and creates a hidden limitation for modular extension scenarios.
Describe the solution you'd like
I propose that the ABP framework should support aggregating dynamic and static definitions for permissions, settings, and features.
Expected behavior:
When
GetGroupsAsyncis called, it should return a combined set of definitions from both static registration and dynamic providers.If the dynamic definition has the same name as the static definition, the framework should merge or override it based on the dynamic option strategy (for example, the dynamic option takes precedence over the static one, or an exception is thrown and clear guidance is provided).
This should be consistent across PermissionDefinitionManager, SettingDefinitionManager, and FeatureDefinitionManager.
Additional context
abp/framework/src/Volo.Abp.Features/Volo/Abp/Features/FeatureDefinitionManager.cs
Lines 56 to 69 in 3874693
Example of Combined Permissions: