SettingManager.cs 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473
  1. using System.Collections.Generic;
  2. using System.Collections.Immutable;
  3. using System.Linq;
  4. using System.Threading.Tasks;
  5. using Abp.Collections.Extensions;
  6. using Abp.Dependency;
  7. using Abp.Domain.Uow;
  8. using Abp.Runtime.Caching;
  9. using Abp.Runtime.Session;
  10. namespace Abp.Configuration
  11. {
  12. /// <summary>
  13. /// This class implements <see cref="ISettingManager"/> to manage setting values in the database.
  14. /// </summary>
  15. public class SettingManager : ISettingManager, ISingletonDependency
  16. {
  17. public const string ApplicationSettingsCacheKey = "ApplicationSettings";
  18. /// <summary>
  19. /// Reference to the current Session.
  20. /// </summary>
  21. public IAbpSession AbpSession { get; set; }
  22. /// <summary>
  23. /// Reference to the setting store.
  24. /// </summary>
  25. public ISettingStore SettingStore { get; set; }
  26. private readonly ISettingDefinitionManager _settingDefinitionManager;
  27. private readonly ITypedCache<string, Dictionary<string, SettingInfo>> _applicationSettingCache;
  28. private readonly ITypedCache<int, Dictionary<string, SettingInfo>> _tenantSettingCache;
  29. private readonly ITypedCache<string, Dictionary<string, SettingInfo>> _userSettingCache;
  30. /// <inheritdoc/>
  31. public SettingManager(ISettingDefinitionManager settingDefinitionManager, ICacheManager cacheManager)
  32. {
  33. _settingDefinitionManager = settingDefinitionManager;
  34. AbpSession = NullAbpSession.Instance;
  35. SettingStore = DefaultConfigSettingStore.Instance;
  36. _applicationSettingCache = cacheManager.GetApplicationSettingsCache();
  37. _tenantSettingCache = cacheManager.GetTenantSettingsCache();
  38. _userSettingCache = cacheManager.GetUserSettingsCache();
  39. }
  40. #region Public methods
  41. /// <inheritdoc/>
  42. public Task<string> GetSettingValueAsync(string name)
  43. {
  44. return GetSettingValueInternalAsync(name, AbpSession.TenantId, AbpSession.UserId);
  45. }
  46. public Task<string> GetSettingValueForApplicationAsync(string name)
  47. {
  48. return GetSettingValueInternalAsync(name);
  49. }
  50. public Task<string> GetSettingValueForApplicationAsync(string name, bool fallbackToDefault)
  51. {
  52. return GetSettingValueInternalAsync(name, fallbackToDefault: fallbackToDefault);
  53. }
  54. public Task<string> GetSettingValueForTenantAsync(string name, int tenantId)
  55. {
  56. return GetSettingValueInternalAsync(name, tenantId);
  57. }
  58. public Task<string> GetSettingValueForTenantAsync(string name, int tenantId, bool fallbackToDefault)
  59. {
  60. return GetSettingValueInternalAsync(name, tenantId, fallbackToDefault: fallbackToDefault);
  61. }
  62. public Task<string> GetSettingValueForUserAsync(string name, int? tenantId, long userId)
  63. {
  64. return GetSettingValueInternalAsync(name, tenantId, userId);
  65. }
  66. public Task<string> GetSettingValueForUserAsync(string name, int? tenantId, long userId, bool fallbackToDefault)
  67. {
  68. return GetSettingValueInternalAsync(name, tenantId, userId, fallbackToDefault);
  69. }
  70. public async Task<IReadOnlyList<ISettingValue>> GetAllSettingValuesAsync()
  71. {
  72. return await GetAllSettingValuesAsync(SettingScopes.Application | SettingScopes.Tenant | SettingScopes.User);
  73. }
  74. /// <inheritdoc/>
  75. public async Task<IReadOnlyList<ISettingValue>> GetAllSettingValuesAsync(SettingScopes scopes)
  76. {
  77. var settingDefinitions = new Dictionary<string, SettingDefinition>();
  78. var settingValues = new Dictionary<string, ISettingValue>();
  79. //Fill all setting with default values.
  80. foreach (var setting in _settingDefinitionManager.GetAllSettingDefinitions())
  81. {
  82. settingDefinitions[setting.Name] = setting;
  83. settingValues[setting.Name] = new SettingValueObject(setting.Name, setting.DefaultValue);
  84. }
  85. //Overwrite application settings
  86. if (scopes.HasFlag(SettingScopes.Application))
  87. {
  88. foreach (var settingValue in await GetAllSettingValuesForApplicationAsync())
  89. {
  90. var setting = settingDefinitions.GetOrDefault(settingValue.Name);
  91. //TODO: Conditions get complicated, try to simplify it
  92. if (setting == null || !setting.Scopes.HasFlag(SettingScopes.Application))
  93. {
  94. continue;
  95. }
  96. if (!setting.IsInherited &&
  97. ((setting.Scopes.HasFlag(SettingScopes.Tenant) && AbpSession.TenantId.HasValue) || (setting.Scopes.HasFlag(SettingScopes.User) && AbpSession.UserId.HasValue)))
  98. {
  99. continue;
  100. }
  101. settingValues[settingValue.Name] = new SettingValueObject(settingValue.Name, settingValue.Value);
  102. }
  103. }
  104. //Overwrite tenant settings
  105. if (scopes.HasFlag(SettingScopes.Tenant) && AbpSession.TenantId.HasValue)
  106. {
  107. foreach (var settingValue in await GetAllSettingValuesForTenantAsync(AbpSession.TenantId.Value))
  108. {
  109. var setting = settingDefinitions.GetOrDefault(settingValue.Name);
  110. //TODO: Conditions get complicated, try to simplify it
  111. if (setting == null || !setting.Scopes.HasFlag(SettingScopes.Tenant))
  112. {
  113. continue;
  114. }
  115. if (!setting.IsInherited &&
  116. (setting.Scopes.HasFlag(SettingScopes.User) && AbpSession.UserId.HasValue))
  117. {
  118. continue;
  119. }
  120. settingValues[settingValue.Name] = new SettingValueObject(settingValue.Name, settingValue.Value);
  121. }
  122. }
  123. //Overwrite user settings
  124. if (scopes.HasFlag(SettingScopes.User) && AbpSession.UserId.HasValue)
  125. {
  126. foreach (var settingValue in await GetAllSettingValuesForUserAsync(AbpSession.ToUserIdentifier()))
  127. {
  128. var setting = settingDefinitions.GetOrDefault(settingValue.Name);
  129. if (setting != null && setting.Scopes.HasFlag(SettingScopes.User))
  130. {
  131. settingValues[settingValue.Name] = new SettingValueObject(settingValue.Name, settingValue.Value);
  132. }
  133. }
  134. }
  135. return settingValues.Values.ToImmutableList();
  136. }
  137. /// <inheritdoc/>
  138. public async Task<IReadOnlyList<ISettingValue>> GetAllSettingValuesForApplicationAsync()
  139. {
  140. return (await GetApplicationSettingsAsync()).Values
  141. .Select(setting => new SettingValueObject(setting.Name, setting.Value))
  142. .ToImmutableList();
  143. }
  144. /// <inheritdoc/>
  145. public async Task<IReadOnlyList<ISettingValue>> GetAllSettingValuesForTenantAsync(int tenantId)
  146. {
  147. return (await GetReadOnlyTenantSettings(tenantId)).Values
  148. .Select(setting => new SettingValueObject(setting.Name, setting.Value))
  149. .ToImmutableList();
  150. }
  151. /// <inheritdoc/>
  152. public Task<IReadOnlyList<ISettingValue>> GetAllSettingValuesForUserAsync(long userId)
  153. {
  154. return GetAllSettingValuesForUserAsync(new UserIdentifier(AbpSession.TenantId, userId));
  155. }
  156. public async Task<IReadOnlyList<ISettingValue>> GetAllSettingValuesForUserAsync(UserIdentifier user)
  157. {
  158. return (await GetReadOnlyUserSettings(user)).Values
  159. .Select(setting => new SettingValueObject(setting.Name, setting.Value))
  160. .ToImmutableList();
  161. }
  162. /// <inheritdoc/>
  163. [UnitOfWork]
  164. public virtual async Task ChangeSettingForApplicationAsync(string name, string value)
  165. {
  166. await InsertOrUpdateOrDeleteSettingValueAsync(name, value, null, null);
  167. await _applicationSettingCache.RemoveAsync(ApplicationSettingsCacheKey);
  168. }
  169. /// <inheritdoc/>
  170. [UnitOfWork]
  171. public virtual async Task ChangeSettingForTenantAsync(int tenantId, string name, string value)
  172. {
  173. await InsertOrUpdateOrDeleteSettingValueAsync(name, value, tenantId, null);
  174. await _tenantSettingCache.RemoveAsync(tenantId);
  175. }
  176. /// <inheritdoc/>
  177. [UnitOfWork]
  178. public virtual Task ChangeSettingForUserAsync(long userId, string name, string value)
  179. {
  180. return ChangeSettingForUserAsync(new UserIdentifier(AbpSession.TenantId, userId), name, value);
  181. }
  182. public async Task ChangeSettingForUserAsync(UserIdentifier user, string name, string value)
  183. {
  184. await InsertOrUpdateOrDeleteSettingValueAsync(name, value, user.TenantId, user.UserId);
  185. await _userSettingCache.RemoveAsync(user.ToUserIdentifierString());
  186. }
  187. #endregion
  188. #region Private methods
  189. private async Task<string> GetSettingValueInternalAsync(string name, int? tenantId = null, long? userId = null, bool fallbackToDefault = true)
  190. {
  191. var settingDefinition = _settingDefinitionManager.GetSettingDefinition(name);
  192. //Get for user if defined
  193. if (settingDefinition.Scopes.HasFlag(SettingScopes.User) && userId.HasValue)
  194. {
  195. var settingValue = await GetSettingValueForUserOrNullAsync(new UserIdentifier(tenantId, userId.Value), name);
  196. if (settingValue != null)
  197. {
  198. return settingValue.Value;
  199. }
  200. if (!fallbackToDefault)
  201. {
  202. return null;
  203. }
  204. if (!settingDefinition.IsInherited)
  205. {
  206. return settingDefinition.DefaultValue;
  207. }
  208. }
  209. //Get for tenant if defined
  210. if (settingDefinition.Scopes.HasFlag(SettingScopes.Tenant) && tenantId.HasValue)
  211. {
  212. var settingValue = await GetSettingValueForTenantOrNullAsync(tenantId.Value, name);
  213. if (settingValue != null)
  214. {
  215. return settingValue.Value;
  216. }
  217. if (!fallbackToDefault)
  218. {
  219. return null;
  220. }
  221. if (!settingDefinition.IsInherited)
  222. {
  223. return settingDefinition.DefaultValue;
  224. }
  225. }
  226. //Get for application if defined
  227. if (settingDefinition.Scopes.HasFlag(SettingScopes.Application))
  228. {
  229. var settingValue = await GetSettingValueForApplicationOrNullAsync(name);
  230. if (settingValue != null)
  231. {
  232. return settingValue.Value;
  233. }
  234. if (!fallbackToDefault)
  235. {
  236. return null;
  237. }
  238. }
  239. //Not defined, get default value
  240. return settingDefinition.DefaultValue;
  241. }
  242. private async Task<SettingInfo> InsertOrUpdateOrDeleteSettingValueAsync(string name, string value, int? tenantId, long? userId)
  243. {
  244. var settingDefinition = _settingDefinitionManager.GetSettingDefinition(name);
  245. var settingValue = await SettingStore.GetSettingOrNullAsync(tenantId, userId, name);
  246. //Determine defaultValue
  247. var defaultValue = settingDefinition.DefaultValue;
  248. if (settingDefinition.IsInherited)
  249. {
  250. //For Tenant and User, Application's value overrides Setting Definition's default value.
  251. if (tenantId.HasValue || userId.HasValue)
  252. {
  253. var applicationValue = await GetSettingValueForApplicationOrNullAsync(name);
  254. if (applicationValue != null)
  255. {
  256. defaultValue = applicationValue.Value;
  257. }
  258. }
  259. //For User, Tenants's value overrides Application's default value.
  260. if (userId.HasValue && tenantId.HasValue)
  261. {
  262. var tenantValue = await GetSettingValueForTenantOrNullAsync(tenantId.Value, name);
  263. if (tenantValue != null)
  264. {
  265. defaultValue = tenantValue.Value;
  266. }
  267. }
  268. }
  269. //No need to store on database if the value is the default value
  270. if (value == defaultValue)
  271. {
  272. if (settingValue != null)
  273. {
  274. await SettingStore.DeleteAsync(settingValue);
  275. }
  276. return null;
  277. }
  278. //If it's not default value and not stored on database, then insert it
  279. if (settingValue == null)
  280. {
  281. settingValue = new SettingInfo
  282. {
  283. TenantId = tenantId,
  284. UserId = userId,
  285. Name = name,
  286. Value = value
  287. };
  288. await SettingStore.CreateAsync(settingValue);
  289. return settingValue;
  290. }
  291. //It's same value in database, no need to update
  292. if (settingValue.Value == value)
  293. {
  294. return settingValue;
  295. }
  296. //Update the setting on database.
  297. settingValue.Value = value;
  298. await SettingStore.UpdateAsync(settingValue);
  299. return settingValue;
  300. }
  301. private async Task<SettingInfo> GetSettingValueForApplicationOrNullAsync(string name)
  302. {
  303. return (await GetApplicationSettingsAsync()).GetOrDefault(name);
  304. }
  305. private async Task<SettingInfo> GetSettingValueForTenantOrNullAsync(int tenantId, string name)
  306. {
  307. return (await GetReadOnlyTenantSettings(tenantId)).GetOrDefault(name);
  308. }
  309. private async Task<SettingInfo> GetSettingValueForUserOrNullAsync(UserIdentifier user, string name)
  310. {
  311. return (await GetReadOnlyUserSettings(user)).GetOrDefault(name);
  312. }
  313. private async Task<Dictionary<string, SettingInfo>> GetApplicationSettingsAsync()
  314. {
  315. return await _applicationSettingCache.GetAsync(ApplicationSettingsCacheKey, async () =>
  316. {
  317. var dictionary = new Dictionary<string, SettingInfo>();
  318. var settingValues = await SettingStore.GetAllListAsync(null, null);
  319. foreach (var settingValue in settingValues)
  320. {
  321. dictionary[settingValue.Name] = settingValue;
  322. }
  323. return dictionary;
  324. });
  325. }
  326. private async Task<ImmutableDictionary<string, SettingInfo>> GetReadOnlyTenantSettings(int tenantId)
  327. {
  328. var cachedDictionary = await GetTenantSettingsFromCache(tenantId);
  329. lock (cachedDictionary)
  330. {
  331. return cachedDictionary.ToImmutableDictionary();
  332. }
  333. }
  334. private async Task<ImmutableDictionary<string, SettingInfo>> GetReadOnlyUserSettings(UserIdentifier user)
  335. {
  336. var cachedDictionary = await GetUserSettingsFromCache(user);
  337. lock (cachedDictionary)
  338. {
  339. return cachedDictionary.ToImmutableDictionary();
  340. }
  341. }
  342. private async Task<Dictionary<string, SettingInfo>> GetTenantSettingsFromCache(int tenantId)
  343. {
  344. return await _tenantSettingCache.GetAsync(
  345. tenantId,
  346. async () =>
  347. {
  348. var dictionary = new Dictionary<string, SettingInfo>();
  349. var settingValues = await SettingStore.GetAllListAsync(tenantId, null);
  350. foreach (var settingValue in settingValues)
  351. {
  352. dictionary[settingValue.Name] = settingValue;
  353. }
  354. return dictionary;
  355. });
  356. }
  357. private async Task<Dictionary<string, SettingInfo>> GetUserSettingsFromCache(UserIdentifier user)
  358. {
  359. return await _userSettingCache.GetAsync(
  360. user.ToUserIdentifierString(),
  361. async () =>
  362. {
  363. var dictionary = new Dictionary<string, SettingInfo>();
  364. var settingValues = await SettingStore.GetAllListAsync(user.TenantId, user.UserId);
  365. foreach (var settingValue in settingValues)
  366. {
  367. dictionary[settingValue.Name] = settingValue;
  368. }
  369. return dictionary;
  370. });
  371. }
  372. public Task<string> GetSettingValueForUserAsync(string name, UserIdentifier user)
  373. {
  374. Check.NotNull(name, nameof(name));
  375. Check.NotNull(user, nameof(user));
  376. return GetSettingValueForUserAsync(name, user.TenantId, user.UserId);
  377. }
  378. #endregion
  379. #region Nested classes
  380. private class SettingValueObject : ISettingValue
  381. {
  382. public string Name { get; private set; }
  383. public string Value { get; private set; }
  384. public SettingValueObject(string name, string value)
  385. {
  386. Value = value;
  387. Name = name;
  388. }
  389. }
  390. #endregion
  391. }
  392. }