介绍
此系列文章主要是对ABP源码进行解读,初探作者在创造ABP的框架思路,和使用到的设计模式进行。
通过解读ABP源码,可以提升ABP使用方式,可以提升编码意识,提高面向对象编程思想。
本篇文章主要介绍ABP框架的系统设置管理等机制。
每个应用程序都需要存储一些设置,并在应用程序的某个地方使用这些设置。ABP提供了一个强大的基础结构来存储/检索服务器端和客户端(js)上可用的应用程序、租户和用户级别设置。
设置是通常存储在数据库(或其他源)中的Name-Value字符串对。我们可以通过将非字符串值转换为字符串来存储。
ABP提供了三种设置范围:
- 应用级:应用程序范围的设置用于用户/租户独立的设置
- 租户级:如果应用程序是多租户的,我们可以定义租户特定的设置
- 用户级:我们可以使用用户范围的设置来存储/获取每个用户特定的设置值
默认设置范围是分层的(除非您将IsInherited为false)。例如,如果我们将设置的范围定义为“应用程序租户用户”,并尝试获取设置的当前值,获取当前值的逻辑如下
- 定义了用户级别的设置,优先使用用户级别的设置值
- 如果没有定义用户级别的设置,但是定义了租户级别的设置值,那么使用租户级别的值
- 如果即没有定义用户级别的设置,也没有定义租户级别的设置值,那么使用应用级别的值
- 如果都没有定义,则使用默认值
参考:
UML
设置- SettingDefinition: 定义设置,设置用于配置和更改应用程序
- SettingDefinitionGroup: 设置组用于将一些设置组合在一起, 一组可以是另一组的子组
- ISettingDefinitionManager: 定义设置定义信息管理器
- SettingDefinitionManager: 实现设置信息管理器,负责从提供者中读取设置信息
- SettingDefinitionProviderContext:设置提供者所使用的上下文
- ISettingsConfiguration: 配置设置系统,主要是提供设置提供者类型
- SettingProvider: 设置提供者基类,继承这个类来定义模块/应用程序的设置
- SettingScopes:设置范围,枚举类型,可以组合使用
- ISettingManager: 这是必须实现的主要接口,以便能够加载/更改设置的值
- SettingManager:该类实现了在数据库中管理设置值的方法
- ISettingStore:定义用于从/到数据源(数据库)获取/设置,在Module.Zero中实现
- ISettingValue:定义设置值接口
- SettingValueObject:设置值的值对象
源码解析
定义设置
定义SettingDefinition
类,提供设置属性
/// <summary>
/// Defines a setting.
/// A setting is used to configure and change behavior of the application.
/// 定义设置,
/// 设置用于配置和更改应用程序
/// </summary>
public class SettingDefinition
{
/// <summary>
/// Unique name of the setting.
/// 设置唯一名称
/// </summary>
public string Name { get; private set; }
/// <summary>
/// Display name of the setting.
/// This can be used to show setting to the user.
/// 设置的显示名,用来向用户显示设置
/// </summary>
public ILocalizableString DisplayName { get; set; }
/// <summary>
/// A brief description for this setting.
/// 设置的简要描述
/// </summary>
public ILocalizableString Description { get; set; }
/// <summary>
/// Scopes of this setting.
/// Default value: <see cref="SettingScopes.Application"/>.
/// 设置的范围,默认值是<see cref="SettingScopes.Application"/>
/// </summary>
public SettingScopes Scopes { get; set; }
/// <summary>
/// Is this setting inherited from parent scopes.
/// Default: True.
/// 设置是从父范围继承,默认为true
/// </summary>
public bool IsInherited { get; set; }
/// <summary>
/// Gets/sets group for this setting.
/// 设置分组
/// </summary>
public SettingDefinitionGroup Group { get; set; }
/// <summary>
/// Default value of the setting.
/// 设置的默认值
/// </summary>
public string DefaultValue { get; set; }
/// <summary>
/// Can clients see this setting and it's value.
/// It maybe dangerous for some settings to be visible to clients (such as email server password).
/// Default: false.
/// </summary>
[Obsolete("Use ClientVisibilityProvider instead.")]
public bool IsVisibleToClients { get; set; }
/// <summary>
/// Client visibility definition for the setting.
/// 客户端是否可以见设置
/// </summary>
public ISettingClientVisibilityProvider ClientVisibilityProvider { get; set; }
/// <summary>
/// Can be used to store a custom object related to this setting.
/// 可以用来存储与此设置相关的自定义对象
/// </summary>
public object CustomData { get; set; }
/// <summary>
/// Creates a new <see cref="SettingDefinition"/> object.
/// </summary>
/// <param name="name">Unique name of the setting</param>
/// <param name="defaultValue">Default value of the setting</param>
/// <param name="displayName">Display name of the permission</param>
/// <param name="group">Group of this setting</param>
/// <param name="description">A brief description for this setting</param>
/// <param name="scopes">Scopes of this setting. Default value: <see cref="SettingScopes.Application"/>.</param>
/// <param name="isVisibleToClients">Can clients see this setting and it's value. Default: false</param>
/// <param name="isInherited">Is this setting inherited from parent scopes. Default: True.</param>
/// <param name="customData">Can be used to store a custom object related to this setting</param>
/// <param name="clientVisibilityProvider">Client visibility definition for the setting. Default: invisible</param>
public SettingDefinition(
string name,
string defaultValue,
ILocalizableString displayName = null,
SettingDefinitionGroup group = null,
ILocalizableString description = null,
SettingScopes scopes = SettingScopes.Application,
bool isVisibleToClients = false,
bool isInherited = true,
object customData = null,
ISettingClientVisibilityProvider clientVisibilityProvider = null)
{
if (string.IsNullOrEmpty(name))
{
throw new ArgumentNullException(nameof(name));
}
Name = name;
DefaultValue = defaultValue;
DisplayName = displayName;
Group = @group;
Description = description;
Scopes = scopes;
IsVisibleToClients = isVisibleToClients;
IsInherited = isInherited;
CustomData = customData;
ClientVisibilityProvider = new HiddenSettingClientVisibilityProvider();
if (isVisibleToClients)
{
ClientVisibilityProvider = new VisibleSettingClientVisibilityProvider();
}
else if (clientVisibilityProvider != null)
{
ClientVisibilityProvider = clientVisibilityProvider;
}
}
}
设置提供者
为了方便从各个模块中读取相应的设置信息,需要定义一个设置提供者,在模块中继承SettingProvider
并实现,在模块启动中使用SettingsConfiguration
设置具体的提供者类型
/// <summary>
/// Inherit this class to define settings for a module/application.
/// 继承这个类来定义模块/应用程序的设置
/// </summary>
public abstract class SettingProvider : ITransientDependency
{
/// <summary>
/// Gets all setting definitions provided by this provider.
/// 获取由该提供者提供的所有设置定义
/// </summary>
/// <returns>List of settings</returns>
public abstract IEnumerable<SettingDefinition> GetSettingDefinitions(SettingDefinitionProviderContext context);
}
Configuration.Settings.Providers.Add<MySettingProvider>();
设置定义管理器
管理器主要收集所有设置提供者提供的设置定义信息
/// <summary>
/// Implements <see cref="ISettingDefinitionManager"/>.
/// 实现<see cref="ISettingDefinitionManager"/>,负责从提供者中读取设置信息
/// </summary>
internal class SettingDefinitionManager : ISettingDefinitionManager, ISingletonDependency
{
private readonly IIocManager _iocManager;
/// <summary>
/// 设置的配置
/// </summary>
private readonly ISettingsConfiguration _settingsConfiguration;
private readonly IDictionary<string, SettingDefinition> _settings;
/// <summary>
/// Constructor.
/// </summary>
public SettingDefinitionManager(IIocManager iocManager, ISettingsConfiguration settingsConfiguration)
{
_iocManager = iocManager;
_settingsConfiguration = settingsConfiguration;
_settings = new Dictionary<string, SettingDefinition>();
}
public void Initialize()
{
var context = new SettingDefinitionProviderContext(this);
foreach (var providerType in _settingsConfiguration.Providers)
{
using (var provider = CreateProvider(providerType))
{
foreach (var settings in provider.Object.GetSettingDefinitions(context))
{
_settings[settings.Name] = settings;
}
}
}
}
public SettingDefinition GetSettingDefinition(string name)
{
if (!_settings.TryGetValue(name, out var settingDefinition))
{
throw new AbpException("There is no setting defined with name: " + name);
}
return settingDefinition;
}
public IReadOnlyList<SettingDefinition> GetAllSettingDefinitions()
{
return _settings.Values.ToImmutableList();
}
private IDisposableDependencyObjectWrapper<SettingProvider> CreateProvider(Type providerType)
{
return _iocManager.ResolveAsDisposable<SettingProvider>(providerType);
}
}
管理设置
为了在其他地方使用修改和获取设置值,abp使用SettingManager
实现
该类主要提供三个大功能:
- 获取设置值
- 获取全部设置值
- 更新设置值
/// <summary>
/// This class implements <see cref="ISettingManager"/> to manage setting values in the database.
/// 该类实现了在数据库中管理设置值的方法。
/// </summary>
public class SettingManager : ISettingManager, ISingletonDependency
{
/// <summary>
/// 缓存的key
/// </summary>
public const string ApplicationSettingsCacheKey = "ApplicationSettings";
/// <summary>
/// Reference to the current Session.
/// 当前Session
/// </summary>
public IAbpSession AbpSession { get; set; }
/// <summary>
/// Reference to the setting store.
/// 设置存储
/// </summary>
public ISettingStore SettingStore { get; set; }
/// <summary>
/// 设置定义管理器
/// </summary>
private readonly ISettingDefinitionManager _settingDefinitionManager;
/// <summary>
/// 应用级别设置缓存
/// </summary>
private readonly ITypedCache<string, Dictionary<string, SettingInfo>> _applicationSettingCache;
/// <summary>
/// 租户级别设置缓存
/// </summary>
private readonly ITypedCache<int, Dictionary<string, SettingInfo>> _tenantSettingCache;
/// <summary>
/// 用户级别设置缓存
/// </summary>
private readonly ITypedCache<string, Dictionary<string, SettingInfo>> _userSettingCache;
/// <inheritdoc/>
public SettingManager(ISettingDefinitionManager settingDefinitionManager, ICacheManager cacheManager)
{
_settingDefinitionManager = settingDefinitionManager;
AbpSession = NullAbpSession.Instance;
SettingStore = DefaultConfigSettingStore.Instance;
_applicationSettingCache = cacheManager.GetApplicationSettingsCache();
_tenantSettingCache = cacheManager.GetTenantSettingsCache();
_userSettingCache = cacheManager.GetUserSettingsCache();
}
#region Public methods
/// <inheritdoc/>
public Task<string> GetSettingValueAsync(string name)
{
return GetSettingValueInternalAsync(name, AbpSession.TenantId, AbpSession.UserId);
}
public Task<string> GetSettingValueForApplicationAsync(string name)
{
return GetSettingValueInternalAsync(name);
}
public Task<string> GetSettingValueForApplicationAsync(string name, bool fallbackToDefault)
{
return GetSettingValueInternalAsync(name, fallbackToDefault: fallbackToDefault);
}
public Task<string> GetSettingValueForTenantAsync(string name, int tenantId)
{
return GetSettingValueInternalAsync(name, tenantId);
}
public Task<string> GetSettingValueForTenantAsync(string name, int tenantId, bool fallbackToDefault)
{
return GetSettingValueInternalAsync(name, tenantId, fallbackToDefault: fallbackToDefault);
}
public Task<string> GetSettingValueForUserAsync(string name, int? tenantId, long userId)
{
return GetSettingValueInternalAsync(name, tenantId, userId);
}
public Task<string> GetSettingValueForUserAsync(string name, int? tenantId, long userId, bool fallbackToDefault)
{
return GetSettingValueInternalAsync(name, tenantId, userId, fallbackToDefault);
}
/// <summary>
/// 获取全部设置值
/// </summary>
/// <returns></returns>
public async Task<IReadOnlyList<ISettingValue>> GetAllSettingValuesAsync()
{
return await GetAllSettingValuesAsync(SettingScopes.Application | SettingScopes.Tenant | SettingScopes.User);
}
/// <summary>
/// 获取全部设置值,用户级别覆盖租户级别,租户级别覆盖应用级别,应用级别覆盖默认值
/// </summary>
/// <param name="scopes"></param>
/// <returns></returns>
public async Task<IReadOnlyList<ISettingValue>> GetAllSettingValuesAsync(SettingScopes scopes)
{
var settingDefinitions = new Dictionary<string, SettingDefinition>();
var settingValues = new Dictionary<string, ISettingValue>();
//Fill all setting with default values.
foreach (var setting in _settingDefinitionManager.GetAllSettingDefinitions())
{
settingDefinitions[setting.Name] = setting;
settingValues[setting.Name] = new SettingValueObject(setting.Name, setting.DefaultValue);
}
//Overwrite application settings
if (scopes.HasFlag(SettingScopes.Application))
{
foreach (var settingValue in await GetAllSettingValuesForApplicationAsync())
{
var setting = settingDefinitions.GetOrDefault(settingValue.Name);
//TODO: Conditions get complicated, try to simplify it
if (setting == null || !setting.Scopes.HasFlag(SettingScopes.Application))
{
continue;
}
if (!setting.IsInherited &&
((setting.Scopes.HasFlag(SettingScopes.Tenant) && AbpSession.TenantId.HasValue) || (setting.Scopes.HasFlag(SettingScopes.User) && AbpSession.UserId.HasValue)))
{
continue;
}
settingValues[settingValue.Name] = new SettingValueObject(settingValue.Name, settingValue.Value);
}
}
//Overwrite tenant settings
if (scopes.HasFlag(SettingScopes.Tenant) && AbpSession.TenantId.HasValue)
{
foreach (var settingValue in await GetAllSettingValuesForTenantAsync(AbpSession.TenantId.Value))
{
var setting = settingDefinitions.GetOrDefault(settingValue.Name);
//TODO: Conditions get complicated, try to simplify it
if (setting == null || !setting.Scopes.HasFlag(SettingScopes.Tenant))
{
continue;
}
if (!setting.IsInherited &&
(setting.Scopes.HasFlag(SettingScopes.User) && AbpSession.UserId.HasValue))
{
continue;
}
settingValues[settingValue.Name] = new SettingValueObject(settingValue.Name, settingValue.Value);
}
}
//Overwrite user settings
if (scopes.HasFlag(SettingScopes.User) && AbpSession.UserId.HasValue)
{
foreach (var settingValue in await GetAllSettingValuesForUserAsync(AbpSession.ToUserIdentifier()))
{
var setting = settingDefinitions.GetOrDefault(settingValue.Name);
if (setting != null && setting.Scopes.HasFlag(SettingScopes.User))
{
settingValues[settingValue.Name] = new SettingValueObject(settingValue.Name, settingValue.Value);
}
}
}
return settingValues.Values.ToImmutableList();
}
/// <inheritdoc/>
public async Task<IReadOnlyList<ISettingValue>> GetAllSettingValuesForApplicationAsync()
{
return (await GetApplicationSettingsAsync()).Values
.Select(setting => new SettingValueObject(setting.Name, setting.Value))
.ToImmutableList();
}
/// <inheritdoc/>
public async Task<IReadOnlyList<ISettingValue>> GetAllSettingValuesForTenantAsync(int tenantId)
{
return (await GetReadOnlyTenantSettings(tenantId)).Values
.Select(setting => new SettingValueObject(setting.Name, setting.Value))
.ToImmutableList();
}
/// <inheritdoc/>
public Task<IReadOnlyList<ISettingValue>> GetAllSettingValuesForUserAsync(long userId)
{
return GetAllSettingValuesForUserAsync(new UserIdentifier(AbpSession.TenantId, userId));
}
public async Task<IReadOnlyList<ISettingValue>> GetAllSettingValuesForUserAsync(UserIdentifier user)
{
return (await GetReadOnlyUserSettings(user)).Values
.Select(setting => new SettingValueObject(setting.Name, setting.Value))
.ToImmutableList();
}
/// <summary>
/// 修改应用级别的设置数据
/// </summary>
/// <param name="name"></param>
/// <param name="value"></param>
/// <returns></returns>
[UnitOfWork]
public virtual async Task ChangeSettingForApplicationAsync(string name, string value)
{
await InsertOrUpdateOrDeleteSettingValueAsync(name, value, null, null);
await _applicationSettingCache.RemoveAsync(ApplicationSettingsCacheKey);
}
/// <summary>
/// 修改租户级别的设置数据
/// </summary>
/// <param name="tenantId"></param>
/// <param name="name"></param>
/// <param name="value"></param>
/// <returns></returns>
[UnitOfWork]
public virtual async Task ChangeSettingForTenantAsync(int tenantId, string name, string value)
{
await InsertOrUpdateOrDeleteSettingValueAsync(name, value, tenantId, null);
await _tenantSettingCache.RemoveAsync(tenantId);
}
[UnitOfWork]
public virtual Task ChangeSettingForUserAsync(long userId, string name, string value)
{
return ChangeSettingForUserAsync(new UserIdentifier(AbpSession.TenantId, userId), name, value);
}
/// <summary>
/// 修改用户级别的设置数据
/// </summary>
/// <param name="user"></param>
/// <param name="name"></param>
/// <param name="value"></param>
/// <returns></returns>
public async Task ChangeSettingForUserAsync(UserIdentifier user, string name, string value)
{
await InsertOrUpdateOrDeleteSettingValueAsync(name, value, user.TenantId, user.UserId);
await _userSettingCache.RemoveAsync(user.ToUserIdentifierString());
}
#endregion
#region Private methods
/// <summary>
/// 获取值的主要函数
/// </summary>
/// <param name="name"></param>
/// <param name="tenantId"></param>
/// <param name="userId"></param>
/// <param name="fallbackToDefault"></param>
/// <returns></returns>
private async Task<string> GetSettingValueInternalAsync(string name, int? tenantId = null, long? userId = null, bool fallbackToDefault = true)
{
var settingDefinition = _settingDefinitionManager.GetSettingDefinition(name);
//Get for user if defined
// 获取用户级别的数据
if (settingDefinition.Scopes.HasFlag(SettingScopes.User) && userId.HasValue)
{
var settingValue = await GetSettingValueForUserOrNullAsync(new UserIdentifier(tenantId, userId.Value), name);
if (settingValue != null)
{
return settingValue.Value;
}
if (!fallbackToDefault)
{
return null;
}
if (!settingDefinition.IsInherited)
{
return settingDefinition.DefaultValue;
}
}
//Get for tenant if defined
//获取租户级别的数据
if (settingDefinition.Scopes.HasFlag(SettingScopes.Tenant) && tenantId.HasValue)
{
var settingValue = await GetSettingValueForTenantOrNullAsync(tenantId.Value, name);
if (settingValue != null)
{
return settingValue.Value;
}
if (!fallbackToDefault)
{
return null;
}
if (!settingDefinition.IsInherited)
{
return settingDefinition.DefaultValue;
}
}
//Get for application if defined
// 获取应用级别的数据
if (settingDefinition.Scopes.HasFlag(SettingScopes.Application))
{
var settingValue = await GetSettingValueForApplicationOrNullAsync(name);
if (settingValue != null)
{
return settingValue.Value;
}
if (!fallbackToDefault)
{
return null;
}
}
//Not defined, get default value
//获取默认值
return settingDefinition.DefaultValue;
}
/// <summary>
/// 插入/更新/删除设置值
/// </summary>
/// <param name="name"></param>
/// <param name="value"></param>
/// <param name="tenantId"></param>
/// <param name="userId"></param>
/// <returns></returns>
private async Task<SettingInfo> InsertOrUpdateOrDeleteSettingValueAsync(string name, string value, int? tenantId, long? userId)
{
var settingDefinition = _settingDefinitionManager.GetSettingDefinition(name);
var settingValue = await SettingStore.GetSettingOrNullAsync(tenantId, userId, name);
//Determine defaultValue
var defaultValue = settingDefinition.DefaultValue;
// 只有定义为继承的才生效
if (settingDefinition.IsInherited)
{
//For Tenant and User, Application's value overrides Setting Definition's default value.
if (tenantId.HasValue || userId.HasValue)
{
var applicationValue = await GetSettingValueForApplicationOrNullAsync(name);
if (applicationValue != null)
{
defaultValue = applicationValue.Value;
}
}
//For User, Tenants's value overrides Application's default value.
if (userId.HasValue && tenantId.HasValue)
{
var tenantValue = await GetSettingValueForTenantOrNullAsync(tenantId.Value, name);
if (tenantValue != null)
{
defaultValue = tenantValue.Value;
}
}
}
//No need to store on database if the value is the default value
if (value == defaultValue)
{
if (settingValue != null)
{
await SettingStore.DeleteAsync(settingValue);
}
return null;
}
//If it's not default value and not stored on database, then insert it
if (settingValue == null)
{
settingValue = new SettingInfo
{
TenantId = tenantId,
UserId = userId,
Name = name,
Value = value
};
await SettingStore.CreateAsync(settingValue);
return settingValue;
}
//It's same value in database, no need to update
if (settingValue.Value == value)
{
return settingValue;
}
//Update the setting on database.
settingValue.Value = value;
await SettingStore.UpdateAsync(settingValue);
return settingValue;
}
private async Task<SettingInfo> GetSettingValueForApplicationOrNullAsync(string name)
{
return (await GetApplicationSettingsAsync()).GetOrDefault(name);
}
private async Task<SettingInfo> GetSettingValueForTenantOrNullAsync(int tenantId, string name)
{
return (await GetReadOnlyTenantSettings(tenantId)).GetOrDefault(name);
}
private async Task<SettingInfo> GetSettingValueForUserOrNullAsync(UserIdentifier user, string name)
{
return (await GetReadOnlyUserSettings(user)).GetOrDefault(name);
}
private async Task<Dictionary<string, SettingInfo>> GetApplicationSettingsAsync()
{
return await _applicationSettingCache.GetAsync(ApplicationSettingsCacheKey, async () =>
{
var dictionary = new Dictionary<string, SettingInfo>();
var settingValues = await SettingStore.GetAllListAsync(null, null);
foreach (var settingValue in settingValues)
{
dictionary[settingValue.Name] = settingValue;
}
return dictionary;
});
}
private async Task<ImmutableDictionary<string, SettingInfo>> GetReadOnlyTenantSettings(int tenantId)
{
var cachedDictionary = await GetTenantSettingsFromCache(tenantId);
lock (cachedDictionary)
{
return cachedDictionary.ToImmutableDictionary();
}
}
private async Task<ImmutableDictionary<string, SettingInfo>> GetReadOnlyUserSettings(UserIdentifier user)
{
var cachedDictionary = await GetUserSettingsFromCache(user);
lock (cachedDictionary)
{
return cachedDictionary.ToImmutableDictionary();
}
}
private async Task<Dictionary<string, SettingInfo>> GetTenantSettingsFromCache(int tenantId)
{
return await _tenantSettingCache.GetAsync(
tenantId,
async () =>
{
var dictionary = new Dictionary<string, SettingInfo>();
var settingValues = await SettingStore.GetAllListAsync(tenantId, null);
foreach (var settingValue in settingValues)
{
dictionary[settingValue.Name] = settingValue;
}
return dictionary;
});
}
private async Task<Dictionary<string, SettingInfo>> GetUserSettingsFromCache(UserIdentifier user)
{
return await _userSettingCache.GetAsync(
user.ToUserIdentifierString(),
async () =>
{
var dictionary = new Dictionary<string, SettingInfo>();
var settingValues = await SettingStore.GetAllListAsync(user.TenantId, user.UserId);
foreach (var settingValue in settingValues)
{
dictionary[settingValue.Name] = settingValue;
}
return dictionary;
});
}
public Task<string> GetSettingValueForUserAsync(string name, UserIdentifier user)
{
Check.NotNull(name, nameof(name));
Check.NotNull(user, nameof(user));
return GetSettingValueForUserAsync(name, user.TenantId, user.UserId);
}
#endregion
#region Nested classes
private class SettingValueObject : ISettingValue
{
public string Name { get; private set; }
public string Value { get; private set; }
public SettingValueObject(string name, string value)
{
Value = value;
Name = name;
}
}
#endregion
}
获取设置值
获取设置的值主要是方法GetSettingValueInternalAsync
,在这个方法内根据设置范围取值
/// <summary>
/// 获取值的主要函数
/// </summary>
/// <param name="name"></param>
/// <param name="tenantId"></param>
/// <param name="userId"></param>
/// <param name="fallbackToDefault"></param>
/// <returns></returns>
private async Task<string> GetSettingValueInternalAsync(string name, int? tenantId = null, long? userId = null, bool fallbackToDefault = true)
{
var settingDefinition = _settingDefinitionManager.GetSettingDefinition(name);
//Get for user if defined
// 获取用户级别的数据
if (settingDefinition.Scopes.HasFlag(SettingScopes.User) && userId.HasValue)
{
var settingValue = await GetSettingValueForUserOrNullAsync(new UserIdentifier(tenantId, userId.Value), name);
if (settingValue != null)
{
return settingValue.Value;
}
if (!fallbackToDefault)
{
return null;
}
if (!settingDefinition.IsInherited)
{
return settingDefinition.DefaultValue;
}
}
//Get for tenant if defined
//获取租户级别的数据
if (settingDefinition.Scopes.HasFlag(SettingScopes.Tenant) && tenantId.HasValue)
{
var settingValue = await GetSettingValueForTenantOrNullAsync(tenantId.Value, name);
if (settingValue != null)
{
return settingValue.Value;
}
if (!fallbackToDefault)
{
return null;
}
if (!settingDefinition.IsInherited)
{
return settingDefinition.DefaultValue;
}
}
//Get for application if defined
// 获取应用级别的数据
if (settingDefinition.Scopes.HasFlag(SettingScopes.Application))
{
var settingValue = await GetSettingValueForApplicationOrNullAsync(name);
if (settingValue != null)
{
return settingValue.Value;
}
if (!fallbackToDefault)
{
return null;
}
}
//Not defined, get default value
//获取默认值
return settingDefinition.DefaultValue;
}
获取全部设置值
按范围覆盖设置值
/// <summary>
/// 获取全部设置值,用户级别覆盖租户级别,租户级别覆盖应用级别,应用级别覆盖默认值
/// </summary>
/// <param name="scopes"></param>
/// <returns></returns>
public async Task<IReadOnlyList<ISettingValue>> GetAllSettingValuesAsync(SettingScopes scopes)
{
var settingDefinitions = new Dictionary<string, SettingDefinition>();
var settingValues = new Dictionary<string, ISettingValue>();
//Fill all setting with default values.
foreach (var setting in _settingDefinitionManager.GetAllSettingDefinitions())
{
settingDefinitions[setting.Name] = setting;
settingValues[setting.Name] = new SettingValueObject(setting.Name, setting.DefaultValue);
}
//Overwrite application settings
if (scopes.HasFlag(SettingScopes.Application))
{
foreach (var settingValue in await GetAllSettingValuesForApplicationAsync())
{
var setting = settingDefinitions.GetOrDefault(settingValue.Name);
//TODO: Conditions get complicated, try to simplify it
if (setting == null || !setting.Scopes.HasFlag(SettingScopes.Application))
{
continue;
}
if (!setting.IsInherited &&
((setting.Scopes.HasFlag(SettingScopes.Tenant) && AbpSession.TenantId.HasValue) || (setting.Scopes.HasFlag(SettingScopes.User) && AbpSession.UserId.HasValue)))
{
continue;
}
settingValues[settingValue.Name] = new SettingValueObject(settingValue.Name, settingValue.Value);
}
}
//Overwrite tenant settings
if (scopes.HasFlag(SettingScopes.Tenant) && AbpSession.TenantId.HasValue)
{
foreach (var settingValue in await GetAllSettingValuesForTenantAsync(AbpSession.TenantId.Value))
{
var setting = settingDefinitions.GetOrDefault(settingValue.Name);
//TODO: Conditions get complicated, try to simplify it
if (setting == null || !setting.Scopes.HasFlag(SettingScopes.Tenant))
{
continue;
}
if (!setting.IsInherited &&
(setting.Scopes.HasFlag(SettingScopes.User) && AbpSession.UserId.HasValue))
{
continue;
}
settingValues[settingValue.Name] = new SettingValueObject(settingValue.Name, settingValue.Value);
}
}
//Overwrite user settings
if (scopes.HasFlag(SettingScopes.User) && AbpSession.UserId.HasValue)
{
foreach (var settingValue in await GetAllSettingValuesForUserAsync(AbpSession.ToUserIdentifier()))
{
var setting = settingDefinitions.GetOrDefault(settingValue.Name);
if (setting != null && setting.Scopes.HasFlag(SettingScopes.User))
{
settingValues[settingValue.Name] = new SettingValueObject(settingValue.Name, settingValue.Value);
}
}
}
return settingValues.Values.ToImmutableList();
}
更新设置值
更新设置主要将设置值数据保存到数据库
- 如果设置的值等于默认值,则从数据库中删除数据
- 如果数据库中没有数据,则插入
- 如果数据库中有数据并且只不等于默认值,则更新数据库数据
/// <summary>
/// 插入/更新/删除设置值
/// </summary>
/// <param name="name"></param>
/// <param name="value"></param>
/// <param name="tenantId"></param>
/// <param name="userId"></param>
/// <returns></returns>
private async Task<SettingInfo> InsertOrUpdateOrDeleteSettingValueAsync(string name, string value, int? tenantId, long? userId)
{
var settingDefinition = _settingDefinitionManager.GetSettingDefinition(name);
var settingValue = await SettingStore.GetSettingOrNullAsync(tenantId, userId, name);
//Determine defaultValue
var defaultValue = settingDefinition.DefaultValue;
// 只有定义为继承的才生效
if (settingDefinition.IsInherited)
{
//For Tenant and User, Application's value overrides Setting Definition's default value.
if (tenantId.HasValue || userId.HasValue)
{
var applicationValue = await GetSettingValueForApplicationOrNullAsync(name);
if (applicationValue != null)
{
defaultValue = applicationValue.Value;
}
}
//For User, Tenants's value overrides Application's default value.
if (userId.HasValue && tenantId.HasValue)
{
var tenantValue = await GetSettingValueForTenantOrNullAsync(tenantId.Value, name);
if (tenantValue != null)
{
defaultValue = tenantValue.Value;
}
}
}
//No need to store on database if the value is the default value
if (value == defaultValue)
{
if (settingValue != null)
{
await SettingStore.DeleteAsync(settingValue);
}
return null;
}
//If it's not default value and not stored on database, then insert it
if (settingValue == null)
{
settingValue = new SettingInfo
{
TenantId = tenantId,
UserId = userId,
Name = name,
Value = value
};
await SettingStore.CreateAsync(settingValue);
return settingValue;
}
//It's same value in database, no need to update
if (settingValue.Value == value)
{
return settingValue;
}
//Update the setting on database.
settingValue.Value = value;
await SettingStore.UpdateAsync(settingValue);
return settingValue;
}
设计模式
- 提供者模式:
SettingProvider
- 外观模式:
ISettingManager
、SettingManager
总结
提供者模式和外观模式我认为是ABP中两个最核心的模式,很多功能都是基于这两个模式进行扩展和编码,如:设置功能、菜单功能、特性功能、组织单元功能等等,分析到具体功能我们可以再和设置功能来比较。
我的公众号
网友评论