From 7121e8f51223c09fd9271ea2f742d89ebb1b871e Mon Sep 17 00:00:00 2001 From: Bart Koelman <104792814+bart-vmware@users.noreply.github.com> Date: Fri, 12 Apr 2024 23:05:37 +0200 Subject: [PATCH] Prevent adding PlaceholderResolver multiple times, which breaks the ENV actuator (#1276) --- .../PlaceholderConfigurationExtensions.cs | 24 ++++++++++----- .../PlaceholderConfigurationExtensionsTest.cs | 30 +++++++++++++++++++ 2 files changed, 46 insertions(+), 8 deletions(-) diff --git a/src/Configuration/src/Placeholder/PlaceholderConfigurationExtensions.cs b/src/Configuration/src/Placeholder/PlaceholderConfigurationExtensions.cs index 656ec341a0..b26d0c80da 100644 --- a/src/Configuration/src/Placeholder/PlaceholderConfigurationExtensions.cs +++ b/src/Configuration/src/Placeholder/PlaceholderConfigurationExtensions.cs @@ -48,15 +48,18 @@ public static IConfigurationBuilder AddPlaceholderResolver(this IConfigurationBu ArgumentGuard.NotNull(builder); ArgumentGuard.NotNull(loggerFactory); - if (builder is IConfigurationRoot configuration) + if (!builder.Sources.Any(source => source is PlaceholderResolverSource)) { - builder.Add(new PlaceholderResolverSource(configuration, loggerFactory)); - } - else - { - var resolver = new PlaceholderResolverSource(builder.Sources, loggerFactory); - builder.Sources.Clear(); - builder.Add(resolver); + if (builder is IConfigurationRoot configuration) + { + builder.Add(new PlaceholderResolverSource(configuration, loggerFactory)); + } + else + { + var resolver = new PlaceholderResolverSource(builder.Sources, loggerFactory); + builder.Sources.Clear(); + builder.Add(resolver); + } } return builder; @@ -102,6 +105,11 @@ public static IConfiguration AddPlaceholderResolver(this IConfiguration configur throw new InvalidOperationException($"Configuration must implement '{typeof(IConfigurationRoot)}'."); } + if (root.Providers.Any(provider => provider is IPlaceholderResolverProvider)) + { + return configuration; + } + return new ConfigurationRoot(new List { new PlaceholderResolverProvider(new List(root.Providers), loggerFactory) diff --git a/src/Configuration/test/Placeholder.Test/PlaceholderConfigurationExtensionsTest.cs b/src/Configuration/test/Placeholder.Test/PlaceholderConfigurationExtensionsTest.cs index c8cba16f30..5424866f02 100644 --- a/src/Configuration/test/Placeholder.Test/PlaceholderConfigurationExtensionsTest.cs +++ b/src/Configuration/test/Placeholder.Test/PlaceholderConfigurationExtensionsTest.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the Apache 2.0 License. // See the LICENSE file in the project root for more information. +using FluentAssertions; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Logging; using Steeltoe.Common.Utils.IO; @@ -22,6 +23,21 @@ public void AddPlaceholderResolver_AddsPlaceholderResolverSourceToList() Assert.NotNull(placeholderSource); } + [Fact] + public void AddPlaceholderResolver_NoDuplicates() + { + var configurationBuilder = new ConfigurationBuilder(); + + configurationBuilder.AddPlaceholderResolver(); + configurationBuilder.AddPlaceholderResolver(); + configurationBuilder.AddPlaceholderResolver(); + + PlaceholderResolverSource? source = configurationBuilder.Sources.OfType().SingleOrDefault(); + Assert.NotNull(source); + Assert.NotNull(source.Sources); + Assert.Empty(source.Sources); + } + [Fact] public void AddPlaceholderResolver_CreatesProvider() { @@ -251,4 +267,18 @@ public void AddPlaceholderResolver_WithConfiguration_ReturnsNewConfiguration() Assert.Equal("notfound", config2["key3"]); Assert.Equal("${nokey}", config2["key4"]); } + + [Fact] + public void AddPlaceholderResolver_WithConfiguration_NoDuplicates() + { + IConfigurationRoot configurationRoot = new ConfigurationBuilder().Build(); + + IConfiguration newConfiguration = configurationRoot.AddPlaceholderResolver().AddPlaceholderResolver().AddPlaceholderResolver(); + + ConfigurationRoot newConfigurationRoot = newConfiguration.Should().BeOfType().Which; + newConfigurationRoot.Providers.Should().HaveCount(1); + + PlaceholderResolverProvider? provider = newConfigurationRoot.Providers.Single().Should().BeOfType().Which; + provider.Providers.Should().BeEmpty(); + } }