From 49c5d1878f456eb67b49157b4a57144218ae2c60 Mon Sep 17 00:00:00 2001 From: Maryam Ariyan Date: Tue, 5 Apr 2022 12:29:35 -0700 Subject: [PATCH 1/6] Allow access to child providers in ChainedConfigurationProvider Fixes #44486 --- .../ref/Microsoft.Extensions.Configuration.cs | 1 + .../src/ChainedConfigurationProvider.cs | 5 ++ .../ChainedConfigurationProviderTests.cs | 83 +++++++++++++++++++ .../tests/ConfigurationManagerTest.cs | 2 +- 4 files changed, 90 insertions(+), 1 deletion(-) create mode 100644 src/libraries/Microsoft.Extensions.Configuration/tests/ChainedConfigurationProviderTests.cs diff --git a/src/libraries/Microsoft.Extensions.Configuration/ref/Microsoft.Extensions.Configuration.cs b/src/libraries/Microsoft.Extensions.Configuration/ref/Microsoft.Extensions.Configuration.cs index 98717cb091a5f5..b5c18ee34b897c 100644 --- a/src/libraries/Microsoft.Extensions.Configuration/ref/Microsoft.Extensions.Configuration.cs +++ b/src/libraries/Microsoft.Extensions.Configuration/ref/Microsoft.Extensions.Configuration.cs @@ -14,6 +14,7 @@ public static partial class ChainedBuilderExtensions public partial class ChainedConfigurationProvider : Microsoft.Extensions.Configuration.IConfigurationProvider, System.IDisposable { public ChainedConfigurationProvider(Microsoft.Extensions.Configuration.ChainedConfigurationSource source) { } + public Microsoft.Extensions.Configuration.IConfiguration Configuration { get { throw null; } } public void Dispose() { } public System.Collections.Generic.IEnumerable GetChildKeys(System.Collections.Generic.IEnumerable earlierKeys, string? parentPath) { throw null; } public Microsoft.Extensions.Primitives.IChangeToken GetReloadToken() { throw null; } diff --git a/src/libraries/Microsoft.Extensions.Configuration/src/ChainedConfigurationProvider.cs b/src/libraries/Microsoft.Extensions.Configuration/src/ChainedConfigurationProvider.cs index f0a9380a6656e2..c8fbedd4a87d0f 100644 --- a/src/libraries/Microsoft.Extensions.Configuration/src/ChainedConfigurationProvider.cs +++ b/src/libraries/Microsoft.Extensions.Configuration/src/ChainedConfigurationProvider.cs @@ -30,6 +30,11 @@ public ChainedConfigurationProvider(ChainedConfigurationSource source!!) _shouldDisposeConfig = source.ShouldDisposeConfiguration; } + /// + /// The chained configuration. + /// + public IConfiguration Configuration => _config; + /// /// Tries to get a configuration value for the specified key. /// diff --git a/src/libraries/Microsoft.Extensions.Configuration/tests/ChainedConfigurationProviderTests.cs b/src/libraries/Microsoft.Extensions.Configuration/tests/ChainedConfigurationProviderTests.cs new file mode 100644 index 00000000000000..00a278c457905e --- /dev/null +++ b/src/libraries/Microsoft.Extensions.Configuration/tests/ChainedConfigurationProviderTests.cs @@ -0,0 +1,83 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.Extensions.Configuration.Memory; +using Microsoft.Extensions.Primitives; +using Moq; +using Xunit; + +namespace Microsoft.Extensions.Configuration.Test +{ + public class ChainedConfigurationProvierTests + { + [Fact] + public void Configuration_Basic() + { + var inputData = new Dictionary() { { "a:b", "c" } }; + + ChainedConfigurationProvider chainedConfig; + chainedConfig = new ChainedConfigurationProvider(new ChainedConfigurationSource + { + Configuration = new ConfigurationBuilder() + .Add(new MemoryConfigurationSource { InitialData = inputData }) + .Build(), + ShouldDisposeConfiguration = false, + }); + + Assert.True(chainedConfig.TryGet("a:b", out string? value)); + Assert.Equal("c", value); + Assert.Equal("c", chainedConfig.Configuration["a:b"]); + } + + [Fact] + public void ConfigurationRoot() + { + var inputData = new Dictionary() { { "a:b", "c" } }; + IConfigurationRoot configRoot = new ConfigurationBuilder() + .Add(new MemoryConfigurationSource { InitialData = inputData }) + .Build(); + + var chainedConfigurationProvider = new ChainedConfigurationProvider(new ChainedConfigurationSource + { + Configuration = configRoot, + ShouldDisposeConfiguration = false, + }); + + Assert.NotNull(chainedConfigurationProvider.Configuration as IConfigurationRoot); + Assert.NotNull((chainedConfigurationProvider.Configuration as IConfigurationRoot).Providers); + } + + [Fact] + public void ChainedConfigurationCouldExposeProvider() + { + var providers = new IConfigurationProvider[] { + new TestConfigurationProvider("foo", "foo-value") + }; + + var configRoot = new ConfigurationRoot(providers); + + var chainedConfigurationSource = new ChainedConfigurationSource + { + Configuration = configRoot, + ShouldDisposeConfiguration = false, + }; + + var chainedConfigurationProvider = chainedConfigurationSource + .Build(new ConfigurationBuilder()) as ChainedConfigurationProvider; + + Assert.NotNull(chainedConfigurationProvider.Configuration as IConfigurationRoot); + Assert.Equal(providers, (chainedConfigurationProvider.Configuration as IConfigurationRoot).Providers); + } + + private class TestConfigurationProvider : ConfigurationProvider + { + public TestConfigurationProvider(string key, string value) + => Data.Add(key, value); + } + } +} diff --git a/src/libraries/Microsoft.Extensions.Configuration/tests/ConfigurationManagerTest.cs b/src/libraries/Microsoft.Extensions.Configuration/tests/ConfigurationManagerTest.cs index d4561ee4889e65..7f2ca2877a48f8 100644 --- a/src/libraries/Microsoft.Extensions.Configuration/tests/ConfigurationManagerTest.cs +++ b/src/libraries/Microsoft.Extensions.Configuration/tests/ConfigurationManagerTest.cs @@ -221,7 +221,7 @@ public async Task ProviderDisposeDelayedWaitingOnConcurrentRead(Action concurrentReadAction(config)); await provider.ReadStartedTask; From 029f66ccc7f19c798252d0fab5abca5637abe904 Mon Sep 17 00:00:00 2001 From: Maryam Ariyan Date: Tue, 5 Apr 2022 12:41:09 -0700 Subject: [PATCH 2/6] Remove unused usings --- .../tests/ChainedConfigurationProviderTests.cs | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/libraries/Microsoft.Extensions.Configuration/tests/ChainedConfigurationProviderTests.cs b/src/libraries/Microsoft.Extensions.Configuration/tests/ChainedConfigurationProviderTests.cs index 00a278c457905e..d4615ec07eb9e1 100644 --- a/src/libraries/Microsoft.Extensions.Configuration/tests/ChainedConfigurationProviderTests.cs +++ b/src/libraries/Microsoft.Extensions.Configuration/tests/ChainedConfigurationProviderTests.cs @@ -1,14 +1,8 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System; using System.Collections.Generic; -using System.Linq; -using System.Threading; -using System.Threading.Tasks; using Microsoft.Extensions.Configuration.Memory; -using Microsoft.Extensions.Primitives; -using Moq; using Xunit; namespace Microsoft.Extensions.Configuration.Test From a61a30ef84a4c20233a2b283c7847772daa0c6d3 Mon Sep 17 00:00:00 2001 From: Maryam Ariyan Date: Tue, 5 Apr 2022 15:32:27 -0700 Subject: [PATCH 3/6] Update tests and add nit feedback --- .../src/ChainedConfigurationProvider.cs | 6 +- .../ChainedConfigurationProviderTests.cs | 61 ++++++++----------- 2 files changed, 27 insertions(+), 40 deletions(-) diff --git a/src/libraries/Microsoft.Extensions.Configuration/src/ChainedConfigurationProvider.cs b/src/libraries/Microsoft.Extensions.Configuration/src/ChainedConfigurationProvider.cs index c8fbedd4a87d0f..26d7d46767d8ac 100644 --- a/src/libraries/Microsoft.Extensions.Configuration/src/ChainedConfigurationProvider.cs +++ b/src/libraries/Microsoft.Extensions.Configuration/src/ChainedConfigurationProvider.cs @@ -21,12 +21,12 @@ public class ChainedConfigurationProvider : IConfigurationProvider, IDisposable /// The source configuration. public ChainedConfigurationProvider(ChainedConfigurationSource source!!) { - if (source.Configuration == null) + var configuration = source.Configuration; + if (configuration == null) { throw new ArgumentException(SR.Format(SR.InvalidNullArgument, "source.Configuration"), nameof(source)); } - - _config = source.Configuration; + _config = configuration; _shouldDisposeConfig = source.ShouldDisposeConfiguration; } diff --git a/src/libraries/Microsoft.Extensions.Configuration/tests/ChainedConfigurationProviderTests.cs b/src/libraries/Microsoft.Extensions.Configuration/tests/ChainedConfigurationProviderTests.cs index d4615ec07eb9e1..cdb793891c1562 100644 --- a/src/libraries/Microsoft.Extensions.Configuration/tests/ChainedConfigurationProviderTests.cs +++ b/src/libraries/Microsoft.Extensions.Configuration/tests/ChainedConfigurationProviderTests.cs @@ -2,6 +2,8 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Collections.Generic; +using System.Linq; +using Castle.Core.Internal; using Microsoft.Extensions.Configuration.Memory; using Xunit; @@ -10,62 +12,47 @@ namespace Microsoft.Extensions.Configuration.Test public class ChainedConfigurationProvierTests { [Fact] - public void Configuration_Basic() + public void ChainedConfiguration_UsingMemoryConfigurationSource_ChainedCouldExposeProvider() { - var inputData = new Dictionary() { { "a:b", "c" } }; - - ChainedConfigurationProvider chainedConfig; - chainedConfig = new ChainedConfigurationProvider(new ChainedConfigurationSource - { - Configuration = new ConfigurationBuilder() - .Add(new MemoryConfigurationSource { InitialData = inputData }) - .Build(), - ShouldDisposeConfiguration = false, - }); + var chainedConfigurationProvider = new ChainedConfigurationSource + { + Configuration = new ConfigurationBuilder() + .Add(new MemoryConfigurationSource { + InitialData = new Dictionary() { { "a:b", "c" } } + }) + .Build(), + ShouldDisposeConfiguration = false, + } + .Build(new ConfigurationBuilder()) as ChainedConfigurationProvider; - Assert.True(chainedConfig.TryGet("a:b", out string? value)); + Assert.True(chainedConfigurationProvider.TryGet("a:b", out string? value)); Assert.Equal("c", value); - Assert.Equal("c", chainedConfig.Configuration["a:b"]); - } + Assert.Equal("c", chainedConfigurationProvider.Configuration["a:b"]); - [Fact] - public void ConfigurationRoot() - { - var inputData = new Dictionary() { { "a:b", "c" } }; - IConfigurationRoot configRoot = new ConfigurationBuilder() - .Add(new MemoryConfigurationSource { InitialData = inputData }) - .Build(); - - var chainedConfigurationProvider = new ChainedConfigurationProvider(new ChainedConfigurationSource - { - Configuration = configRoot, - ShouldDisposeConfiguration = false, - }); - - Assert.NotNull(chainedConfigurationProvider.Configuration as IConfigurationRoot); - Assert.NotNull((chainedConfigurationProvider.Configuration as IConfigurationRoot).Providers); + var configRoot = chainedConfigurationProvider.Configuration as IConfigurationRoot; + Assert.NotNull(configRoot); + Assert.Equal(1, configRoot.Providers.Count()); + Assert.IsType(configRoot.Providers.First()); } [Fact] - public void ChainedConfigurationCouldExposeProvider() + public void ChainedConfiguration_ExposesProvider() { var providers = new IConfigurationProvider[] { new TestConfigurationProvider("foo", "foo-value") }; - - var configRoot = new ConfigurationRoot(providers); - var chainedConfigurationSource = new ChainedConfigurationSource { - Configuration = configRoot, + Configuration = new ConfigurationRoot(providers), ShouldDisposeConfiguration = false, }; var chainedConfigurationProvider = chainedConfigurationSource .Build(new ConfigurationBuilder()) as ChainedConfigurationProvider; - Assert.NotNull(chainedConfigurationProvider.Configuration as IConfigurationRoot); - Assert.Equal(providers, (chainedConfigurationProvider.Configuration as IConfigurationRoot).Providers); + var configRoot = chainedConfigurationProvider.Configuration as IConfigurationRoot; + Assert.NotNull(configRoot); + Assert.Equal(providers, configRoot.Providers); } private class TestConfigurationProvider : ConfigurationProvider From 2f896ab4efad70f45c952e40fc381f102d41992e Mon Sep 17 00:00:00 2001 From: Maryam Ariyan Date: Tue, 5 Apr 2022 17:05:40 -0700 Subject: [PATCH 4/6] Remove unused using --- .../tests/ChainedConfigurationProviderTests.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/libraries/Microsoft.Extensions.Configuration/tests/ChainedConfigurationProviderTests.cs b/src/libraries/Microsoft.Extensions.Configuration/tests/ChainedConfigurationProviderTests.cs index cdb793891c1562..b18da67bd69a69 100644 --- a/src/libraries/Microsoft.Extensions.Configuration/tests/ChainedConfigurationProviderTests.cs +++ b/src/libraries/Microsoft.Extensions.Configuration/tests/ChainedConfigurationProviderTests.cs @@ -3,7 +3,6 @@ using System.Collections.Generic; using System.Linq; -using Castle.Core.Internal; using Microsoft.Extensions.Configuration.Memory; using Xunit; From eae02f79efebc9004ff64d1d4f2138ebabb55120 Mon Sep 17 00:00:00 2001 From: Maryam Ariyan Date: Wed, 6 Apr 2022 09:05:31 -0700 Subject: [PATCH 5/6] Apply suggestions from code review Co-authored-by: Stephen Toub --- .../src/ChainedConfigurationProvider.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libraries/Microsoft.Extensions.Configuration/src/ChainedConfigurationProvider.cs b/src/libraries/Microsoft.Extensions.Configuration/src/ChainedConfigurationProvider.cs index 26d7d46767d8ac..a599e56b45bc68 100644 --- a/src/libraries/Microsoft.Extensions.Configuration/src/ChainedConfigurationProvider.cs +++ b/src/libraries/Microsoft.Extensions.Configuration/src/ChainedConfigurationProvider.cs @@ -22,7 +22,7 @@ public class ChainedConfigurationProvider : IConfigurationProvider, IDisposable public ChainedConfigurationProvider(ChainedConfigurationSource source!!) { var configuration = source.Configuration; - if (configuration == null) + if (configuration == null) { throw new ArgumentException(SR.Format(SR.InvalidNullArgument, "source.Configuration"), nameof(source)); } @@ -31,7 +31,7 @@ public ChainedConfigurationProvider(ChainedConfigurationSource source!!) } /// - /// The chained configuration. + /// Gets the chained configuration. /// public IConfiguration Configuration => _config; From fe9625679bb59aa34925ef332981494718f7f541 Mon Sep 17 00:00:00 2001 From: Maryam Ariyan Date: Wed, 6 Apr 2022 09:09:52 -0700 Subject: [PATCH 6/6] Simplify assignment statement --- .../src/ChainedConfigurationProvider.cs | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/libraries/Microsoft.Extensions.Configuration/src/ChainedConfigurationProvider.cs b/src/libraries/Microsoft.Extensions.Configuration/src/ChainedConfigurationProvider.cs index a599e56b45bc68..c5d46497155e8d 100644 --- a/src/libraries/Microsoft.Extensions.Configuration/src/ChainedConfigurationProvider.cs +++ b/src/libraries/Microsoft.Extensions.Configuration/src/ChainedConfigurationProvider.cs @@ -21,12 +21,7 @@ public class ChainedConfigurationProvider : IConfigurationProvider, IDisposable /// The source configuration. public ChainedConfigurationProvider(ChainedConfigurationSource source!!) { - var configuration = source.Configuration; - if (configuration == null) - { - throw new ArgumentException(SR.Format(SR.InvalidNullArgument, "source.Configuration"), nameof(source)); - } - _config = configuration; + _config = source.Configuration ?? throw new ArgumentException(SR.Format(SR.InvalidNullArgument, "source.Configuration"), nameof(source)); _shouldDisposeConfig = source.ShouldDisposeConfiguration; }