feat: settingmanagement

main
NoahLan 11 months ago
parent 6ce4bf3fa3
commit 8abbd5bea2

@ -0,0 +1,13 @@
using Volo.Abp.Data;
namespace NPin.Framework.SettingManagement.Domain;
/// <summary>
/// Abp设置管理器数据库参数
/// </summary>
public class AbpSettingManagementDbProperties
{
public static string DbTablePrefix { get; set; } = AbpCommonDbProperties.DbTablePrefix;
public static string? DbSchema { get; set; } = AbpCommonDbProperties.DbSchema;
public const string ConnectionStringName = "AbpSettingManagement";
}

@ -0,0 +1,47 @@
using JetBrains.Annotations;
using Volo.Abp.MultiTenancy;
using Volo.Abp.Text.Formatting;
namespace NPin.Framework.SettingManagement.Domain.Caching;
/// <summary>
/// 设置缓存项
/// 忽略多租户
/// </summary>
[Serializable]
[IgnoreMultiTenancy]
public class SettingCacheItem
{
/// <summary>
/// 缓存Key格式化参数
/// pn: providerName
/// pk: providerKey
/// n: name
/// </summary>
private const string CacheKeyFormat = "pn:{0},pk:{1},n:{2}";
/// <summary>
/// 值
/// </summary>
public string? Value { get; set; }
public SettingCacheItem()
{
}
public SettingCacheItem(string? value)
{
Value = value;
}
public static string CalculateCacheKey(string name, string providerName, string providerKey)
{
return string.Format(CacheKeyFormat, providerName, providerKey, name);
}
public static string? GetSettingNameFormCacheKeyOrNull(string cacheKey)
{
var result = FormattedStringValueExtracter.Extract(cacheKey, CacheKeyFormat, true);
return result.IsMatch ? result.Matches.Last().Value : null;
}
}

@ -0,0 +1,38 @@
using NPin.Framework.SettingManagement.Domain.Entities;
using Volo.Abp.Caching;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Domain.Entities.Events;
using Volo.Abp.EventBus;
namespace NPin.Framework.SettingManagement.Domain.Caching;
/// <summary>
/// 设置缓存项 过期
/// 变动时 过期
/// </summary>
public class SettingCacheItemInvalidator : ILocalEventHandler<EntityChangedEventData<SettingEntity>>,
ITransientDependency
{
protected IDistributedCache<SettingCacheItem> Cache { get; }
public SettingCacheItemInvalidator(IDistributedCache<SettingCacheItem> cache)
{
Cache = cache;
}
public virtual async Task HandleEventAsync(EntityChangedEventData<SettingEntity> eventData)
{
var entity = eventData.Entity;
var cacheKey = CalculateCacheKey(
entity.Name,
entity.ProviderName,
entity.ProviderKey);
await Cache.RemoveAsync(cacheKey, considerUow: true);
}
protected virtual string CalculateCacheKey(string name, string providerName, string providerKey)
{
return SettingCacheItem.CalculateCacheKey(name, providerName, providerKey);
}
}

@ -0,0 +1,46 @@
using JetBrains.Annotations;
using Volo.Abp.Domain.Entities;
namespace NPin.Framework.SettingManagement.Domain.Entities;
public class SettingEntity: Entity<Guid>, IAggregateRoot<Guid>
{
[NotNull]
public virtual string Name { get; protected set; }
[NotNull]
public virtual string Value { get; internal set; }
[CanBeNull]
public virtual string ProviderName { get; protected set; }
[CanBeNull]
public virtual string ProviderKey { get; protected set; }
public SettingEntity()
{
}
public SettingEntity(
Guid id,
[NotNull] string name,
[NotNull] string value,
[CanBeNull] string providerName = null,
[CanBeNull] string providerKey = null)
{
Check.NotNull(name, nameof(name));
Check.NotNull(value, nameof(value));
Id = id;
Name = name;
Value = value;
ProviderName = providerName;
ProviderKey = providerKey;
}
public override string ToString()
{
return $"{base.ToString()}, Name = {Name}, Value = {Value}, ProviderName = {ProviderName}, ProviderKey = {ProviderKey}";
}
}

@ -0,0 +1,16 @@
using JetBrains.Annotations;
using Volo.Abp.Settings;
namespace NPin.Framework.SettingManagement.Domain;
/// <summary>
/// 设置管理器
/// </summary>
public interface ISettingManager
{
Task<string?> GetOrNullAsync([NotNull] string name, [NotNull] string providerName, string? providerKey, bool fallback = true);
Task<List<SettingValue>> GetAllAsync([NotNull] string providerName, string? providerKey, bool fallback = true);
Task SetAsync([NotNull] string name, string? value, [NotNull] string providerName, string? providerKey, bool forceToSet = false);
}

@ -0,0 +1,24 @@
using NPin.Framework.SettingManagement.Domain.Entities;
using Volo.Abp.Domain.Repositories;
namespace NPin.Framework.SettingManagement.Domain;
public interface ISettingRepository: IBasicRepository<SettingEntity, Guid>
{
Task<SettingEntity?> FindAsync(
string name,
string providerName,
string providerKey,
CancellationToken cancellationToken = default);
Task<List<SettingEntity>> GetListAsync(
string providerName,
string providerKey,
CancellationToken cancellationToken = default);
Task<List<SettingEntity>> GetListAsync(
string[] names,
string providerName,
string providerKey,
CancellationToken cancellationToken = default);
}

@ -0,0 +1,14 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\..\..\common.props" />
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Volo.Abp.Ddd.Domain" Version="$(AbpVersion)" />
<PackageReference Include="Volo.Abp.SettingManagement.Domain.Shared" Version="$(AbpVersion)" />
</ItemGroup>
</Project>

@ -0,0 +1,28 @@
using NPin.Framework.SettingManagement.Domain.Options;
using Volo.Abp.Caching;
using Volo.Abp.Domain;
using Volo.Abp.SettingManagement;
using Volo.Abp.Settings;
namespace NPin.Framework.SettingManagement.Domain;
[DependsOn(
typeof(AbpSettingsModule),
typeof(AbpDddDomainModule),
typeof(AbpSettingManagementDomainSharedModule),
typeof(AbpCachingModule)
)]
public class NPinFrameworkSettingManagementDomainModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
Configure<SettingManagementOptions>(options =>
{
options.Providers.Add<DefaultValueSettingManagementProvider>();
options.Providers.Add<ConfigurationSettingManagementProvider>();
options.Providers.Add<GlobalSettingManagementProvider>();
options.Providers.Add<TenantSettingManagementProvider>();
options.Providers.Add<UserSettingManagementProvider>();
});
}
}

@ -0,0 +1,13 @@
using Volo.Abp.Collections;
namespace NPin.Framework.SettingManagement.Domain.Options;
public class SettingManagementOptions
{
public ITypeList<ISettingManagementProvider> Providers { get; }
public SettingManagementOptions()
{
Providers = new TypeList<ISettingManagementProvider>();
}
}

@ -0,0 +1,32 @@
using Microsoft.Extensions.Configuration;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Settings;
namespace NPin.Framework.SettingManagement.Domain;
public class ConfigurationSettingManagementProvider: ISettingManagementProvider, ITransientDependency
{
public string Name => ConfigurationSettingValueProvider.ProviderName;
protected IConfiguration Configuration { get; }
public ConfigurationSettingManagementProvider(IConfiguration configuration)
{
Configuration = configuration;
}
public virtual Task<string?> GetOrNullAsync(SettingDefinition setting, string providerKey)
{
return Task.FromResult(Configuration[ConfigurationSettingValueProvider.ConfigurationNamePrefix + setting.Name]);
}
public Task SetAsync(SettingDefinition setting, string value, string providerKey)
{
throw new AbpException($"Can not set a setting value to the application configuration.");
}
public Task ClearAsync(SettingDefinition setting, string providerKey)
{
throw new AbpException($"Can not clear provider to the application configuration.");
}
}

@ -0,0 +1,26 @@
using Volo.Abp.DependencyInjection;
using Volo.Abp.Settings;
namespace NPin.Framework.SettingManagement.Domain;
public class DefaultValueSettingManagementProvider : ISettingManagementProvider, ISingletonDependency
{
public string Name => DefaultValueSettingValueProvider.ProviderName;
public virtual Task<string?> GetOrNullAsync(SettingDefinition setting, string providerKey)
{
return Task.FromResult(setting.DefaultValue);
}
public Task SetAsync(SettingDefinition setting, string value, string providerKey)
{
throw new AbpException(
$"Can not set default value of a setting. It is only possible while defining the setting in a {typeof(ISettingDefinitionProvider)} implementation.");
}
public Task ClearAsync(SettingDefinition setting, string providerKey)
{
throw new AbpException(
$"Can not clear default value of a setting. It is only possible while defining the setting in a {typeof(ISettingDefinitionProvider)} implementation.");
}
}

@ -0,0 +1,19 @@
using JetBrains.Annotations;
using Volo.Abp.Settings;
namespace NPin.Framework.SettingManagement.Domain.Provider.Extensions;
public static class ConfigurationValueSettingManagerExtensions
{
public static Task<string?> GetOrNullConfigurationAsync(this ISettingManager settingManager, [NotNull] string name,
bool fallback = true)
{
return settingManager.GetOrNullAsync(name, ConfigurationSettingValueProvider.ProviderName, null, fallback);
}
public static Task<List<SettingValue>> GetAllConfigurationAsync(this ISettingManager settingManager,
bool fallback = true)
{
return settingManager.GetAllAsync(ConfigurationSettingValueProvider.ProviderName, null, fallback);
}
}

@ -0,0 +1,18 @@
using JetBrains.Annotations;
using Volo.Abp.Settings;
namespace NPin.Framework.SettingManagement.Domain.Provider.Extensions;
public static class DefaultValueSettingManagerExtensions
{
public static Task<string?> GetOrNullDefaultAsync(this ISettingManager settingManager, [NotNull] string name,
bool fallback = true)
{
return settingManager.GetOrNullAsync(name, DefaultValueSettingValueProvider.ProviderName, null, fallback);
}
public static Task<List<SettingValue>> GetAllDefaultAsync(this ISettingManager settingManager, bool fallback = true)
{
return settingManager.GetAllAsync(DefaultValueSettingValueProvider.ProviderName, null, fallback);
}
}

@ -0,0 +1,24 @@
using JetBrains.Annotations;
using Volo.Abp.Settings;
namespace NPin.Framework.SettingManagement.Domain.Provider.Extensions;
public static class GlobalSettingManagerExtensions
{
public static Task<string?> GetOrNullGlobalAsync(this ISettingManager settingManager, [NotNull] string name,
bool fallback = true)
{
return settingManager.GetOrNullAsync(name, GlobalSettingValueProvider.ProviderName, null, fallback);
}
public static Task<List<SettingValue>> GetAllGlobalAsync(this ISettingManager settingManager, bool fallback = true)
{
return settingManager.GetAllAsync(GlobalSettingValueProvider.ProviderName, null, fallback);
}
public static Task SetGlobalAsync(this ISettingManager settingManager, [NotNull] string name,
string? value)
{
return settingManager.SetAsync(name, value, GlobalSettingValueProvider.ProviderName, null);
}
}

@ -0,0 +1,53 @@
using JetBrains.Annotations;
using Volo.Abp.Settings;
namespace NPin.Framework.SettingManagement.Domain.Provider.Extensions;
public static class TenantSettingManagerExtensions
{
public static Task<string?> GetOrNullForTenantAsync(this ISettingManager settingManager, [NotNull] string name,
Guid tenantId, bool fallback = true)
{
return settingManager.GetOrNullAsync(name, TenantSettingValueProvider.ProviderName, tenantId.ToString(),
fallback);
}
public static Task<string?> GetOrNullForCurrentTenantAsync(this ISettingManager settingManager,
[NotNull] string name, bool fallback = true)
{
return settingManager.GetOrNullAsync(name, TenantSettingValueProvider.ProviderName, null, fallback);
}
public static Task<List<SettingValue>> GetAllForTenantAsync(this ISettingManager settingManager, Guid tenantId,
bool fallback = true)
{
return settingManager.GetAllAsync(TenantSettingValueProvider.ProviderName, tenantId.ToString(), fallback);
}
public static Task<List<SettingValue>> GetAllForCurrentTenantAsync(this ISettingManager settingManager,
bool fallback = true)
{
return settingManager.GetAllAsync(TenantSettingValueProvider.ProviderName, null, fallback);
}
public static Task SetForTenantAsync(this ISettingManager settingManager, Guid tenantId, [NotNull] string name,
string? value, bool forceToSet = false)
{
return settingManager.SetAsync(name, value, TenantSettingValueProvider.ProviderName, tenantId.ToString(),
forceToSet);
}
public static Task SetForCurrentTenantAsync(this ISettingManager settingManager, [NotNull] string name,
string? value, bool forceToSet = false)
{
return settingManager.SetAsync(name, value, TenantSettingValueProvider.ProviderName, null, forceToSet);
}
public static Task SetForTenantOrGlobalAsync(this ISettingManager settingManager, Guid? tenantId,
[NotNull] string name, string? value, bool forceToSet = false)
{
return tenantId.HasValue
? settingManager.SetForTenantAsync(tenantId.Value, name, value, forceToSet)
: settingManager.SetGlobalAsync(name, value);
}
}

@ -0,0 +1,44 @@
using JetBrains.Annotations;
using Volo.Abp.Settings;
namespace NPin.Framework.SettingManagement.Domain.Provider.Extensions;
public static class UserSettingManagerExtensions
{
public static Task<string?> GetOrNullForUserAsync(this ISettingManager settingManager, [NotNull] string name,
Guid userId, bool fallback = true)
{
return settingManager.GetOrNullAsync(name, UserSettingValueProvider.ProviderName, userId.ToString(), fallback);
}
public static Task<string?> GetOrNullForCurrentUserAsync(this ISettingManager settingManager, [NotNull] string name,
bool fallback = true)
{
return settingManager.GetOrNullAsync(name, UserSettingValueProvider.ProviderName, null, fallback);
}
public static Task<List<SettingValue>> GetAllForUserAsync(this ISettingManager settingManager, Guid userId,
bool fallback = true)
{
return settingManager.GetAllAsync(UserSettingValueProvider.ProviderName, userId.ToString(), fallback);
}
public static Task<List<SettingValue>> GetAllForCurrentUserAsync(this ISettingManager settingManager,
bool fallback = true)
{
return settingManager.GetAllAsync(UserSettingValueProvider.ProviderName, null, fallback);
}
public static Task SetForUserAsync(this ISettingManager settingManager, Guid userId, [NotNull] string name,
string? value, bool forceToSet = false)
{
return settingManager.SetAsync(name, value, UserSettingValueProvider.ProviderName, userId.ToString(),
forceToSet);
}
public static Task SetForCurrentUserAsync(this ISettingManager settingManager, [NotNull] string name, string? value,
bool forceToSet = false)
{
return settingManager.SetAsync(name, value, UserSettingValueProvider.ProviderName, null, forceToSet);
}
}

@ -0,0 +1,18 @@
using Volo.Abp.DependencyInjection;
using Volo.Abp.Settings;
namespace NPin.Framework.SettingManagement.Domain;
public class GlobalSettingManagementProvider: SettingManagementProvider, ITransientDependency
{
public override string Name => GlobalSettingValueProvider.ProviderName;
public GlobalSettingManagementProvider(ISettingManagementStore settingManagementStore) : base(settingManagementStore)
{
}
protected override string? NormalizeProviderKey(string providerKey)
{
return null;
}
}

@ -0,0 +1,34 @@
using JetBrains.Annotations;
using Volo.Abp.Settings;
namespace NPin.Framework.SettingManagement.Domain;
public interface ISettingManagementProvider
{
string Name { get; }
/// <summary>
/// 获取配置项
/// </summary>
/// <param name="setting"></param>
/// <param name="providerKey"></param>
/// <returns></returns>
Task<string?> GetOrNullAsync([NotNull] SettingDefinition setting, [CanBeNull] string providerKey);
/// <summary>
/// 设置配置数据
/// </summary>
/// <param name="setting"></param>
/// <param name="value"></param>
/// <param name="providerKey"></param>
/// <returns></returns>
Task SetAsync([NotNull] SettingDefinition setting, [NotNull] string value, [CanBeNull] string providerKey);
/// <summary>
/// 清除配置项
/// </summary>
/// <param name="setting"></param>
/// <param name="providerKey"></param>
/// <returns></returns>
Task ClearAsync([NotNull] SettingDefinition setting, [CanBeNull] string providerKey);
}

@ -0,0 +1,28 @@
using Volo.Abp.DependencyInjection;
using Volo.Abp.MultiTenancy;
using Volo.Abp.Settings;
namespace NPin.Framework.SettingManagement.Domain;
public class TenantSettingManagementProvider : SettingManagementProvider, ITransientDependency
{
public override string Name => TenantSettingValueProvider.ProviderName;
protected ICurrentTenant CurrentTenant { get; }
public TenantSettingManagementProvider(ISettingManagementStore settingManagementStore, ICurrentTenant currentTenant)
: base(settingManagementStore)
{
CurrentTenant = currentTenant;
}
protected override string? NormalizeProviderKey(string? providerKey)
{
if (providerKey != null)
{
return providerKey;
}
return CurrentTenant.Id?.ToString();
}
}

@ -0,0 +1,28 @@
using Volo.Abp.DependencyInjection;
using Volo.Abp.Settings;
using Volo.Abp.Users;
namespace NPin.Framework.SettingManagement.Domain;
public class UserSettingManagementProvider : SettingManagementProvider, ITransientDependency
{
public override string Name => UserSettingValueProvider.ProviderName;
protected ICurrentUser CurrentUser { get; }
public UserSettingManagementProvider(ISettingManagementStore settingManagementStore, ICurrentUser currentUser) :
base(settingManagementStore)
{
CurrentUser = currentUser;
}
protected override string? NormalizeProviderKey(string? providerKey)
{
if (providerKey != null)
{
return providerKey;
}
return CurrentUser?.Id.ToString();
}
}

@ -0,0 +1,38 @@
using Volo.Abp.Settings;
namespace NPin.Framework.SettingManagement.Domain;
/// <summary>
/// 设置管理器提供者
/// </summary>
public abstract class SettingManagementProvider : ISettingManagementProvider
{
public abstract string Name { get; }
protected ISettingManagementStore SettingManagementStore { get; }
public SettingManagementProvider(ISettingManagementStore settingManagementStore)
{
SettingManagementStore = settingManagementStore;
}
public virtual async Task<string?> GetOrNullAsync(SettingDefinition setting, string providerKey)
{
return await SettingManagementStore.GetOrNullAsync(setting.Name, Name, NormalizeProviderKey(providerKey));
}
public virtual async Task SetAsync(SettingDefinition setting, string value, string providerKey)
{
await SettingManagementStore.SetAsync(setting.Name, value, Name, NormalizeProviderKey(providerKey));
}
public virtual async Task ClearAsync(SettingDefinition setting, string providerKey)
{
await SettingManagementStore.DeleteAsync(setting.Name, Name, NormalizeProviderKey(providerKey));
}
protected virtual string? NormalizeProviderKey(string? providerKey)
{
return providerKey;
}
}

@ -0,0 +1,200 @@
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using NPin.Framework.SettingManagement.Domain.Options;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Settings;
namespace NPin.Framework.SettingManagement.Domain;
public class SettingManager : ISettingManager, ISingletonDependency
{
private readonly Lazy<List<ISettingManagementProvider>> _lazyProviders;
protected ISettingDefinitionManager SettingDefinitionManager { get; }
protected ISettingEncryptionService SettingEncryptionService { get; }
protected List<ISettingManagementProvider> Providers => _lazyProviders.Value;
protected SettingManagementOptions Options { get; }
public SettingManager(
IServiceProvider serviceProvider,
ISettingDefinitionManager settingDefinitionManager,
ISettingEncryptionService settingEncryptionService,
IOptions<SettingManagementOptions> options)
{
SettingDefinitionManager = settingDefinitionManager;
SettingEncryptionService = settingEncryptionService;
Options = options.Value;
// TODO use IServiceScopeFactory and create a scope ?
_lazyProviders = new Lazy<List<ISettingManagementProvider>>(
() => Options
.Providers
.Select(c => serviceProvider.GetRequiredService(c) as ISettingManagementProvider)
.ToList(),
true
);
}
public virtual Task<string?> 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<List<SettingValue>> GetAllAsync(string providerName, string? providerKey,
bool fallback = true)
{
Check.NotNull(providerName, nameof(providerName));
var settingDefinitions = await SettingDefinitionManager.GetAllAsync();
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<SettingValue>();
}
var settingValues = new Dictionary<string, SettingValue>();
foreach (var setting in settingDefinitions)
{
string value = null;
if (setting.IsInherited)
{
foreach (var provider in providerList)
{
var providerValue = await provider.GetOrNullAsync(
setting,
provider.Name == providerName ? providerKey : null
);
if (providerValue != null)
{
value = providerValue;
}
}
}
else
{
value = await providerList[0].GetOrNullAsync(
setting,
providerKey
);
}
if (setting.IsEncrypted)
{
value = SettingEncryptionService.Decrypt(setting, value);
}
if (value != null)
{
settingValues[setting.Name] = new SettingValue(setting.Name, value);
}
}
return settingValues.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 setting = await SettingDefinitionManager.GetAsync(name);
var providers = Enumerable
.Reverse(Providers)
.SkipWhile(p => p.Name != providerName)
.ToList();
if (!providers.Any())
{
return;
}
if (setting.IsEncrypted)
{
value = SettingEncryptionService.Encrypt(setting, value);
}
if (providers.Count > 1 && !forceToSet && setting.IsInherited && 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(setting, providerKey);
}
}
else
{
foreach (var provider in providers)
{
await provider.SetAsync(setting, value, providerKey);
}
}
}
protected virtual async Task<string?> GetOrNullInternalAsync(string name, string? providerName, string? providerKey,
bool fallback = true)
{
var setting = await SettingDefinitionManager.GetAsync(name);
var providers = Enumerable
.Reverse(Providers);
if (providerName != null)
{
providers = providers.SkipWhile(c => c.Name != providerName);
}
if (!fallback || !setting.IsInherited)
{
providers = providers.TakeWhile(c => c.Name == providerName);
}
string value = null;
foreach (var provider in providers)
{
value = await provider.GetOrNullAsync(
setting,
provider.Name == providerName ? providerKey : null
);
if (value != null)
{
break;
}
}
if (setting.IsEncrypted)
{
value = SettingEncryptionService.Decrypt(setting, value);
}
return value;
}
}

@ -0,0 +1,19 @@
using Volo.Abp.Settings;
namespace NPin.Framework.SettingManagement.Domain;
/// <summary>
/// 设置存储器
/// </summary>
public interface ISettingManagementStore
{
Task<string?> GetOrNullAsync(string name, string providerName, string providerKey);
Task<List<SettingValue>> GetListAsync(string providerName, string providerKey);
Task<List<SettingValue>> GetListAsync(string[] names, string providerName, string providerKey);
Task SetAsync(string name, string value, string providerName, string providerKey);
Task DeleteAsync(string name, string providerName, string providerKey);
}

@ -0,0 +1,215 @@
using NPin.Framework.SettingManagement.Domain.Caching;
using NPin.Framework.SettingManagement.Domain.Entities;
using Volo.Abp.Caching;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Guids;
using Volo.Abp.Settings;
using Volo.Abp.Uow;
namespace NPin.Framework.SettingManagement.Domain;
public class SettingManagementStore : ISettingManagementStore, ITransientDependency
{
protected IDistributedCache<SettingCacheItem> Cache { get; }
protected ISettingDefinitionManager SettingDefinitionManager { get; }
protected ISettingRepository SettingRepository { get; }
protected IGuidGenerator GuidGenerator { get; }
public SettingManagementStore(IDistributedCache<SettingCacheItem> cache,
ISettingDefinitionManager settingDefinitionManager, ISettingRepository settingRepository,
IGuidGenerator guidGenerator)
{
Cache = cache;
SettingDefinitionManager = settingDefinitionManager;
SettingRepository = settingRepository;
GuidGenerator = guidGenerator;
}
[UnitOfWork]
public virtual async Task<string?> GetOrNullAsync(string name, string providerName, string providerKey)
{
return (await GetCacheItemAsync(name, providerName, providerKey)).Value;
}
[UnitOfWork]
public virtual async Task<List<SettingValue>> GetListAsync(string providerName, string providerKey)
{
var settings = await SettingRepository.GetListAsync(providerName, providerKey);
return settings.Select(s => new SettingValue(s.Name, s.Value)).ToList();
}
[UnitOfWork]
public virtual async Task<List<SettingValue>> GetListAsync(string[] names, string providerName, string providerKey)
{
Check.NotNullOrEmpty(names, nameof(names));
var result = new List<SettingValue>();
if (names.Length == 1)
{
var name = names.First();
result.Add(new SettingValue(name, (await GetCacheItemAsync(name, providerName, providerKey)).Value));
return result;
}
var cacheItems = await GetCacheItemsAsync(names, providerName, providerKey);
result.AddRange(cacheItems.Select(item =>
new SettingValue(GetSettingNameFormCacheKeyOrNull(item.Key), item.Value?.Value)));
return result;
}
[UnitOfWork]
public virtual async Task SetAsync(string name, string value, string providerName, string providerKey)
{
var setting = await SettingRepository.FindAsync(name, providerName, providerKey);
if (setting == null)
{
setting = new SettingEntity(GuidGenerator.Create(), name, value, providerName, providerKey);
await SettingRepository.InsertAsync(setting);
}
else
{
setting.Value = value;
await SettingRepository.UpdateAsync(setting);
}
await Cache.SetAsync(CalculateCacheKey(name, providerName, providerKey), new SettingCacheItem(setting.Value),
considerUow: true);
}
[UnitOfWork]
public virtual async Task DeleteAsync(string name, string providerName, string providerKey)
{
var setting = await SettingRepository.FindAsync(name, providerName, providerKey);
if (setting != null)
{
await SettingRepository.DeleteAsync(setting);
await Cache.RemoveAsync(CalculateCacheKey(name, providerName, providerKey), considerUow: true);
}
}
protected virtual async Task<SettingCacheItem> GetCacheItemAsync(string name, string providerName,
string providerKey)
{
var cacheKey = CalculateCacheKey(name, providerName, providerKey);
var cacheItem = await Cache.GetAsync(cacheKey, considerUow: true);
if (cacheItem != null)
{
return cacheItem;
}
cacheItem = new SettingCacheItem(null);
await SetCacheItemsAsync(providerName, providerKey, name, cacheItem);
return cacheItem;
}
protected virtual async Task<List<KeyValuePair<string, SettingCacheItem>>> GetCacheItemsAsync(string[] names,
string providerName, string providerKey)
{
var cacheKeys = names.Select(x => CalculateCacheKey(x, providerName, providerKey)).ToList();
var cacheItems = (await Cache.GetManyAsync(cacheKeys, considerUow: true)).ToList();
if (cacheItems.All(x => x.Value != null))
{
return cacheItems;
}
var notCacheKeys = cacheItems.Where(x => x.Value == null).Select(x => x.Key).ToList();
var newCacheItems = await SetCacheItemsAsync(providerName, providerKey, notCacheKeys);
var result = new List<KeyValuePair<string, SettingCacheItem>>();
foreach (var key in cacheKeys)
{
var item = newCacheItems.FirstOrDefault(x => x.Key == key);
if (item.Value == null)
{
item = cacheItems.FirstOrDefault(x => x.Key == key);
}
result.Add(new KeyValuePair<string, SettingCacheItem>(key, item.Value));
}
return result;
}
private async Task SetCacheItemsAsync(
string providerName,
string providerKey,
string currentName,
SettingCacheItem currentCacheItem)
{
var settingDefinitions = await SettingDefinitionManager.GetAllAsync();
var settingsDictionary = (await SettingRepository.GetListAsync(providerName, providerKey))
.ToDictionary(s => s.Name, s => s.Value);
var cacheItems = new List<KeyValuePair<string, SettingCacheItem>>();
foreach (var settingDefinition in settingDefinitions)
{
var settingValue = settingsDictionary.GetOrDefault(settingDefinition.Name);
cacheItems.Add(
new KeyValuePair<string, SettingCacheItem>(
CalculateCacheKey(settingDefinition.Name, providerName, providerKey),
new SettingCacheItem(settingValue)
)
);
if (settingDefinition.Name == currentName)
{
currentCacheItem.Value = settingValue;
}
}
await Cache.SetManyAsync(cacheItems, considerUow: true);
}
private async Task<List<KeyValuePair<string, SettingCacheItem>>> SetCacheItemsAsync(
string providerName,
string providerKey,
List<string> notCacheKeys)
{
var settingDefinitions = (await SettingDefinitionManager.GetAllAsync()).Where(x =>
notCacheKeys.Any(k => GetSettingNameFormCacheKeyOrNull(k) == x.Name));
var settingsDictionary =
(await SettingRepository.GetListAsync(notCacheKeys.Select(GetSettingNameFormCacheKeyOrNull).ToArray(),
providerName, providerKey))
.ToDictionary(s => s.Name, s => s.Value);
var cacheItems = new List<KeyValuePair<string, SettingCacheItem>>();
foreach (var settingDefinition in settingDefinitions)
{
var settingValue = settingsDictionary.GetOrDefault(settingDefinition.Name);
cacheItems.Add(
new KeyValuePair<string, SettingCacheItem>(
CalculateCacheKey(settingDefinition.Name, providerName, providerKey),
new SettingCacheItem(settingValue)
)
);
}
await Cache.SetManyAsync(cacheItems, considerUow: true);
return cacheItems;
}
protected virtual string CalculateCacheKey(string name, string providerName, string providerKey)
{
return SettingCacheItem.CalculateCacheKey(name, providerName, providerKey);
}
protected virtual string? GetSettingNameFormCacheKeyOrNull(string key)
{
//TODO: throw ex when name is null?
return SettingCacheItem.GetSettingNameFormCacheKeyOrNull(key);
}
}

@ -0,0 +1,27 @@
using Volo.Abp.DependencyInjection;
using Volo.Abp.Settings;
namespace NPin.Framework.SettingManagement.Domain;
/// <summary>
/// 设置存储
/// </summary>
public class SettingStore : ISettingStore, ITransientDependency
{
protected ISettingManagementStore ManagementStore { get; }
public SettingStore(ISettingManagementStore managementStore)
{
ManagementStore = managementStore;
}
public virtual Task<string?> GetOrNullAsync(string name, string? providerName, string? providerKey)
{
return ManagementStore.GetOrNullAsync(name, providerName, providerKey);
}
public virtual Task<List<SettingValue>> GetAllAsync(string[] names, string? providerName, string? providerKey)
{
return ManagementStore.GetListAsync(names, providerName, providerKey);
}
}

@ -0,0 +1,14 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\..\..\common.props" />
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\framework\NPin.Framework.SqlSugarCore\NPin.Framework.SqlSugarCore.csproj" />
<ProjectReference Include="..\NPin.Framework.SettingManagement.Domain\NPin.Framework.SettingManagement.Domain.csproj" />
</ItemGroup>
</Project>

@ -0,0 +1,18 @@
using Microsoft.Extensions.DependencyInjection;
using NPin.Framework.SettingManagement.Domain;
using NPin.Framework.SqlSugarCore;
namespace NPin.Framework.SettingManagement.SqlSugarCore;
[DependsOn(
typeof(NPinFrameworkSettingManagementDomainModule),
typeof(NPinFrameworkSqlSugarCoreModule)
)]
public class NPinFrameworkSettingManagementSqlSugarCoreModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
var services = context.Services;
services.AddTransient<ISettingRepository, SqlSugarCoreSettingRepository>();
}
}

@ -0,0 +1,39 @@
using NPin.Framework.SettingManagement.Domain;
using NPin.Framework.SettingManagement.Domain.Entities;
using NPin.Framework.SqlSugarCore.Abstractions;
using NPin.Framework.SqlSugarCore.Repositories;
namespace NPin.Framework.SettingManagement.SqlSugarCore;
public class SqlSugarCoreSettingRepository : SqlSugarRepository<SettingEntity, Guid>, ISettingRepository
{
public SqlSugarCoreSettingRepository(ISugarDbContextProvider<ISqlSugarDbContext> sugarDbContextProvider) : base(
sugarDbContextProvider)
{
}
public virtual async Task<SettingEntity?> FindAsync(string name, string providerName, string providerKey,
CancellationToken cancellationToken = default)
{
return await DbQueryable
.Where(s => s.Name == name && s.ProviderName == providerName && s.ProviderKey == providerKey)
.OrderBy(x => x.Id)
.FirstAsync(cancellationToken);
}
public virtual async Task<List<SettingEntity>> GetListAsync(string providerName, string providerKey,
CancellationToken cancellationToken = default)
{
return await DbQueryable
.Where(s => s.ProviderName == providerName && s.ProviderKey == providerKey)
.ToListAsync(cancellationToken);
}
public virtual async Task<List<SettingEntity>> GetListAsync(string[] names, string providerName, string providerKey,
CancellationToken cancellationToken = default)
{
return await DbQueryable
.Where(s => names.Contains(s.Name) && s.ProviderName == providerName && s.ProviderKey == providerKey)
.ToListAsync(cancellationToken);
}
}
Loading…
Cancel
Save