Skip to content

Commit 974edf9

Browse files
[release/8.0-rc2] Ensure Bind can handle null from GetSection (#92477)
* Ensure Bind can handle null from GetSection IConfiguration instances may return a null value from GetSection. We were not handling this and would throw a NullReferenceException. * Address feedback * Remove Moq from ConfigBinder tests --------- Co-authored-by: Eric StJohn <[email protected]>
1 parent 873b3cc commit 974edf9

File tree

3 files changed

+47
-2
lines changed

3 files changed

+47
-2
lines changed

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -298,6 +298,11 @@ private static void BindInstance(
298298
return;
299299
}
300300

301+
if (config is null)
302+
{
303+
return;
304+
}
305+
301306
var section = config as IConfigurationSection;
302307
string? configValue = section?.Value;
303308
if (configValue != null && TryConvertValue(type, configValue, section?.Path, out object? convertedValue, out Exception? error))

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

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -888,5 +888,11 @@ public int MyIntProperty
888888
}
889889
}
890890

891+
public class SimplePoco
892+
{
893+
public string A { get; set; }
894+
public string B { get; set; }
895+
}
896+
891897
}
892898
}

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

Lines changed: 36 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#if BUILDING_SOURCE_GENERATOR_TESTS
1212
using Microsoft.Extensions.Configuration;
1313
#endif
14+
using Microsoft.Extensions.Configuration.Memory;
1415
using Microsoft.Extensions.Configuration.Test;
1516
using Xunit;
1617

@@ -1767,7 +1768,7 @@ public void EnsureCallingThePropertySetter()
17671768
Assert.Equal(0, options.OtherCodeNullable);
17681769
Assert.Equal("default", options.OtherCodeString);
17691770
Assert.Null(options.OtherCodeNull);
1770-
Assert.Null(options.OtherCodeUri);
1771+
Assert.Null(options.OtherCodeUri);
17711772
}
17721773

17731774
[Fact]
@@ -2238,7 +2239,7 @@ void TestUntypedOverloads(IConfiguration? configuration, string? key)
22382239
Assert.Throws<ArgumentNullException>(() => configuration.GetValue(typeof(GeolocationClass), key, new GeolocationClass()));
22392240
Assert.Throws<ArgumentNullException>(() => configuration.GetValue(typeof(Geolocation), key));
22402241
Assert.Throws<ArgumentNullException>(() => configuration.GetValue(typeof(Geolocation), key, defaultValue: null));
2241-
Assert.Throws<ArgumentNullException>(() => configuration.GetValue(typeof(Geolocation), key, default(Geolocation)));
2242+
Assert.Throws<ArgumentNullException>(() => configuration.GetValue(typeof(Geolocation), key, default(Geolocation)));
22422243
}
22432244
}
22442245

@@ -2404,5 +2405,38 @@ public void SharedChildInstance()
24042405
config.GetSection("A").Bind(instance);
24052406
Assert.Equal("localhost", instance.ConnectionString);
24062407
}
2408+
2409+
[Fact]
2410+
public void CanBindToMockConfigurationSection()
2411+
{
2412+
const string expectedA = "hello";
2413+
2414+
var configSource = new MemoryConfigurationSource()
2415+
{
2416+
InitialData = new Dictionary<string, string?>()
2417+
{
2418+
[$":{nameof(SimplePoco.A)}"] = expectedA,
2419+
}
2420+
};
2421+
var configRoot = new MockConfigurationRoot(new[] { configSource.Build(null) });
2422+
var configSection = new ConfigurationSection(configRoot, string.Empty);
2423+
2424+
SimplePoco result = new();
2425+
configSection.Bind(result);
2426+
2427+
Assert.Equal(expectedA, result.A);
2428+
Assert.Equal(default(string), result.B);
2429+
}
2430+
2431+
// a mock configuration root that will return null for undefined Sections,
2432+
// as is common when Configuration interfaces are mocked
2433+
class MockConfigurationRoot : ConfigurationRoot, IConfigurationRoot
2434+
{
2435+
public MockConfigurationRoot(IList<IConfigurationProvider> providers) : base(providers)
2436+
{ }
2437+
2438+
IConfigurationSection IConfiguration.GetSection(string key) =>
2439+
this[key] is null ? null : new ConfigurationSection(this, key);
2440+
}
24072441
}
24082442
}

0 commit comments

Comments
 (0)