n ABP 10.1.1, a feature defined with .WithProviders(TenantFeatureValueProvider.ProviderName) still appears in the SaaS Edition Features dialog and can be saved for provider E. However, runtime IFeatureChecker appears to filter value providers by FeatureDefinition.AllowedProviders, so edition values for that feature are ignored and only tenant values are considered.
Could you clarify whether AllowedProviders is intended to restrict only runtime feature value providers, or also Feature Management UI/API providers? If it is runtime-only, should the Edition Features dialog hide or disable features whose AllowedProviders does not include E, to avoid saving values that runtime checks will not use?
9 Answer(s)
-
0
AllowedProviders(set viaWithProviders(...)) is intended to restrict which value providers are considered at runtime for that feature. So in your example, if the feature only allowsTenantFeatureValueProvider.ProviderName(“T”), thenIFeatureCheckerwill ignore the edition (“E”) value even if one exists, and only tenant/default can take effect.- In ABP 10.1.1, the Feature Management UI/API (including the SaaS Edition Features dialog) does not automatically hide/disable features based on
FeatureDefinition.AllowedProviders. As a result, it can still let you save an edition-level value that will never be used at runtime for that feature. This is essentially a UX mismatch: the stored value is valid data, but it is not applicable given the feature definition’s allowed providers.
What you should do to avoid the “configurable but ignored” situation:
- Preferred (keep behavior consistent): allow “E” if you want it configurable in Edition Features
context.AddGroup("MyGroup") .AddFeature("MyFeature", defaultValue: "false") .WithProviders( TenantFeatureValueProvider.ProviderName, EditionFeatureValueProvider.ProviderName );- If you intentionally want tenant-only configuration, then you should treat edition configuration as irrelevant and (today) you must enforce that at the UI layer yourself:
- Customize/extend the Feature Management UI so that when editing an Edition you filter out (or disable) any feature whose
AllowedProvidersdoes not include"E".
No verified source available for this specific UI behavior detail in ABP 10.1.1 (the runtime provider filtering is consistent with the feature system’s “Feature Value Providers executed one by one” design, but the “Edition Features dialog should hide/disable based on AllowedProviders” behavior is not documented/guaranteed).
This response was generated by AI. If it didn’t solve your problem, feel free to post a new answer — our support team will jump in to help you soon.
Markdown supported.Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post) -
0
I would consider this a bug, not only a UX mismatch. If AllowedProviders = ["T"], the Edition Features UI should not allow saving an "E" value that runtime feature checking will ignore. The UI/API should respect FeatureDefinition.AllowedProviders for the provider currently being edited.
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 report — you're right, this is a framework-level bug. The Feature Management UI/API should respect
FeatureDefinition.AllowedProvidersto match the runtime behavior inIFeatureChecker. We'll fix it in the next version: https://github.com/abpframework/abp/pull/25462For now, you can work around it on the backend by overriding
FeatureAppService.GetAsyncto filter features whoseAllowedProvidersdoes not include the current providerName. Add this class to yourHttpApi.Hostproject:using Microsoft.Extensions.Options; using Volo.Abp.DependencyInjection; using Volo.Abp.Features; using Volo.Abp.FeatureManagement; [Dependency(ReplaceServices = true)] [ExposeServices(typeof(IFeatureAppService))] public class MyFeatureAppService : FeatureAppService { public MyFeatureAppService( IFeatureManager featureManager, IFeatureDefinitionManager featureDefinitionManager, IOptions<FeatureManagementOptions> options) : base(featureManager, featureDefinitionManager, options) { } public override async Task<GetFeatureListResultDto> GetAsync(string providerName, string providerKey) { var result = await base.GetAsync(providerName, providerKey); foreach (var group in result.Groups) { var filtered = new List<FeatureDto>(); foreach (var feature in group.Features) { var definition = await FeatureDefinitionManager.GetAsync(feature.Name); if (!definition.AllowedProviders.Any() || definition.AllowedProviders.Contains(providerName)) { filtered.Add(feature); } } group.Features = filtered; } return result; } }The Edition Features dialog will then hide features that are restricted to other providers.
Thanks
Markdown supported.Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post) -
0
There are no providers on feature groups, only on individual features. However, after filtering out features that are not valid for the current provider, a group can become empty and still be shown in the UI.
I think that is also an issue: empty feature groups should be hidden after provider-based feature filtering. Just for your information, I have already fixed this on my side within my FeatureAppService replacement.
Markdown supported.Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post) -
0
Hi,
Good catch — the post-process workaround needs to drop empty groups after filtering, otherwise a group whose features are all restricted to other providers stays in the result with an empty list. Here is the updated snippet:
[Dependency(ReplaceServices = true)] [ExposeServices(typeof(IFeatureAppService))] public class MyFeatureAppService : FeatureAppService { public MyFeatureAppService( IFeatureManager featureManager, IFeatureDefinitionManager featureDefinitionManager, IOptions<FeatureManagementOptions> options) : base(featureManager, featureDefinitionManager, options) { } public override async Task<GetFeatureListResultDto> GetAsync(string providerName, string providerKey) { var result = await base.GetAsync(providerName, providerKey); foreach (var group in result.Groups) { var filtered = new List<FeatureDto>(); foreach (var feature in group.Features) { var definition = await FeatureDefinitionManager.GetAsync(feature.Name); if (!definition.AllowedProviders.Any() || definition.AllowedProviders.Contains(providerName)) { filtered.Add(feature); } } group.Features = filtered; } result.Groups = result.Groups.Where(g => g.Features.Any()).ToList(); return result; } }The framework fix in https://github.com/abpframework/abp/pull/25462 filters inline during enumeration, so the existing empty-group check in
FeatureAppService.GetAsyncalready handles this — once you upgrade you can drop the override.Thanks
Markdown supported.Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post)