diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/Common/ConfigurationBinderTests.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/Common/ConfigurationBinderTests.cs index a08ff66bd1e4d1..d869a5ad827125 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/Common/ConfigurationBinderTests.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/Common/ConfigurationBinderTests.cs @@ -3007,5 +3007,36 @@ public void BindArraysWithNullAndOtherValues() Assert.Equal([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10], instance.ByteArray3); #endif } + + [Fact] + public void TestProvidersOrder() + { + string jsonConfig1 = @" + { + ""SimplePoco"": { + ""A"": ""Provider1A"", + ""B"": ""Provider1B"", + }, + }"; + + // Missing B in the second provider should not override the value from the first provider. + string jsonConfig2 = @" + { + ""SimplePoco"": { + ""A"": ""Provider2A"", + }, + }"; + + var configuration = new ConfigurationBuilder() + .AddJsonStream(new MemoryStream(Encoding.UTF8.GetBytes(jsonConfig1))) + .AddJsonStream(new MemoryStream(Encoding.UTF8.GetBytes(jsonConfig2))) + .Build().GetSection("SimplePoco"); + + SimplePoco? result = configuration.Get(); + + Assert.NotNull(result); + Assert.Equal("Provider2A", result.A); // Value should come from the last provider + Assert.Equal("Provider1B", result.B); // B should not be overridden by the second provider + } } } diff --git a/src/libraries/Microsoft.Extensions.Configuration/src/InternalConfigurationRootExtensions.cs b/src/libraries/Microsoft.Extensions.Configuration/src/InternalConfigurationRootExtensions.cs index 30bf4e33752947..c70b6af44b8917 100644 --- a/src/libraries/Microsoft.Extensions.Configuration/src/InternalConfigurationRootExtensions.cs +++ b/src/libraries/Microsoft.Extensions.Configuration/src/InternalConfigurationRootExtensions.cs @@ -42,8 +42,15 @@ internal static IEnumerable GetChildrenImplementation(thi internal static bool TryGetConfiguration(this IConfigurationRoot root, string key, out string? value) { - foreach (IConfigurationProvider provider in root.Providers) + // common cases Providers is IList in ConfigurationRoot + IList providers = root.Providers is IList list + ? list + : root.Providers.ToList(); + + // ensure looping in the reverse order + for (int i = providers.Count - 1; i >= 0; i--) { + IConfigurationProvider provider = providers[i]; if (provider.TryGet(key, out value)) { return true;