diff --git a/docs/en/framework/infrastructure/features.md b/docs/en/framework/infrastructure/features.md index 2d135b822b8..e450dc20683 100644 --- a/docs/en/framework/infrastructure/features.md +++ b/docs/en/framework/infrastructure/features.md @@ -395,8 +395,31 @@ There are three pre-defined value providers, executed by the given order: * `TenantFeatureValueProvider` tries to get if the feature value is explicitly set for the **current tenant**. * `EditionFeatureValueProvider` tries to get the feature value for the current edition. Edition Id is obtained from the current principal identity (`ICurrentPrincipalAccessor`) with the claim name `editionid` (a constant defined as`AbpClaimTypes.EditionId`). Editions are not implemented for the [tenant management](../../modules/tenant-management.md) module. You can implement it yourself or consider to use the [SaaS module](https://abp.io/modules/Volo.Saas) of the ABP Commercial. +* `ConfigurationFeatureValueProvider`: Gets the value from the [IConfiguration service](../fundamentals/configuration.md). * `DefaultValueFeatureValueProvider` gets the default value of the feature. +#### Feature Values in the Application Configuration + +The `ConfigurationFeatureValueProvider` reads the feature values from the `IConfiguration` service, which can read values from the `appsettings.json` by default. So, the easiest way to configure feature values is to define them in the `appsettings.json` file. + +For example, you can configure feature values as shown below: + +````json +{ + "Features": { + "MyApp.Reporting": "true", + "MyApp.PdfReporting": "true", + "MyApp.MaxProductCount": "50" + } +} +```` + +Feature values should be configured under the `Features` section as like in this example. + +> `IConfiguration` is an .NET Core service and it can read values not only from the `appsettings.json`, but also from the environment, user secrets... etc. See [Microsoft's documentation](https://docs.microsoft.com/en-us/aspnet/core/fundamentals/configuration/) for more. + +#### Custom Feature Value Providers + You can write your own provider by inheriting the `FeatureValueProvider`. **Example: Enable all features for a user with "SystemAdmin" as a "User_Type" claim value** diff --git a/docs/en/modules/feature-management.md b/docs/en/modules/feature-management.md index 300b232f936..e80098a04df 100644 --- a/docs/en/modules/feature-management.md +++ b/docs/en/modules/feature-management.md @@ -72,9 +72,10 @@ namespace Demo ## Feature Management Providers -Features Management Module is extensible, just like the [features system](../framework/infrastructure/features.md). You can extend it by defining feature management providers. There are 3 pre-built feature management providers registered it the following order: +Features Management Module is extensible, just like the [features system](../framework/infrastructure/features.md). You can extend it by defining feature management providers. There are 4 pre-built feature management providers registered in the following order: * `DefaultValueFeatureManagementProvider`: Gets the value from the default value of the feature definition. It can not set the default value since default values are hard-coded on the feature definition. +* `ConfigurationFeatureManagementProvider`: Gets the value from the [IConfiguration service](../framework/fundamentals/configuration.md). * `EditionFeatureManagementProvider`: Gets or sets the feature values for an edition. Edition is a group of features assigned to tenants. Edition system has not implemented by the Tenant Management module. You can implement it yourself or purchase the ABP [SaaS Module](https://abp.io/modules/Volo.Saas) which implements it and also provides more SaaS features, like subscription and payment. * `TenantFeatureManagementProvider`: Gets or sets the features values for tenants. diff --git a/framework/src/Volo.Abp.Features/Volo/Abp/Features/AbpFeaturesModule.cs b/framework/src/Volo.Abp.Features/Volo/Abp/Features/AbpFeaturesModule.cs index cde88956b59..ab39c1aba72 100644 --- a/framework/src/Volo.Abp.Features/Volo/Abp/Features/AbpFeaturesModule.cs +++ b/framework/src/Volo.Abp.Features/Volo/Abp/Features/AbpFeaturesModule.cs @@ -31,6 +31,7 @@ public override void ConfigureServices(ServiceConfigurationContext context) context.Services.Configure(options => { options.ValueProviders.Add(); + options.ValueProviders.Add(); options.ValueProviders.Add(); options.ValueProviders.Add(); }); diff --git a/framework/src/Volo.Abp.Features/Volo/Abp/Features/ConfigurationFeatureValueProvider.cs b/framework/src/Volo.Abp.Features/Volo/Abp/Features/ConfigurationFeatureValueProvider.cs new file mode 100644 index 00000000000..7309e99b6f6 --- /dev/null +++ b/framework/src/Volo.Abp.Features/Volo/Abp/Features/ConfigurationFeatureValueProvider.cs @@ -0,0 +1,26 @@ +using System.Threading.Tasks; +using Microsoft.Extensions.Configuration; + +namespace Volo.Abp.Features; + +public class ConfigurationFeatureValueProvider : FeatureValueProvider +{ + public const string ConfigurationNamePrefix = "Features:"; + + public const string ProviderName = "C"; + + public override string Name => ProviderName; + + protected IConfiguration Configuration { get; } + + public ConfigurationFeatureValueProvider(IFeatureStore featureStore, IConfiguration configuration) + : base(featureStore) + { + Configuration = configuration; + } + + public override Task GetOrNullAsync(FeatureDefinition feature) + { + return Task.FromResult(Configuration[ConfigurationNamePrefix + feature.Name]); + } +} diff --git a/modules/feature-management/src/Volo.Abp.FeatureManagement.Domain/Volo/Abp/FeatureManagement/AbpFeatureManagementDomainModule.cs b/modules/feature-management/src/Volo.Abp.FeatureManagement.Domain/Volo/Abp/FeatureManagement/AbpFeatureManagementDomainModule.cs index 42ad413f3f2..ebb4c99c14c 100644 --- a/modules/feature-management/src/Volo.Abp.FeatureManagement.Domain/Volo/Abp/FeatureManagement/AbpFeatureManagementDomainModule.cs +++ b/modules/feature-management/src/Volo.Abp.FeatureManagement.Domain/Volo/Abp/FeatureManagement/AbpFeatureManagementDomainModule.cs @@ -29,6 +29,7 @@ public override void ConfigureServices(ServiceConfigurationContext context) Configure(options => { options.Providers.Add(); + options.Providers.Add(); options.Providers.Add(); //TODO: Should be moved to the Tenant Management module diff --git a/modules/feature-management/src/Volo.Abp.FeatureManagement.Domain/Volo/Abp/FeatureManagement/ConfigurationFeatureManagementProvider.cs b/modules/feature-management/src/Volo.Abp.FeatureManagement.Domain/Volo/Abp/FeatureManagement/ConfigurationFeatureManagementProvider.cs new file mode 100644 index 00000000000..ac2b2e3e088 --- /dev/null +++ b/modules/feature-management/src/Volo.Abp.FeatureManagement.Domain/Volo/Abp/FeatureManagement/ConfigurationFeatureManagementProvider.cs @@ -0,0 +1,44 @@ +using System; +using System.Threading.Tasks; +using Microsoft.Extensions.Configuration; +using Volo.Abp.DependencyInjection; +using Volo.Abp.Features; + +namespace Volo.Abp.FeatureManagement; + +public class ConfigurationFeatureManagementProvider : IFeatureManagementProvider, ISingletonDependency +{ + public string Name => ConfigurationFeatureValueProvider.ProviderName; + + protected IConfiguration Configuration { get; } + + public ConfigurationFeatureManagementProvider(IConfiguration configuration) + { + Configuration = configuration; + } + + public virtual bool Compatible(string providerName) + { + return providerName == Name; + } + + public virtual Task HandleContextAsync(string providerName, string providerKey) + { + return Task.FromResult(NullAsyncDisposable.Instance); + } + + public virtual Task GetOrNullAsync(FeatureDefinition feature, string providerKey) + { + return Task.FromResult(Configuration[ConfigurationFeatureValueProvider.ConfigurationNamePrefix + feature.Name]); + } + + public virtual Task SetAsync(FeatureDefinition feature, string value, string providerKey) + { + throw new AbpException($"Can not set a feature value to the application configuration."); + } + + public virtual Task ClearAsync(FeatureDefinition feature, string providerKey) + { + throw new AbpException($"Can not set a feature value to the application configuration."); + } +} diff --git a/modules/feature-management/src/Volo.Abp.FeatureManagement.Domain/Volo/Abp/FeatureManagement/ConfigurationValueFeatureManagerExtensions.cs b/modules/feature-management/src/Volo.Abp.FeatureManagement.Domain/Volo/Abp/FeatureManagement/ConfigurationValueFeatureManagerExtensions.cs new file mode 100644 index 00000000000..726bc4ddbde --- /dev/null +++ b/modules/feature-management/src/Volo.Abp.FeatureManagement.Domain/Volo/Abp/FeatureManagement/ConfigurationValueFeatureManagerExtensions.cs @@ -0,0 +1,19 @@ +using System.Collections.Generic; +using System.Threading.Tasks; +using JetBrains.Annotations; +using Volo.Abp.Features; + +namespace Volo.Abp.FeatureManagement; + +public static class ConfigurationValueFeatureManagerExtensions +{ + public static Task GetOrNullConfigurationAsync(this IFeatureManager featureManager, [NotNull] string name, bool fallback = true) + { + return featureManager.GetOrNullAsync(name, ConfigurationFeatureValueProvider.ProviderName, null, fallback); + } + + public static Task> GetAllConfigurationAsync(this IFeatureManager featureManager, bool fallback = true) + { + return featureManager.GetAllAsync(ConfigurationFeatureValueProvider.ProviderName, null, fallback); + } +}