From f47e3deee9fe2156c5e09434cfc2dbdda8ad45ec Mon Sep 17 00:00:00 2001 From: TheXamlGuy Date: Mon, 7 Oct 2024 23:12:22 +0100 Subject: [PATCH] Fixed issue where singleton configuration cache was blocking creation of new components --- Toolkit.Foundation/ComponentBuilder.cs | 6 +-- Toolkit.Foundation/ConfigurationCache.cs | 11 ++-- Toolkit.Foundation/ConfigurationMonitor.cs | 3 +- Toolkit.Foundation/ConfigurationSource.cs | 59 ++++++++------------- Toolkit.Foundation/IConfigurationCache.cs | 9 ++++ Toolkit.Foundation/IHostBuilderExtension.cs | 16 +++--- 6 files changed, 51 insertions(+), 53 deletions(-) create mode 100644 Toolkit.Foundation/IConfigurationCache.cs diff --git a/Toolkit.Foundation/ComponentBuilder.cs b/Toolkit.Foundation/ComponentBuilder.cs index 6e4f2df..78791a3 100644 --- a/Toolkit.Foundation/ComponentBuilder.cs +++ b/Toolkit.Foundation/ComponentBuilder.cs @@ -68,8 +68,7 @@ public class ComponentBuilder : where TConfiguration : class, new() { - hostBuilder.AddConfiguration(section: section, path: ConfigurationFile, - defaultConfiguration: configuration); + hostBuilder.AddConfiguration(section, ConfigurationFile, configuration); return this; } @@ -90,7 +89,8 @@ public class ComponentBuilder : public IComponentHost Build() { - hostBuilder.UseContentRoot(ContentRoot, true) + hostBuilder + .UseContentRoot(ContentRoot, true) .ConfigureAppConfiguration(config => { config.AddJsonFile(ConfigurationFile, true, true); diff --git a/Toolkit.Foundation/ConfigurationCache.cs b/Toolkit.Foundation/ConfigurationCache.cs index e96cbd2..70f05d7 100644 --- a/Toolkit.Foundation/ConfigurationCache.cs +++ b/Toolkit.Foundation/ConfigurationCache.cs @@ -2,16 +2,17 @@ namespace Toolkit.Foundation; -public static class ConfigurationCache +public class ConfigurationCache : + IConfigurationCache { - private static readonly ConcurrentDictionary cache = new(); + private readonly ConcurrentDictionary cache = new(); - public static void Set(string section, + public void Set(string section, TConfiguration configuration) => cache[section] = configuration; - public static bool Remove(string section) => cache.TryRemove(section, out _); + public bool Remove(string section) => cache.TryRemove(section, out _); - public static bool TryGet(string section, + public bool TryGet(string section, out TConfiguration? configuration) { if (cache.TryGetValue(section, out object? cachedValue)) diff --git a/Toolkit.Foundation/ConfigurationMonitor.cs b/Toolkit.Foundation/ConfigurationMonitor.cs index 20add1a..ccbb85b 100644 --- a/Toolkit.Foundation/ConfigurationMonitor.cs +++ b/Toolkit.Foundation/ConfigurationMonitor.cs @@ -3,6 +3,7 @@ namespace Toolkit.Foundation; public class ConfigurationMonitor(string section, + IConfigurationCache cache, IConfigurationFile file, IServiceProvider serviceProvider, IPublisher publisher) : @@ -20,7 +21,7 @@ public class ConfigurationMonitor(string section, if (serviceProvider.GetRequiredKeyedService>(section) is IConfigurationDescriptor configuration) { - ConfigurationCache.Remove(section); + cache.Remove(section); publisher.PublishUI(new ChangedEventArgs(configuration.Value)); } } diff --git a/Toolkit.Foundation/ConfigurationSource.cs b/Toolkit.Foundation/ConfigurationSource.cs index c464212..c722b29 100644 --- a/Toolkit.Foundation/ConfigurationSource.cs +++ b/Toolkit.Foundation/ConfigurationSource.cs @@ -9,6 +9,7 @@ namespace Toolkit.Foundation; public class ConfigurationSource(IConfigurationFile configurationFile, string section, + IConfigurationCache cache, JsonSerializerOptions? serializerOptions = null) : IConfigurationSource where TConfiguration : @@ -58,13 +59,13 @@ public class ConfigurationSource(IConfigurationFile(IConfigurationFile(sectionNode, serializerOptions ?? defaultSerializerOptions()); - ConfigurationCache.Set(section, value); + cache.Set(section, value); return true; } @@ -136,16 +137,9 @@ public class ConfigurationSource(IConfigurationFile(IConfigurationFile property in newObject) + { + existingObject[property.Key] = MergeNodes(existingObject[property.Key], CloneNode(property.Value)); + } + return existingObject; + } + + return newNode; + } + private JsonNode? CloneNode(JsonNode? node) { if (node is null) @@ -165,6 +173,7 @@ public class ConfigurationSource(IConfigurationFile(IConfigurationFile property in newObject) - { - existingObject[property.Key] = MergeNodes(existingObject[property.Key], CloneNode(property.Value)); - } - - return existingObject; - } - else if (existingNode is JsonArray existingArray && newNode is JsonArray newArray) - { - foreach (JsonNode? item in newArray) - { - existingArray.Add(CloneNode(item)); - } - - return existingArray; - } - else - { - return newNode; - } - } } diff --git a/Toolkit.Foundation/IConfigurationCache.cs b/Toolkit.Foundation/IConfigurationCache.cs new file mode 100644 index 0000000..4dfa090 --- /dev/null +++ b/Toolkit.Foundation/IConfigurationCache.cs @@ -0,0 +1,9 @@ +namespace Toolkit.Foundation +{ + public interface IConfigurationCache + { + bool Remove(string section); + void Set(string section, TConfiguration configuration); + bool TryGet(string section, out TConfiguration? configuration); + } +} \ No newline at end of file diff --git a/Toolkit.Foundation/IHostBuilderExtension.cs b/Toolkit.Foundation/IHostBuilderExtension.cs index 631f278..8aa74f2 100644 --- a/Toolkit.Foundation/IHostBuilderExtension.cs +++ b/Toolkit.Foundation/IHostBuilderExtension.cs @@ -118,7 +118,9 @@ public static class IHostBuilderExtension context.Properties.Add(section, new List { typeof(TConfiguration) }); } - services.TryAddSingleton>(provider => + services.AddKeyedScoped(section); + + services.TryAddKeyedTransient>(section, (provider, key) => { IFileInfo? fileInfo = null; if (provider.GetService() is IHostEnvironment hostEnvironment) @@ -140,8 +142,9 @@ public static class IHostBuilderExtension serializerDelegate.Invoke(defaultSerializer); } - return new ConfigurationSource(provider.GetRequiredService>(), + return new ConfigurationSource(provider.GetRequiredKeyedService>(section), section, + provider.GetRequiredKeyedService(section), defaultSerializer); }); @@ -174,15 +177,16 @@ public static class IHostBuilderExtension services.TryAddKeyedTransient>(section, (provider, key) => new ConfigurationDescriptor(section, provider.GetRequiredKeyedService>(key))); - services.AddTransient(provider => + services.TryAddTransient(provider => provider.GetRequiredKeyedService>(section)); - services.AddTransient(provider => + services.TryAddTransient(provider => provider.GetRequiredKeyedService>(section).Value); services.AddHostedService(provider => - new ConfigurationMonitor(section, - provider.GetRequiredService>(), + new ConfigurationMonitor(section, + provider.GetRequiredKeyedService(section), + provider.GetRequiredKeyedService>(section), provider.GetRequiredService(), provider.GetRequiredService())); }