Browse Source

Add configuration-based feature value provider

pull/24034/head
maliming 7 months ago
parent
commit
f816227cc5
No known key found for this signature in database GPG Key ID: A646B9CB645ECEA4
  1. 23
      docs/en/framework/infrastructure/features.md
  2. 3
      docs/en/modules/feature-management.md
  3. 1
      framework/src/Volo.Abp.Features/Volo/Abp/Features/AbpFeaturesModule.cs
  4. 26
      framework/src/Volo.Abp.Features/Volo/Abp/Features/ConfigurationFeatureValueProvider.cs
  5. 1
      modules/feature-management/src/Volo.Abp.FeatureManagement.Domain/Volo/Abp/FeatureManagement/AbpFeatureManagementDomainModule.cs
  6. 44
      modules/feature-management/src/Volo.Abp.FeatureManagement.Domain/Volo/Abp/FeatureManagement/ConfigurationFeatureManagementProvider.cs
  7. 19
      modules/feature-management/src/Volo.Abp.FeatureManagement.Domain/Volo/Abp/FeatureManagement/ConfigurationValueSettingManagerExtensions.cs

23
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**

3
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 it 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](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.

1
framework/src/Volo.Abp.Features/Volo/Abp/Features/AbpFeaturesModule.cs

@ -31,6 +31,7 @@ public class AbpFeaturesModule : AbpModule
context.Services.Configure<AbpFeatureOptions>(options =>
{
options.ValueProviders.Add<DefaultValueFeatureValueProvider>();
options.ValueProviders.Add<ConfigurationFeatureValueProvider>();
options.ValueProviders.Add<EditionFeatureValueProvider>();
options.ValueProviders.Add<TenantFeatureValueProvider>();
});

26
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<string?> GetOrNullAsync(FeatureDefinition feature)
{
return Task.FromResult(Configuration[ConfigurationNamePrefix + feature.Name]);
}
}

1
modules/feature-management/src/Volo.Abp.FeatureManagement.Domain/Volo/Abp/FeatureManagement/AbpFeatureManagementDomainModule.cs

@ -29,6 +29,7 @@ public class AbpFeatureManagementDomainModule : AbpModule
Configure<FeatureManagementOptions>(options =>
{
options.Providers.Add<DefaultValueFeatureManagementProvider>();
options.Providers.Add<ConfigurationFeatureManagementProvider>();
options.Providers.Add<EditionFeatureManagementProvider>();
//TODO: Should be moved to the Tenant Management module

44
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<IAsyncDisposable> HandleContextAsync(string providerName, string providerKey)
{
return Task.FromResult<IAsyncDisposable>(NullAsyncDisposable.Instance);
}
public virtual Task<string> 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.");
}
}

19
modules/feature-management/src/Volo.Abp.FeatureManagement.Domain/Volo/Abp/FeatureManagement/ConfigurationValueSettingManagerExtensions.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<string> GetOrNullConfigurationAsync(this IFeatureManager featureManager, [NotNull] string name, bool fallback = true)
{
return featureManager.GetOrNullAsync(name, ConfigurationFeatureValueProvider.ProviderName, null, fallback);
}
public static Task<List<FeatureNameValue>> GetAllConfigurationAsync(this IFeatureManager featureManager, bool fallback = true)
{
return featureManager.GetAllAsync(ConfigurationFeatureValueProvider.ProviderName, null, fallback);
}
}
Loading…
Cancel
Save