Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,10 @@ private TypeSpec CreateTypeSpec(TypeParseInfo typeParseInfo)
{
spec = new ConfigurationSectionSpec(type);
}
else if (SymbolEqualityComparer.Default.Equals(type, _typeSymbols.IConfiguration))
{
spec = new ConfigurationSectionSpec(type) { IsIConfiguration = true };
}
else if (type is INamedTypeSymbol)
{
spec = CreateObjectSpec(typeParseInfo);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,11 @@ private void EmitGetCoreMethod()
EmitEndBlock(); // End if-check for input type.
}
break;
case ConfigurationSectionSpec { IsIConfiguration: true }:
{
_writer.WriteLine($"return {Identifier.configuration};");
}
break;
case ConfigurationSectionSpec:
{
EmitCastToIConfigurationSection();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,11 @@ public SimpleTypeSpec(ITypeSymbol type) : base(type) { }
internal sealed record ConfigurationSectionSpec : SimpleTypeSpec
{
public ConfigurationSectionSpec(ITypeSymbol type) : base(type) { }

/// <summary>
/// Indicates whether this spec represents <see cref="IConfiguration"/> (as opposed to <see cref="IConfigurationSection"/>).
/// </summary>
public bool IsIConfiguration { get; init; }
}

public sealed record ParsableFromStringSpec : SimpleTypeSpec
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -324,8 +324,8 @@ private static void BindInstance(
BinderOptions options,
bool isParentCollection)
{
// if binding IConfigurationSection, break early
if (type == typeof(IConfigurationSection))
// if binding IConfigurationSection or IConfiguration, break early
if (type == typeof(IConfigurationSection) || type == typeof(IConfiguration))
{
bindingPoint.TrySetValue(config);
return;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,16 +60,26 @@ public class NestedOptions
}
}

public class ConfigurationInterfaceOptions
public class OptionsWithIConfigurationSection
{
public IConfigurationSection Section { get; set; }
}

public class OptionsWithIConfiguration
{
public IConfiguration Section { get; set; }
}

public class DerivedOptionsWithIConfigurationSection : DerivedOptions
{
public IConfigurationSection DerivedSection { get; set; }
}

public class DerivedOptionsWithIConfiguration : DerivedOptions
{
public IConfiguration DerivedSection { get; set; }
}

public record struct RecordStructTypeOptions(string Color, int Length);

public record RecordOptionsWithNesting(int Number, RecordOptionsWithNesting.RecordNestedOptions Nested1,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -95,19 +95,19 @@ public void CanBindIConfigurationSection()
configurationBuilder.AddInMemoryCollection(dic);
var config = configurationBuilder.Build();

var options = config.Get<ConfigurationInterfaceOptions>();
var options = config.Get<OptionsWithIConfigurationSection>();
var childOptions = options.Section.Get<DerivedOptions>();
Test();

options = (ConfigurationInterfaceOptions)config.Get(typeof(ConfigurationInterfaceOptions));
options = (OptionsWithIConfigurationSection)config.Get(typeof(OptionsWithIConfigurationSection));
childOptions = (DerivedOptions)options.Section.Get(typeof(DerivedOptions));
Test();

options = config.Get<ConfigurationInterfaceOptions>(options => { });
options = config.Get<OptionsWithIConfigurationSection>(options => { });
childOptions = options.Section.Get<DerivedOptions>(options => { });
Test();

options = (ConfigurationInterfaceOptions)config.Get(typeof(ConfigurationInterfaceOptions), options => { });
options = (OptionsWithIConfigurationSection)config.Get(typeof(OptionsWithIConfigurationSection), options => { });
childOptions = (DerivedOptions)options.Section.Get(typeof(DerivedOptions), options => { });
Test();

Expand All @@ -125,7 +125,43 @@ void Test()
}

[Fact]
public void CanBindWithKeyOverload()
public void CanBindIConfigurationSectionWithDerivedOptionsSection()
{
var dic = new Dictionary<string, string>
{
{"Section:Integer", "-2"},
{"Section:Boolean", "TRUe"},
{"Section:Nested:Integer", "11"},
{"Section:Virtual", "Sup"},
{"Section:DerivedSection:Nested:Integer", "11"},
{"Section:DerivedSection:Virtual", "Sup"}
};
var configurationBuilder = new ConfigurationBuilder();
configurationBuilder.AddInMemoryCollection(dic);
var config = configurationBuilder.Build();

var options = config.Get<OptionsWithIConfigurationSection>();

var childOptions = options.Section.Get<DerivedOptionsWithIConfigurationSection>();

var childDerivedOptions = childOptions.DerivedSection.Get<DerivedOptions>();

Assert.True(childOptions.Boolean);
Assert.Equal(-2, childOptions.Integer);
Assert.Equal(11, childOptions.Nested.Integer);
Assert.Equal("Derived:Sup", childOptions.Virtual);
Assert.Equal(11, childDerivedOptions.Nested.Integer);
Assert.Equal("Derived:Sup", childDerivedOptions.Virtual);

Assert.Equal("Section", options.Section.Key);
Assert.Equal("Section", options.Section.Path);
Assert.Equal("DerivedSection", childOptions.DerivedSection.Key);
Assert.Equal("Section:DerivedSection", childOptions.DerivedSection.Path);
Assert.Null(options.Section.Value);
}

[Fact]
public void CanBindIConfiguration()
{
var dic = new Dictionary<string, string>
{
Expand All @@ -138,17 +174,38 @@ public void CanBindWithKeyOverload()
configurationBuilder.AddInMemoryCollection(dic);
var config = configurationBuilder.Build();

var options = new DerivedOptions();
config.Bind("Section", options);
var options = config.Get<OptionsWithIConfiguration>();
var childOptions = options.Section.Get<DerivedOptions>();
Test();

Assert.True(options.Boolean);
Assert.Equal(-2, options.Integer);
Assert.Equal(11, options.Nested.Integer);
Assert.Equal("Derived:Sup", options.Virtual);
options = (OptionsWithIConfiguration)config.Get(typeof(OptionsWithIConfiguration));
childOptions = (DerivedOptions)options.Section.Get(typeof(DerivedOptions));
Test();

options = config.Get<OptionsWithIConfiguration>(options => { });
childOptions = options.Section.Get<DerivedOptions>(options => { });
Test();

options = (OptionsWithIConfiguration)config.Get(typeof(OptionsWithIConfiguration), options => { });
childOptions = (DerivedOptions)options.Section.Get(typeof(DerivedOptions), options => { });
Test();

void Test()
{
Assert.True(childOptions.Boolean);
Assert.Equal(-2, childOptions.Integer);
Assert.Equal(11, childOptions.Nested.Integer);
Assert.Equal("Derived:Sup", childOptions.Virtual);

var section = Assert.IsAssignableFrom<IConfigurationSection>(options.Section);
Assert.Equal("Section", section.Key);
Assert.Equal("Section", section.Path);
Assert.Null(section.Value);
}
}

[Fact]
public void CanBindIConfigurationSectionWithDerivedOptionsSection()
public void CanBindIConfigurationWithDerivedOptionsSection()
{
var dic = new Dictionary<string, string>
{
Expand All @@ -163,10 +220,8 @@ public void CanBindIConfigurationSectionWithDerivedOptionsSection()
configurationBuilder.AddInMemoryCollection(dic);
var config = configurationBuilder.Build();

var options = config.Get<ConfigurationInterfaceOptions>();

var childOptions = options.Section.Get<DerivedOptionsWithIConfigurationSection>();

var options = config.Get<OptionsWithIConfiguration>();
var childOptions = options.Section.Get<DerivedOptionsWithIConfiguration>();
var childDerivedOptions = childOptions.DerivedSection.Get<DerivedOptions>();

Assert.True(childOptions.Boolean);
Expand All @@ -176,11 +231,37 @@ public void CanBindIConfigurationSectionWithDerivedOptionsSection()
Assert.Equal(11, childDerivedOptions.Nested.Integer);
Assert.Equal("Derived:Sup", childDerivedOptions.Virtual);

Assert.Equal("Section", options.Section.Key);
Assert.Equal("Section", options.Section.Path);
Assert.Equal("DerivedSection", childOptions.DerivedSection.Key);
Assert.Equal("Section:DerivedSection", childOptions.DerivedSection.Path);
Assert.Null(options.Section.Value);
var section = Assert.IsAssignableFrom<IConfigurationSection>(options.Section);
Assert.Equal("Section", section.Key);
Assert.Equal("Section", section.Path);

var derivedSection = Assert.IsAssignableFrom<IConfigurationSection>(childOptions.DerivedSection);
Assert.Equal("DerivedSection", derivedSection.Key);
Assert.Equal("Section:DerivedSection", derivedSection.Path);
Assert.Null(section.Value);
}

[Fact]
public void CanBindWithKeyOverload()
{
var dic = new Dictionary<string, string>
{
{"Section:Integer", "-2"},
{"Section:Boolean", "TRUe"},
{"Section:Nested:Integer", "11"},
{"Section:Virtual", "Sup"}
};
var configurationBuilder = new ConfigurationBuilder();
configurationBuilder.AddInMemoryCollection(dic);
var config = configurationBuilder.Build();

var options = new DerivedOptions();
config.Bind("Section", options);

Assert.True(options.Boolean);
Assert.Equal(-2, options.Integer);
Assert.Equal(11, options.Nested.Integer);
Assert.Equal("Derived:Sup", options.Virtual);
}

[Fact]
Expand Down Expand Up @@ -2621,6 +2702,8 @@ public void GetIConfigurationSection()
}
""");

Assert.Throws<InvalidCastException>(() => configuration.Get<IConfigurationSection>());

var obj = configuration.GetSection("value").Get<IConfigurationSection>();
Assert.Equal("MyString", obj.Value);

Expand Down Expand Up @@ -2649,6 +2732,40 @@ static void ValidateList(List<IConfigurationSection> list)
}
}

[Fact]
public void GetIConfiguration()
{
var configuration = TestHelpers.GetConfigurationFromJsonString("""
{
"vaLue": { "key": "MyString" },
}
""");

Assert.Same(configuration, configuration.Get<IConfiguration>());

var obj = configuration.GetSection("value").Get<IConfiguration>();
Assert.Equal("MyString", obj["key"]);

configuration = TestHelpers.GetConfigurationFromJsonString("""
{
"vaLue": [ { "key": "MyString" } ],
}
""");

var list = configuration.GetSection("value").Get<List<IConfiguration>>();
ValidateList(list);

var dict = configuration.Get<Dictionary<string, List<IConfiguration>>>();
Assert.Equal(1, dict.Count);
ValidateList(dict["vaLue"]);

static void ValidateList(List<IConfiguration> list)
{
Assert.Equal(1, list.Count);
Assert.Equal("MyString", list[0]["key"]);
}
}

[Fact]
public void NullableDictKeys()
{
Expand Down
Loading