Open Source Web Application Framework for ASP.NET Core
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

248 lines
8.1 KiB

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Xml.Linq;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Localization;
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<IFeatureManagementProvider> Providers => _lazyProviders.Value;
protected FeatureManagementOptions Options { get; }
protected IStringLocalizerFactory StringLocalizerFactory { get; }
private readonly Lazy<List<IFeatureManagementProvider>> _lazyProviders;
public FeatureManager(
IOptions<FeatureManagementOptions> options,
IServiceProvider serviceProvider,
IFeatureDefinitionManager featureDefinitionManager,
IStringLocalizerFactory stringLocalizerFactory)
{
FeatureDefinitionManager = featureDefinitionManager;
StringLocalizerFactory = stringLocalizerFactory;
Options = options.Value;
//TODO: Instead, use IServiceScopeFactory and create a scope..?
_lazyProviders = new Lazy<List<IFeatureManagementProvider>>(
() => Options
.Providers
.Select(c => serviceProvider.GetRequiredService(c) as IFeatureManagementProvider)
.ToList(),
true
);
}
public virtual async Task<string> GetOrNullAsync(
string name,
string providerName,
string providerKey,
bool fallback = true)
{
Check.NotNull(name, nameof(name));
Check.NotNull(providerName, nameof(providerName));
return (await GetOrNullInternalAsync(name, providerName, providerKey, fallback)).Value;
}
public virtual async Task<List<FeatureNameValue>> GetAllAsync(
string providerName,
string providerKey,
bool fallback = true)
{
return (await GetAllWithProviderAsync(providerName, providerKey, fallback))
.Select(x => new FeatureNameValue(x.Name, x.Value)).ToList();
}
public async Task<FeatureNameValueWithGrantedProvider> GetOrNullWithProviderAsync(string name,
string providerName, string providerKey, bool fallback = true)
{
Check.NotNull(name, nameof(name));
Check.NotNull(providerName, nameof(providerName));
return await GetOrNullInternalAsync(name, providerName, providerKey, fallback);
}
public async Task<List<FeatureNameValueWithGrantedProvider>> GetAllWithProviderAsync(string providerName,
string providerKey, bool fallback = true)
{
Check.NotNull(providerName, nameof(providerName));
var featureDefinitions = await FeatureDefinitionManager.GetAllAsync();
var providers = Enumerable.Reverse(Providers).SkipWhile(c => c.Name != providerName);
if (!fallback)
{
providers = providers.TakeWhile(c => c.Name == providerName);
}
var providerList = providers.ToList();
if (!providerList.Any())
{
return new List<FeatureNameValueWithGrantedProvider>();
}
var featureValues = new Dictionary<string, FeatureNameValueWithGrantedProvider>();
foreach (var feature in featureDefinitions)
{
var featureNameValueWithGrantedProvider = new FeatureNameValueWithGrantedProvider(feature.Name, null);
foreach (var provider in providerList)
{
string pk = null;
if (provider.Compatible(providerName))
{
pk = providerKey;
}
var value = await provider.GetOrNullAsync(feature, pk);
if (value != null)
{
featureNameValueWithGrantedProvider.Value = value;
featureNameValueWithGrantedProvider.Provider = new FeatureValueProviderInfo(provider.Name, pk);
break;
}
}
if (featureNameValueWithGrantedProvider.Value != null)
{
featureValues[feature.Name] = featureNameValueWithGrantedProvider;
}
}
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 = await FeatureDefinitionManager.GetAsync(name);
if (feature.ValueType?.Validator.IsValid(value) == false)
{
throw new FeatureValueInvalidException(feature.DisplayName.Localize(StringLocalizerFactory));
}
var providers = Enumerable
.Reverse(Providers)
.SkipWhile(p => p.Name != providerName)
.ToList();
if (!providers.Any())
{
return;
}
if (providers.Count > 1 && !forceToSet && value != null)
{
await using (await providers[0].HandleContextAsync(providerName, providerKey))
{
var fallbackValue = await GetOrNullInternalAsync(name, providers[1].Name, null);
if (fallbackValue.Value == 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<FeatureNameValueWithGrantedProvider> GetOrNullInternalAsync(
string name,
string providerName,
string providerKey,
bool fallback = true) //TODO: Fallback is not used
{
var feature = await FeatureDefinitionManager.GetAsync(name);
var providers = Enumerable
.Reverse(Providers);
if (providerName != null)
{
providers = providers.SkipWhile(c => c.Name != providerName);
}
var featureNameValueWithGrantedProvider = new FeatureNameValueWithGrantedProvider(name, null);
foreach (var provider in providers)
{
string pk = null;
if (provider.Compatible(providerName))
{
pk = providerKey;
}
var value = await provider.GetOrNullAsync(feature, pk);
if (value != null)
{
featureNameValueWithGrantedProvider.Value = value;
featureNameValueWithGrantedProvider.Provider = new FeatureValueProviderInfo(provider.Name, pk);
break;
}
}
return featureNameValueWithGrantedProvider;
}
public async Task DeleteAsync(string providerName, string providerKey)
{
var featureNameValues = await GetAllAsync(providerName, providerKey);
var providers = Enumerable
.Reverse(Providers)
.SkipWhile(p => p.Name != providerName)
.ToList();
if (!providers.Any())
{
return;
}
providers = providers
.TakeWhile(p => p.Name == providerName)
.ToList(); //Getting list for case of there are more than one provider with same providerName
foreach (var featureNameValue in featureNameValues)
{
var feature = await FeatureDefinitionManager.GetAsync(featureNameValue.Name);
foreach (var provider in providers)
{
await provider.ClearAsync(feature, providerKey);
}
}
}
}