using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using System.Threading.Tasks;
using Abp.Collections.Extensions;
using Abp.Dependency;
using Abp.Domain.Uow;
using Abp.Runtime.Caching;
using Abp.Runtime.Session;
namespace Abp.Configuration
{
///
/// This class implements to manage setting values in the database.
///
public class SettingManager : ISettingManager, ISingletonDependency
{
public const string ApplicationSettingsCacheKey = "ApplicationSettings";
///
/// Reference to the current Session.
///
public IAbpSession AbpSession { get; set; }
///
/// Reference to the setting store.
///
public ISettingStore SettingStore { get; set; }
private readonly ISettingDefinitionManager _settingDefinitionManager;
private readonly ITypedCache> _applicationSettingCache;
private readonly ITypedCache> _tenantSettingCache;
private readonly ITypedCache> _userSettingCache;
///
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
///
public Task GetSettingValueAsync(string name)
{
return GetSettingValueInternalAsync(name, AbpSession.TenantId, AbpSession.UserId);
}
public Task GetSettingValueForApplicationAsync(string name)
{
return GetSettingValueInternalAsync(name);
}
public Task GetSettingValueForApplicationAsync(string name, bool fallbackToDefault)
{
return GetSettingValueInternalAsync(name, fallbackToDefault: fallbackToDefault);
}
public Task GetSettingValueForTenantAsync(string name, int tenantId)
{
return GetSettingValueInternalAsync(name, tenantId);
}
public Task GetSettingValueForTenantAsync(string name, int tenantId, bool fallbackToDefault)
{
return GetSettingValueInternalAsync(name, tenantId, fallbackToDefault: fallbackToDefault);
}
public Task GetSettingValueForUserAsync(string name, int? tenantId, long userId)
{
return GetSettingValueInternalAsync(name, tenantId, userId);
}
public Task GetSettingValueForUserAsync(string name, int? tenantId, long userId, bool fallbackToDefault)
{
return GetSettingValueInternalAsync(name, tenantId, userId, fallbackToDefault);
}
public async Task> GetAllSettingValuesAsync()
{
return await GetAllSettingValuesAsync(SettingScopes.Application | SettingScopes.Tenant | SettingScopes.User);
}
///
public async Task> GetAllSettingValuesAsync(SettingScopes scopes)
{
var settingDefinitions = new Dictionary();
var settingValues = new Dictionary();
//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();
}
///
public async Task> GetAllSettingValuesForApplicationAsync()
{
return (await GetApplicationSettingsAsync()).Values
.Select(setting => new SettingValueObject(setting.Name, setting.Value))
.ToImmutableList();
}
///
public async Task> GetAllSettingValuesForTenantAsync(int tenantId)
{
return (await GetReadOnlyTenantSettings(tenantId)).Values
.Select(setting => new SettingValueObject(setting.Name, setting.Value))
.ToImmutableList();
}
///
public Task> GetAllSettingValuesForUserAsync(long userId)
{
return GetAllSettingValuesForUserAsync(new UserIdentifier(AbpSession.TenantId, userId));
}
public async Task> GetAllSettingValuesForUserAsync(UserIdentifier user)
{
return (await GetReadOnlyUserSettings(user)).Values
.Select(setting => new SettingValueObject(setting.Name, setting.Value))
.ToImmutableList();
}
///
[UnitOfWork]
public virtual async Task ChangeSettingForApplicationAsync(string name, string value)
{
await InsertOrUpdateOrDeleteSettingValueAsync(name, value, null, null);
await _applicationSettingCache.RemoveAsync(ApplicationSettingsCacheKey);
}
///
[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);
}
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
private async Task 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;
}
private async Task 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 GetSettingValueForApplicationOrNullAsync(string name)
{
return (await GetApplicationSettingsAsync()).GetOrDefault(name);
}
private async Task GetSettingValueForTenantOrNullAsync(int tenantId, string name)
{
return (await GetReadOnlyTenantSettings(tenantId)).GetOrDefault(name);
}
private async Task GetSettingValueForUserOrNullAsync(UserIdentifier user, string name)
{
return (await GetReadOnlyUserSettings(user)).GetOrDefault(name);
}
private async Task> GetApplicationSettingsAsync()
{
return await _applicationSettingCache.GetAsync(ApplicationSettingsCacheKey, async () =>
{
var dictionary = new Dictionary();
var settingValues = await SettingStore.GetAllListAsync(null, null);
foreach (var settingValue in settingValues)
{
dictionary[settingValue.Name] = settingValue;
}
return dictionary;
});
}
private async Task> GetReadOnlyTenantSettings(int tenantId)
{
var cachedDictionary = await GetTenantSettingsFromCache(tenantId);
lock (cachedDictionary)
{
return cachedDictionary.ToImmutableDictionary();
}
}
private async Task> GetReadOnlyUserSettings(UserIdentifier user)
{
var cachedDictionary = await GetUserSettingsFromCache(user);
lock (cachedDictionary)
{
return cachedDictionary.ToImmutableDictionary();
}
}
private async Task> GetTenantSettingsFromCache(int tenantId)
{
return await _tenantSettingCache.GetAsync(
tenantId,
async () =>
{
var dictionary = new Dictionary();
var settingValues = await SettingStore.GetAllListAsync(tenantId, null);
foreach (var settingValue in settingValues)
{
dictionary[settingValue.Name] = settingValue;
}
return dictionary;
});
}
private async Task> GetUserSettingsFromCache(UserIdentifier user)
{
return await _userSettingCache.GetAsync(
user.ToUserIdentifierString(),
async () =>
{
var dictionary = new Dictionary();
var settingValues = await SettingStore.GetAllListAsync(user.TenantId, user.UserId);
foreach (var settingValue in settingValues)
{
dictionary[settingValue.Name] = settingValue;
}
return dictionary;
});
}
public Task 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
}
}