diff --git a/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/PermissionValueProvider.cs b/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/PermissionValueProvider.cs
index 91351593a5..44d23f718a 100644
--- a/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/PermissionValueProvider.cs
+++ b/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/PermissionValueProvider.cs
@@ -3,7 +3,7 @@ using Volo.Abp.DependencyInjection;
namespace Volo.Abp.Authorization.Permissions
{
- public abstract class PermissionValueProvider : IPermissionValueProvider, ISingletonDependency
+ public abstract class PermissionValueProvider : IPermissionValueProvider, ISingletonDependency //TODO: to transient?
{
public abstract string Name { get; }
diff --git a/framework/src/Volo.Abp.Features/Volo/Abp/Features/DefaultValueSettingValueProvider.cs b/framework/src/Volo.Abp.Features/Volo/Abp/Features/DefaultValueSettingValueProvider.cs
index d60a55586a..275be89af2 100644
--- a/framework/src/Volo.Abp.Features/Volo/Abp/Features/DefaultValueSettingValueProvider.cs
+++ b/framework/src/Volo.Abp.Features/Volo/Abp/Features/DefaultValueSettingValueProvider.cs
@@ -2,7 +2,7 @@
namespace Volo.Abp.Features
{
- public class DefaultValueFeatureValueProvider : FeatureValueProvider
+ public class DefaultValueFeatureValueProvider : FeatureValueProvider //TODO: Directly implement IFeatureValueProvider
{
public const string ProviderName = "Default";
diff --git a/framework/src/Volo.Abp.Features/Volo/Abp/Features/FeatureValueProvider.cs b/framework/src/Volo.Abp.Features/Volo/Abp/Features/FeatureValueProvider.cs
index b93b6903e2..7ef664e6ce 100644
--- a/framework/src/Volo.Abp.Features/Volo/Abp/Features/FeatureValueProvider.cs
+++ b/framework/src/Volo.Abp.Features/Volo/Abp/Features/FeatureValueProvider.cs
@@ -3,7 +3,7 @@ using Volo.Abp.DependencyInjection;
namespace Volo.Abp.Features
{
- public abstract class FeatureValueProvider : IFeatureValueProvider, ISingletonDependency
+ public abstract class FeatureValueProvider : IFeatureValueProvider, ISingletonDependency //TODO: to transient?
{
public abstract string Name { get; }
diff --git a/framework/src/Volo.Abp.Settings/Volo/Abp/Settings/SettingValue.cs b/framework/src/Volo.Abp.Settings/Volo/Abp/Settings/SettingValue.cs
index d7f48081dd..b03a5159c8 100644
--- a/framework/src/Volo.Abp.Settings/Volo/Abp/Settings/SettingValue.cs
+++ b/framework/src/Volo.Abp.Settings/Volo/Abp/Settings/SettingValue.cs
@@ -5,17 +5,11 @@ namespace Volo.Abp.Settings
[Serializable]
public class SettingValue : NameValue
{
- ///
- /// Creates a new .
- ///
public SettingValue()
{
}
- ///
- /// Creates a new .
- ///
public SettingValue(string name, string value)
{
Name = name;
diff --git a/framework/src/Volo.Abp.Settings/Volo/Abp/Settings/SettingValueProvider.cs b/framework/src/Volo.Abp.Settings/Volo/Abp/Settings/SettingValueProvider.cs
index 5173f80540..0a383a3e3b 100644
--- a/framework/src/Volo.Abp.Settings/Volo/Abp/Settings/SettingValueProvider.cs
+++ b/framework/src/Volo.Abp.Settings/Volo/Abp/Settings/SettingValueProvider.cs
@@ -3,7 +3,7 @@ using Volo.Abp.DependencyInjection;
namespace Volo.Abp.Settings
{
- public abstract class SettingValueProvider : ISettingValueProvider, ISingletonDependency
+ public abstract class SettingValueProvider : ISettingValueProvider, ISingletonDependency //TODO: to transient?
{
public abstract string Name { get; }
diff --git a/modules/feature-management/src/Volo.Abp.FeatureManagement.Application/Volo/Abp/FeatureManagement/AbpFeatureManagementApplicationModule.cs b/modules/feature-management/src/Volo.Abp.FeatureManagement.Application/Volo/Abp/FeatureManagement/AbpFeatureManagementApplicationModule.cs
index 8116e436b0..62ee615a10 100644
--- a/modules/feature-management/src/Volo.Abp.FeatureManagement.Application/Volo/Abp/FeatureManagement/AbpFeatureManagementApplicationModule.cs
+++ b/modules/feature-management/src/Volo.Abp.FeatureManagement.Application/Volo/Abp/FeatureManagement/AbpFeatureManagementApplicationModule.cs
@@ -1,6 +1,5 @@
using Volo.Abp.AutoMapper;
using Volo.Abp.Modularity;
-using Volo.Abp.Settings;
namespace Volo.Abp.FeatureManagement
{
@@ -17,11 +16,6 @@ namespace Volo.Abp.FeatureManagement
{
options.AddProfile(validate: true);
});
-
- Configure(options =>
- {
- options.DefinitionProviders.Add();
- });
}
}
}
diff --git a/modules/feature-management/src/Volo.Abp.FeatureManagement.Application/Volo/Abp/FeatureManagement/FeatureManagementSettingDefinitionProvider.cs b/modules/feature-management/src/Volo.Abp.FeatureManagement.Application/Volo/Abp/FeatureManagement/FeatureManagementSettingDefinitionProvider.cs
deleted file mode 100644
index 9a064e6409..0000000000
--- a/modules/feature-management/src/Volo.Abp.FeatureManagement.Application/Volo/Abp/FeatureManagement/FeatureManagementSettingDefinitionProvider.cs
+++ /dev/null
@@ -1,14 +0,0 @@
-using Volo.Abp.Settings;
-
-namespace Volo.Abp.FeatureManagement
-{
- public class FeatureManagementSettingDefinitionProvider : SettingDefinitionProvider
- {
- public override void Define(ISettingDefinitionContext context)
- {
- /* Define module settings here.
- * Use names from FeatureManagementSettings class.
- */
- }
- }
-}
\ No newline at end of file
diff --git a/modules/feature-management/src/Volo.Abp.FeatureManagement.Application/Volo/Abp/FeatureManagement/FeatureManagementSettings.cs b/modules/feature-management/src/Volo.Abp.FeatureManagement.Application/Volo/Abp/FeatureManagement/FeatureManagementSettings.cs
deleted file mode 100644
index ed634b9bca..0000000000
--- a/modules/feature-management/src/Volo.Abp.FeatureManagement.Application/Volo/Abp/FeatureManagement/FeatureManagementSettings.cs
+++ /dev/null
@@ -1,11 +0,0 @@
-namespace Volo.Abp.FeatureManagement
-{
- public static class FeatureManagementSettings
- {
- public const string GroupName = "AbpFeatureManagement";
-
- /* Add constants for setting names. Example:
- * public const string MySettingName = GroupName + ".MySettingName";
- */
- }
-}
\ No newline at end of file
diff --git a/modules/feature-management/src/Volo.Abp.FeatureManagement.Domain/Volo.Abp.FeatureManagement.Domain.csproj b/modules/feature-management/src/Volo.Abp.FeatureManagement.Domain/Volo.Abp.FeatureManagement.Domain.csproj
index 5df85ab931..9a3ebac4f3 100644
--- a/modules/feature-management/src/Volo.Abp.FeatureManagement.Domain/Volo.Abp.FeatureManagement.Domain.csproj
+++ b/modules/feature-management/src/Volo.Abp.FeatureManagement.Domain/Volo.Abp.FeatureManagement.Domain.csproj
@@ -10,6 +10,7 @@
+
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 82492b1fd7..db6dabf9c6 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
@@ -1,4 +1,5 @@
-using Volo.Abp.FeatureManagement.Localization;
+using Volo.Abp.Caching;
+using Volo.Abp.FeatureManagement.Localization;
using Volo.Abp.Features;
using Volo.Abp.Localization;
using Volo.Abp.Localization.ExceptionHandling;
@@ -9,12 +10,19 @@ namespace Volo.Abp.FeatureManagement
{
[DependsOn(
typeof(AbpFeatureManagementDomainSharedModule),
- typeof(AbpFeaturesModule)
+ typeof(AbpFeaturesModule),
+ typeof(AbpCachingModule)
)]
public class AbpFeatureManagementDomainModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
+ Configure(options =>
+ {
+ options.Providers.Add();
+ options.Providers.Add();
+ });
+
Configure(options =>
{
options.FileSets.AddEmbedded();
diff --git a/modules/feature-management/src/Volo.Abp.FeatureManagement.Domain/Volo/Abp/FeatureManagement/DefaultValueFeatureManagementProvider.cs b/modules/feature-management/src/Volo.Abp.FeatureManagement.Domain/Volo/Abp/FeatureManagement/DefaultValueFeatureManagementProvider.cs
new file mode 100644
index 0000000000..aa20684d3a
--- /dev/null
+++ b/modules/feature-management/src/Volo.Abp.FeatureManagement.Domain/Volo/Abp/FeatureManagement/DefaultValueFeatureManagementProvider.cs
@@ -0,0 +1,26 @@
+using System.Threading.Tasks;
+using Volo.Abp.DependencyInjection;
+using Volo.Abp.Features;
+
+namespace Volo.Abp.FeatureManagement
+{
+ public class DefaultValueFeatureManagementProvider : IFeatureManagementProvider, ISingletonDependency
+ {
+ public string Name => DefaultValueFeatureValueProvider.ProviderName;
+
+ public Task GetOrNullAsync(FeatureDefinition feature, string providerKey)
+ {
+ return Task.FromResult(feature.DefaultValue);
+ }
+
+ public Task SetAsync(FeatureDefinition feature, string value, string providerKey)
+ {
+ throw new AbpException($"Can not set default value of a feature. It is only possible while defining the feature in a {typeof(IFeatureDefinitionProvider)} implementation.");
+ }
+
+ public Task ClearAsync(FeatureDefinition feature, string providerKey)
+ {
+ throw new AbpException($"Can not clear default value of a feature. It is only possible while defining the feature in a {typeof(IFeatureDefinitionProvider)} implementation.");
+ }
+ }
+}
\ No newline at end of file
diff --git a/modules/feature-management/src/Volo.Abp.FeatureManagement.Domain/Volo/Abp/FeatureManagement/DefaultValueFeatureManagerExtensions.cs b/modules/feature-management/src/Volo.Abp.FeatureManagement.Domain/Volo/Abp/FeatureManagement/DefaultValueFeatureManagerExtensions.cs
new file mode 100644
index 0000000000..c000b66df3
--- /dev/null
+++ b/modules/feature-management/src/Volo.Abp.FeatureManagement.Domain/Volo/Abp/FeatureManagement/DefaultValueFeatureManagerExtensions.cs
@@ -0,0 +1,20 @@
+using System.Collections.Generic;
+using System.Threading.Tasks;
+using JetBrains.Annotations;
+using Volo.Abp.Features;
+
+namespace Volo.Abp.FeatureManagement
+{
+ public static class DefaultValueFeatureManagerExtensions
+ {
+ public static Task GetOrNullDefaultAsync(this IFeatureManager featureManager, [NotNull] string name, bool fallback = true)
+ {
+ return featureManager.GetOrNullAsync(name, DefaultValueFeatureValueProvider.ProviderName, null, fallback);
+ }
+
+ public static Task> GetAllDefaultAsync(this IFeatureManager featureManager, bool fallback = true)
+ {
+ return featureManager.GetAllAsync(DefaultValueFeatureValueProvider.ProviderName, null, fallback);
+ }
+ }
+}
\ No newline at end of file
diff --git a/modules/feature-management/src/Volo.Abp.FeatureManagement.Domain/Volo/Abp/FeatureManagement/FeatureManagementOptions.cs b/modules/feature-management/src/Volo.Abp.FeatureManagement.Domain/Volo/Abp/FeatureManagement/FeatureManagementOptions.cs
new file mode 100644
index 0000000000..0599c3e4c5
--- /dev/null
+++ b/modules/feature-management/src/Volo.Abp.FeatureManagement.Domain/Volo/Abp/FeatureManagement/FeatureManagementOptions.cs
@@ -0,0 +1,14 @@
+using Volo.Abp.Collections;
+
+namespace Volo.Abp.FeatureManagement
+{
+ public class FeatureManagementOptions
+ {
+ public ITypeList Providers { get; }
+
+ public FeatureManagementOptions()
+ {
+ Providers = new TypeList();
+ }
+ }
+}
\ No newline at end of file
diff --git a/modules/feature-management/src/Volo.Abp.FeatureManagement.Domain/Volo/Abp/FeatureManagement/FeatureManagementProvider.cs b/modules/feature-management/src/Volo.Abp.FeatureManagement.Domain/Volo/Abp/FeatureManagement/FeatureManagementProvider.cs
new file mode 100644
index 0000000000..1d0c59773b
--- /dev/null
+++ b/modules/feature-management/src/Volo.Abp.FeatureManagement.Domain/Volo/Abp/FeatureManagement/FeatureManagementProvider.cs
@@ -0,0 +1,37 @@
+using System.Threading.Tasks;
+using Volo.Abp.Features;
+
+namespace Volo.Abp.FeatureManagement
+{
+ public abstract class FeatureManagementProvider : IFeatureManagementProvider
+ {
+ public abstract string Name { get; }
+
+ protected IFeatureManagementStore Store { get; }
+
+ protected FeatureManagementProvider(IFeatureManagementStore store)
+ {
+ Store = store;
+ }
+
+ public async Task GetOrNullAsync(FeatureDefinition feature, string providerKey)
+ {
+ return await Store.GetOrNullAsync(feature.Name, Name, NormalizeProviderKey(providerKey));
+ }
+
+ public virtual async Task SetAsync(FeatureDefinition feature, string value, string providerKey)
+ {
+ await Store.SetAsync(feature.Name, value, Name, NormalizeProviderKey(providerKey));
+ }
+
+ public virtual async Task ClearAsync(FeatureDefinition feature, string providerKey)
+ {
+ await Store.DeleteAsync(feature.Name, Name, NormalizeProviderKey(providerKey));
+ }
+
+ protected virtual string NormalizeProviderKey(string providerKey)
+ {
+ return providerKey;
+ }
+ }
+}
\ No newline at end of file
diff --git a/modules/feature-management/src/Volo.Abp.FeatureManagement.Domain/Volo/Abp/FeatureManagement/FeatureManagementStore.cs b/modules/feature-management/src/Volo.Abp.FeatureManagement.Domain/Volo/Abp/FeatureManagement/FeatureManagementStore.cs
new file mode 100644
index 0000000000..94c4d48067
--- /dev/null
+++ b/modules/feature-management/src/Volo.Abp.FeatureManagement.Domain/Volo/Abp/FeatureManagement/FeatureManagementStore.cs
@@ -0,0 +1,81 @@
+using System.Threading.Tasks;
+using Volo.Abp.Caching;
+using Volo.Abp.DependencyInjection;
+using Volo.Abp.Guids;
+
+namespace Volo.Abp.FeatureManagement
+{
+ public class FeatureManagementStore : IFeatureManagementStore, ITransientDependency
+ {
+ protected IDistributedCache Cache { get; }
+ protected IFeatureValueRepository FeatureValueRepository { get; }
+ protected IGuidGenerator GuidGenerator { get; }
+
+ public FeatureManagementStore(
+ IFeatureValueRepository featureValueRepository,
+ IGuidGenerator guidGenerator,
+ IDistributedCache cache)
+ {
+ FeatureValueRepository = featureValueRepository;
+ GuidGenerator = guidGenerator;
+ Cache = cache;
+ }
+
+ public async Task GetOrNullAsync(string name, string providerName, string providerKey)
+ {
+ var cacheItem = await GetCacheItemAsync(name, providerName, providerKey);
+ return cacheItem.Value;
+ }
+
+ public async Task SetAsync(string name, string value, string providerName, string providerKey)
+ {
+ var featureValue = await FeatureValueRepository.FindAsync(name, providerName, providerKey);
+ if (featureValue == null)
+ {
+ featureValue = new FeatureValue(GuidGenerator.Create(), name, value, providerName, providerKey);
+ await FeatureValueRepository.InsertAsync(featureValue);
+ }
+ else
+ {
+ featureValue.Value = value;
+ await FeatureValueRepository.UpdateAsync(featureValue);
+ }
+ }
+
+ public async Task DeleteAsync(string name, string providerName, string providerKey)
+ {
+ var featureValue = await FeatureValueRepository.FindAsync(name, providerName, providerKey);
+ if (featureValue != null)
+ {
+ await FeatureValueRepository.DeleteAsync(featureValue);
+ }
+ }
+
+ protected virtual async Task GetCacheItemAsync(string name, string providerName, string providerKey)
+ {
+ var cacheKey = CalculateCacheKey(name, providerName, providerKey);
+ var cacheItem = await Cache.GetAsync(cacheKey);
+
+ if (cacheItem != null)
+ {
+ return cacheItem;
+ }
+
+ var featureValue = await FeatureValueRepository.FindAsync(name, providerName, providerKey);
+
+ cacheItem = new FeatureValueCacheItem(featureValue?.Value);
+
+ await Cache.SetAsync(
+ cacheKey,
+ cacheItem
+ );
+
+ return cacheItem;
+ }
+
+ protected virtual string CalculateCacheKey(string name, string providerName, string providerKey)
+ {
+ return FeatureValueCacheItem.CalculateCacheKey(name, providerName, providerKey);
+ }
+ }
+}
\ No newline at end of file
diff --git a/modules/feature-management/src/Volo.Abp.FeatureManagement.Domain/Volo/Abp/FeatureManagement/FeatureManager.cs b/modules/feature-management/src/Volo.Abp.FeatureManagement.Domain/Volo/Abp/FeatureManagement/FeatureManager.cs
new file mode 100644
index 0000000000..06ca345bf6
--- /dev/null
+++ b/modules/feature-management/src/Volo.Abp.FeatureManagement.Domain/Volo/Abp/FeatureManagement/FeatureManager.cs
@@ -0,0 +1,186 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Options;
+using Volo.Abp.DependencyInjection;
+using Volo.Abp.Features;
+
+namespace Volo.Abp.FeatureManagement
+{
+ public class FeatureManager : IFeatureManager, ISingletonDependency
+ {
+ protected IFeatureDefinitionManager FeatureDefinitionManager { get; }
+ protected List Providers => _lazyProviders.Value;
+ protected FeatureManagementOptions Options { get; }
+
+ private readonly Lazy> _lazyProviders;
+
+ public FeatureManager(
+ IOptions options,
+ IServiceProvider serviceProvider,
+ IFeatureDefinitionManager featureDefinitionManager)
+ {
+ FeatureDefinitionManager = featureDefinitionManager;
+ Options = options.Value;
+
+ //TODO: Instead, use IHybridServiceScopeFactory and create a scope..?
+
+ _lazyProviders = new Lazy>(
+ () => Options
+ .Providers
+ .Select(c => serviceProvider.GetRequiredService(c) as IFeatureManagementProvider)
+ .ToList(),
+ true
+ );
+ }
+
+ public virtual Task GetOrNullAsync(
+ string name,
+ string providerName,
+ string providerKey,
+ bool fallback = true)
+ {
+ Check.NotNull(name, nameof(name));
+ Check.NotNull(providerName, nameof(providerName));
+
+ return GetOrNullInternalAsync(name, providerName, providerKey, fallback);
+ }
+
+ public virtual async Task> GetAllAsync(
+ string providerName,
+ string providerKey,
+ bool fallback = true)
+ {
+ Check.NotNull(providerName, nameof(providerName));
+
+ var featureDefinitions = FeatureDefinitionManager.GetAll();
+ var providers = Enumerable.Reverse(Providers)
+ .SkipWhile(c => c.Name != providerName);
+
+ if (!fallback)
+ {
+ providers = providers.TakeWhile(c => c.Name == providerName);
+ }
+
+ var providerList = providers.Reverse().ToList();
+
+ if (!providerList.Any())
+ {
+ return new List();
+ }
+
+ var featureValues = new Dictionary();
+
+ foreach (var feature in featureDefinitions)
+ {
+ string value = null;
+
+ foreach (var provider in providerList)
+ {
+ var providerValue = await provider.GetOrNullAsync(
+ feature,
+ provider.Name == providerName ? providerKey : null
+ );
+
+ if (providerValue != null)
+ {
+ value = providerValue;
+ }
+ }
+
+ if (value != null)
+ {
+ featureValues[feature.Name] = new FeatureNameValue(feature.Name, value);
+ }
+ }
+
+ return featureValues.Values.ToList();
+ }
+
+ public virtual async Task SetAsync(
+ string name,
+ string value,
+ string providerName,
+ string providerKey,
+ bool forceToSet = false)
+ {
+ Check.NotNull(name, nameof(name));
+ Check.NotNull(providerName, nameof(providerName));
+
+ var feature = FeatureDefinitionManager.Get(name);
+
+ var providers = Enumerable
+ .Reverse(Providers)
+ .SkipWhile(p => p.Name != providerName)
+ .ToList();
+
+ if (!providers.Any())
+ {
+ return;
+ }
+
+ if (providers.Count > 1 && !forceToSet && value != null)
+ {
+ var fallbackValue = await GetOrNullInternalAsync(name, providers[1].Name, null);
+ if (fallbackValue == value)
+ {
+ //Clear the value if it's same as it's fallback value
+ value = null;
+ }
+ }
+
+ providers = providers
+ .TakeWhile(p => p.Name == providerName)
+ .ToList(); //Getting list for case of there are more than one provider with same providerName
+
+ if (value == null)
+ {
+ foreach (var provider in providers)
+ {
+ await provider.ClearAsync(feature, providerKey);
+ }
+ }
+ else
+ {
+ foreach (var provider in providers)
+ {
+ await provider.SetAsync(feature, value, providerKey);
+ }
+ }
+ }
+
+ protected virtual async Task GetOrNullInternalAsync(
+ string name,
+ string providerName,
+ string providerKey,
+ bool fallback = true) //TODO: Fallback is not used
+ {
+ var feature = FeatureDefinitionManager.Get(name);
+ var providers = Enumerable
+ .Reverse(Providers);
+
+ if (providerName != null)
+ {
+ providers = providers.SkipWhile(c => c.Name != providerName);
+ }
+
+ string value = null;
+ foreach (var provider in providers)
+ {
+ value = await provider.GetOrNullAsync(
+ feature,
+ provider.Name == providerName ? providerKey : null
+ );
+
+ if (value != null)
+ {
+ break;
+ }
+ }
+
+ return value;
+ }
+ }
+}
\ No newline at end of file
diff --git a/modules/feature-management/src/Volo.Abp.FeatureManagement.Domain/Volo/Abp/FeatureManagement/FeatureNameValue.cs b/modules/feature-management/src/Volo.Abp.FeatureManagement.Domain/Volo/Abp/FeatureManagement/FeatureNameValue.cs
new file mode 100644
index 0000000000..c7b64d9a1c
--- /dev/null
+++ b/modules/feature-management/src/Volo.Abp.FeatureManagement.Domain/Volo/Abp/FeatureManagement/FeatureNameValue.cs
@@ -0,0 +1,19 @@
+using System;
+
+namespace Volo.Abp.FeatureManagement
+{
+ [Serializable]
+ public class FeatureNameValue : NameValue
+ {
+ public FeatureNameValue()
+ {
+
+ }
+
+ public FeatureNameValue(string name, string value)
+ {
+ Name = name;
+ Value = value;
+ }
+ }
+}
\ No newline at end of file
diff --git a/modules/feature-management/src/Volo.Abp.FeatureManagement.Domain/Volo/Abp/FeatureManagement/FeatureStore.cs b/modules/feature-management/src/Volo.Abp.FeatureManagement.Domain/Volo/Abp/FeatureManagement/FeatureStore.cs
index dbe851008c..23d5ea7d50 100644
--- a/modules/feature-management/src/Volo.Abp.FeatureManagement.Domain/Volo/Abp/FeatureManagement/FeatureStore.cs
+++ b/modules/feature-management/src/Volo.Abp.FeatureManagement.Domain/Volo/Abp/FeatureManagement/FeatureStore.cs
@@ -4,24 +4,21 @@ using Volo.Abp.Features;
namespace Volo.Abp.FeatureManagement
{
- //TODO: Implement caching
-
public class FeatureStore : IFeatureStore, ITransientDependency
{
- protected IFeatureValueRepository FeatureValueRepository { get; }
+ protected IFeatureManagementStore FeatureManagementStore { get; }
- public FeatureStore(IFeatureValueRepository featureValueRepository)
+ public FeatureStore(IFeatureManagementStore featureManagementStore)
{
- FeatureValueRepository = featureValueRepository;
+ FeatureManagementStore = featureManagementStore;
}
- public async Task GetOrNullAsync(
- string name,
- string providerName,
+ public Task GetOrNullAsync(
+ string name,
+ string providerName,
string providerKey)
{
- var featureValue = await FeatureValueRepository.FindAsync(name, providerName, providerKey);
- return featureValue?.Value;
+ return FeatureManagementStore.GetOrNullAsync(name, providerName, providerKey);
}
}
}
diff --git a/modules/feature-management/src/Volo.Abp.FeatureManagement.Domain/Volo/Abp/FeatureManagement/FeatureValueCacheItem.cs b/modules/feature-management/src/Volo.Abp.FeatureManagement.Domain/Volo/Abp/FeatureManagement/FeatureValueCacheItem.cs
new file mode 100644
index 0000000000..765e6c9b32
--- /dev/null
+++ b/modules/feature-management/src/Volo.Abp.FeatureManagement.Domain/Volo/Abp/FeatureManagement/FeatureValueCacheItem.cs
@@ -0,0 +1,25 @@
+using System;
+
+namespace Volo.Abp.FeatureManagement
+{
+ [Serializable]
+ public class FeatureValueCacheItem
+ {
+ public string Value { get; set; }
+
+ public FeatureValueCacheItem()
+ {
+
+ }
+
+ public FeatureValueCacheItem(string value)
+ {
+ Value = value;
+ }
+
+ public static string CalculateCacheKey(string name, string providerName, string providerKey)
+ {
+ return "pn:" + providerName + ",pk:" + providerKey + ",n:" + name;
+ }
+ }
+}
\ No newline at end of file
diff --git a/modules/feature-management/src/Volo.Abp.FeatureManagement.Domain/Volo/Abp/FeatureManagement/FeatureValueCacheItemInvalidator.cs b/modules/feature-management/src/Volo.Abp.FeatureManagement.Domain/Volo/Abp/FeatureManagement/FeatureValueCacheItemInvalidator.cs
new file mode 100644
index 0000000000..63e207b1e7
--- /dev/null
+++ b/modules/feature-management/src/Volo.Abp.FeatureManagement.Domain/Volo/Abp/FeatureManagement/FeatureValueCacheItemInvalidator.cs
@@ -0,0 +1,36 @@
+using System.Threading.Tasks;
+using Volo.Abp.Caching;
+using Volo.Abp.DependencyInjection;
+using Volo.Abp.Domain.Entities.Events;
+using Volo.Abp.EventBus;
+
+namespace Volo.Abp.FeatureManagement
+{
+ public class FeatureValueCacheItemInvalidator :
+ ILocalEventHandler>,
+ ITransientDependency
+ {
+ protected IDistributedCache Cache { get; }
+
+ public FeatureValueCacheItemInvalidator(IDistributedCache cache)
+ {
+ Cache = cache;
+ }
+
+ public virtual async Task HandleEventAsync(EntityChangedEventData eventData)
+ {
+ var cacheKey = CalculateCacheKey(
+ eventData.Entity.Name,
+ eventData.Entity.ProviderName,
+ eventData.Entity.ProviderKey
+ );
+
+ await Cache.RemoveAsync(cacheKey);
+ }
+
+ protected virtual string CalculateCacheKey(string name, string providerName, string providerKey)
+ {
+ return FeatureValueCacheItem.CalculateCacheKey(name, providerName, providerKey);
+ }
+ }
+}
diff --git a/modules/feature-management/src/Volo.Abp.FeatureManagement.Domain/Volo/Abp/FeatureManagement/IFeatureManagementProvider.cs b/modules/feature-management/src/Volo.Abp.FeatureManagement.Domain/Volo/Abp/FeatureManagement/IFeatureManagementProvider.cs
new file mode 100644
index 0000000000..204ed16235
--- /dev/null
+++ b/modules/feature-management/src/Volo.Abp.FeatureManagement.Domain/Volo/Abp/FeatureManagement/IFeatureManagementProvider.cs
@@ -0,0 +1,17 @@
+using System.Threading.Tasks;
+using JetBrains.Annotations;
+using Volo.Abp.Features;
+
+namespace Volo.Abp.FeatureManagement
+{
+ public interface IFeatureManagementProvider
+ {
+ string Name { get; }
+
+ Task GetOrNullAsync([NotNull] FeatureDefinition feature, [CanBeNull] string providerKey);
+
+ Task SetAsync([NotNull] FeatureDefinition feature, [NotNull] string value, [CanBeNull] string providerKey);
+
+ Task ClearAsync([NotNull] FeatureDefinition feature, [CanBeNull] string providerKey);
+ }
+}
\ No newline at end of file
diff --git a/modules/feature-management/src/Volo.Abp.FeatureManagement.Domain/Volo/Abp/FeatureManagement/IFeatureManagementStore.cs b/modules/feature-management/src/Volo.Abp.FeatureManagement.Domain/Volo/Abp/FeatureManagement/IFeatureManagementStore.cs
new file mode 100644
index 0000000000..d32ff19d84
--- /dev/null
+++ b/modules/feature-management/src/Volo.Abp.FeatureManagement.Domain/Volo/Abp/FeatureManagement/IFeatureManagementStore.cs
@@ -0,0 +1,13 @@
+using System.Threading.Tasks;
+
+namespace Volo.Abp.FeatureManagement
+{
+ public interface IFeatureManagementStore
+ {
+ Task GetOrNullAsync(string name, string providerName, string providerKey);
+
+ Task SetAsync(string name, string value, string providerName, string providerKey);
+
+ Task DeleteAsync(string name, string providerName, string providerKey);
+ }
+}
\ No newline at end of file
diff --git a/modules/feature-management/src/Volo.Abp.FeatureManagement.Domain/Volo/Abp/FeatureManagement/IFeatureManager.cs b/modules/feature-management/src/Volo.Abp.FeatureManagement.Domain/Volo/Abp/FeatureManagement/IFeatureManager.cs
new file mode 100644
index 0000000000..df19cd332b
--- /dev/null
+++ b/modules/feature-management/src/Volo.Abp.FeatureManagement.Domain/Volo/Abp/FeatureManagement/IFeatureManager.cs
@@ -0,0 +1,15 @@
+using System.Collections.Generic;
+using System.Threading.Tasks;
+using JetBrains.Annotations;
+
+namespace Volo.Abp.FeatureManagement
+{
+ public interface IFeatureManager
+ {
+ Task GetOrNullAsync([NotNull]string name, [NotNull] string providerName, [CanBeNull] string providerKey, bool fallback = true);
+
+ Task> GetAllAsync([NotNull] string providerName, [CanBeNull] string providerKey, bool fallback = true);
+
+ Task SetAsync([NotNull] string name, [CanBeNull] string value, [NotNull] string providerName, [CanBeNull] string providerKey, bool forceToSet = false);
+ }
+}
\ No newline at end of file
diff --git a/modules/feature-management/src/Volo.Abp.FeatureManagement.Domain/Volo/Abp/FeatureManagement/TenantFeatureManagementProvider.cs b/modules/feature-management/src/Volo.Abp.FeatureManagement.Domain/Volo/Abp/FeatureManagement/TenantFeatureManagementProvider.cs
new file mode 100644
index 0000000000..928d794671
--- /dev/null
+++ b/modules/feature-management/src/Volo.Abp.FeatureManagement.Domain/Volo/Abp/FeatureManagement/TenantFeatureManagementProvider.cs
@@ -0,0 +1,14 @@
+using Volo.Abp.Features;
+
+namespace Volo.Abp.FeatureManagement
+{
+ public class TenantFeatureManagementProvider : FeatureManagementProvider
+ {
+ public override string Name => TenantFeatureValueProvider.ProviderName;
+
+ public TenantFeatureManagementProvider(IFeatureManagementStore store)
+ : base(store)
+ {
+ }
+ }
+}
\ No newline at end of file
diff --git a/modules/feature-management/src/Volo.Abp.FeatureManagement.Domain/Volo/Abp/FeatureManagement/TenantFeatureManagerExtensions.cs b/modules/feature-management/src/Volo.Abp.FeatureManagement.Domain/Volo/Abp/FeatureManagement/TenantFeatureManagerExtensions.cs
new file mode 100644
index 0000000000..6a26def9a6
--- /dev/null
+++ b/modules/feature-management/src/Volo.Abp.FeatureManagement.Domain/Volo/Abp/FeatureManagement/TenantFeatureManagerExtensions.cs
@@ -0,0 +1,41 @@
+using System;
+using System.Collections.Generic;
+using System.Threading.Tasks;
+using JetBrains.Annotations;
+using Volo.Abp.Features;
+
+namespace Volo.Abp.FeatureManagement
+{
+ public static class TenantFeatureManagerExtensions
+ {
+ public static Task GetOrNullForTenantAsync(this IFeatureManager featureManager, [NotNull] string name, Guid tenantId, bool fallback = true)
+ {
+ return featureManager.GetOrNullAsync(name, TenantFeatureValueProvider.ProviderName, tenantId.ToString(), fallback);
+ }
+
+ public static Task GetOrNullForCurrentTenantAsync(this IFeatureManager featureManager, [NotNull] string name, bool fallback = true)
+ {
+ return featureManager.GetOrNullAsync(name, TenantFeatureValueProvider.ProviderName, null, fallback);
+ }
+
+ public static Task> GetAllForTenantAsync(this IFeatureManager featureManager, Guid tenantId, bool fallback = true)
+ {
+ return featureManager.GetAllAsync(TenantFeatureValueProvider.ProviderName, tenantId.ToString(), fallback);
+ }
+
+ public static Task> GetAllForCurrentTenantAsync(this IFeatureManager featureManager, bool fallback = true)
+ {
+ return featureManager.GetAllAsync(TenantFeatureValueProvider.ProviderName, null, fallback);
+ }
+
+ public static Task SetForTenantAsync(this IFeatureManager featureManager, Guid tenantId, [NotNull] string name, [CanBeNull] string value, bool forceToSet = false)
+ {
+ return featureManager.SetAsync(name, value, TenantFeatureValueProvider.ProviderName, tenantId.ToString(), forceToSet);
+ }
+
+ public static Task SetForCurrentTenantAsync(this IFeatureManager featureManager, [NotNull] string name, [CanBeNull] string value, bool forceToSet = false)
+ {
+ return featureManager.SetAsync(name, value, TenantFeatureValueProvider.ProviderName, null, forceToSet);
+ }
+ }
+}
diff --git a/modules/setting-management/src/Volo.Abp.SettingManagement.Domain/Volo/Abp/SettingManagement/Setting.cs b/modules/setting-management/src/Volo.Abp.SettingManagement.Domain/Volo/Abp/SettingManagement/Setting.cs
index 78e7b3e70c..49c2769237 100644
--- a/modules/setting-management/src/Volo.Abp.SettingManagement.Domain/Volo/Abp/SettingManagement/Setting.cs
+++ b/modules/setting-management/src/Volo.Abp.SettingManagement.Domain/Volo/Abp/SettingManagement/Setting.cs
@@ -4,8 +4,7 @@ using Volo.Abp.Domain.Entities;
namespace Volo.Abp.SettingManagement
{
- //TODO: Convert to AggregateRoot
- public class Setting : Entity
+ public class Setting : Entity, IAggregateRoot
{
[NotNull]
public virtual string Name { get; protected set; }
diff --git a/modules/setting-management/src/Volo.Abp.SettingManagement.Domain/Volo/Abp/SettingManagement/SettingManagementProvider.cs b/modules/setting-management/src/Volo.Abp.SettingManagement.Domain/Volo/Abp/SettingManagement/SettingManagementProvider.cs
index d350cc28d7..2859b2e7f4 100644
--- a/modules/setting-management/src/Volo.Abp.SettingManagement.Domain/Volo/Abp/SettingManagement/SettingManagementProvider.cs
+++ b/modules/setting-management/src/Volo.Abp.SettingManagement.Domain/Volo/Abp/SettingManagement/SettingManagementProvider.cs
@@ -7,6 +7,7 @@ namespace Volo.Abp.SettingManagement
{
public abstract string Name { get; }
+ //TODO: Rename to Store
protected ISettingManagementStore SettingManagementStore { get; }
protected SettingManagementProvider(ISettingManagementStore settingManagementStore)