Skip to content

Commit 73877b4

Browse files
authored
Fix Configuration to throw with ErrorOnUnknownConfiguration option (#110209)
* Fix Configuration to throw with ErrorOnUnknownConfiguration option * Fix the fired Debug.Assert * address the feedback
1 parent f2e5072 commit 73877b4

File tree

2 files changed

+33
-4
lines changed

2 files changed

+33
-4
lines changed

src/libraries/Microsoft.Extensions.Configuration.Binder/src/ConfigurationBinder.cs

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -465,9 +465,23 @@ private static void BindInstance(
465465
}
466466
else
467467
{
468-
if (isParentCollection && bindingPoint.Value is null && string.IsNullOrEmpty(configValue))
468+
// Reaching this point indicates that the configuration section is a leaf node with a string value.
469+
// Typically, configValue will be an empty string if the value in the configuration is empty or null.
470+
// While configValue could be any other string, we already know it cannot be converted to the required type, as TryConvertValue has already failed.
471+
472+
if (!string.IsNullOrEmpty(configValue))
469473
{
470-
// If we don't have an instance, try to create one
474+
// If we have a value, but no children, we can't bind it to anything
475+
// We already tried calling TryConvertValue and couldn't convert the configuration value to the required type.
476+
if (options.ErrorOnUnknownConfiguration)
477+
{
478+
Debug.Assert(section is not null);
479+
throw new InvalidOperationException(SR.Format(SR.Error_FailedBinding, section.Path, type));
480+
}
481+
}
482+
else if (isParentCollection && bindingPoint.Value is null)
483+
{
484+
// Try to create the default instance of the type
471485
bindingPoint.TrySetValue(CreateInstance(type, config, options, out _));
472486
}
473487
}
@@ -498,8 +512,6 @@ private static object CreateInstance(
498512
BinderOptions options,
499513
out ParameterInfo[]? constructorParameters)
500514
{
501-
Debug.Assert(!type.IsArray);
502-
503515
constructorParameters = null;
504516

505517
if (type.IsInterface || type.IsAbstract)

src/libraries/Microsoft.Extensions.Configuration.Binder/tests/Common/ConfigurationBinderTests.cs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2815,5 +2815,22 @@ public void CanGetEnumerableNotCollection()
28152815
Assert.True(result.Enabled);
28162816
Assert.Equal(new [] { "new", "class", "rosebud"}, result.Keywords);
28172817
}
2818+
2819+
#if !BUILDING_SOURCE_GENERATOR_TESTS
2820+
[Fact]
2821+
public void EnsureThrowingWithCollectionAndErrorOnUnknownConfigurationOption()
2822+
{
2823+
var configuration = new ConfigurationBuilder().AddInMemoryCollection(new Dictionary<string, string?> { ["Values:Monday"] = "not-an-array-of-string" }).Build();
2824+
Assert.Throws<InvalidOperationException>(() => configuration.Get<TestSettings>(options => options.ErrorOnUnknownConfiguration = true));
2825+
2826+
configuration = new ConfigurationBuilder().AddInMemoryCollection(new Dictionary<string, string?> { ["Values:Monday"] = "" }).Build();
2827+
Assert.Throws<InvalidOperationException>(() => configuration.Get<TestSettings>(options => options.ErrorOnUnknownConfiguration = true));
2828+
2829+
configuration = new ConfigurationBuilder().AddInMemoryCollection(new Dictionary<string, string?> { ["Values:Monday"] = null }).Build();
2830+
Assert.Throws<InvalidOperationException>(() => configuration.Get<TestSettings>(options => options.ErrorOnUnknownConfiguration = true));
2831+
}
2832+
2833+
internal class TestSettings { public Dictionary<DayOfWeek, string[]> Values { get; init; } = []; }
2834+
#endif
28182835
}
28192836
}

0 commit comments

Comments
 (0)