Skip to content

Commit 5864743

Browse files
authored
Fix binding logic for dictionaries with complex elements (#89117)
* Fix binding logic for dictionaries with complex elements * Remove interace impls not relevant to test and causing issues
1 parent 82f9a57 commit 5864743

File tree

3 files changed

+98
-1
lines changed

3 files changed

+98
-1
lines changed

src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/Emitter/CoreBindingHelper.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -731,7 +731,7 @@ void Emit_BindAndAddLogic_ForElement(string parsedKeyExpr)
731731
""");
732732
}
733733

734-
EmitBindCoreCall(elementType, $"{Identifier.element}!", Identifier.section, InitializationKind.None);
734+
EmitBindCoreCall(elementType, Identifier.element, Identifier.section, InitializationKind.None);
735735
_writer.WriteLine($"{objIdentifier}[{parsedKeyExpr}] = {Identifier.element};");
736736
}
737737

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

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33

44
using System;
55
using System.Collections.Generic;
6+
using System.ComponentModel;
7+
using System.Diagnostics.CodeAnalysis;
68
using System.Globalization;
79
using System.Linq;
810
using Microsoft.Extensions.Configuration;
@@ -664,5 +666,35 @@ public struct StructWithParameterlessAndParameterizedCtor
664666

665667
public int MyInt { get; }
666668
}
669+
670+
[TypeConverter(typeof(GeolocationTypeConverter))]
671+
public struct Geolocation
672+
{
673+
public static readonly Geolocation Zero = new(0, 0);
674+
675+
public Geolocation(double latitude, double longitude)
676+
{
677+
Latitude = latitude;
678+
Longitude = longitude;
679+
}
680+
681+
public double Latitude { get; set; }
682+
683+
public double Longitude { get; set; }
684+
685+
private sealed class GeolocationTypeConverter : TypeConverter
686+
{
687+
public override bool CanConvertFrom(ITypeDescriptorContext? context, Type sourceType) =>
688+
throw new NotImplementedException();
689+
690+
public override object? ConvertFrom(ITypeDescriptorContext? context, CultureInfo? culture, object value) =>
691+
throw new NotImplementedException();
692+
}
693+
}
694+
695+
public class GeolocationWrapper
696+
{
697+
public Geolocation Location { get; set; }
698+
}
667699
}
668700
}

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

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1900,5 +1900,70 @@ public void AllowsCaseInsensitiveMatch()
19001900
GenericOptionsWithParamCtor<string> obj2 = configuration.Get<GenericOptionsWithParamCtor<string>>();
19011901
Assert.Equal("MyString", obj2.Value);
19021902
}
1903+
1904+
[Fact]
1905+
public void ObjWith_TypeConverter()
1906+
{
1907+
var configuration = TestHelpers.GetConfigurationFromJsonString("""
1908+
{
1909+
"Location":
1910+
{
1911+
"Latitude": 3,
1912+
"Longitude": 4,
1913+
}
1914+
}
1915+
""");
1916+
1917+
// TypeConverter impl is not honored (https://github.com/dotnet/runtime/issues/83599).
1918+
1919+
GeolocationWrapper obj = configuration.Get<GeolocationWrapper>();
1920+
ValidateGeolocation(obj.Location);
1921+
1922+
configuration = TestHelpers.GetConfigurationFromJsonString(""" { "Geolocation": "3, 4", } """);
1923+
obj = configuration.Get<GeolocationWrapper>();
1924+
Assert.Equal(Geolocation.Zero, obj.Location);
1925+
}
1926+
1927+
[Fact]
1928+
public void ComplexObj_As_Dictionary_Element()
1929+
{
1930+
var configuration = TestHelpers.GetConfigurationFromJsonString("""
1931+
{
1932+
"First":
1933+
{
1934+
"Latitude": 3,
1935+
"Longitude": 4,
1936+
}
1937+
}
1938+
""");
1939+
1940+
Geolocation obj = configuration.Get<IDictionary<string, Geolocation>>()["First"];
1941+
ValidateGeolocation(obj);
1942+
1943+
obj = configuration.Get<IReadOnlyDictionary<string, Geolocation>>()["First"];
1944+
ValidateGeolocation(obj);
1945+
}
1946+
1947+
[Fact]
1948+
public void ComplexObj_As_Enumerable_Element()
1949+
{
1950+
var configuration = TestHelpers.GetConfigurationFromJsonString("""{ "Enumerable": [{ "Latitude": 3, "Longitude": 4 }] }""")
1951+
.GetSection("Enumerable");
1952+
1953+
Geolocation obj = configuration.Get<IList<Geolocation>>()[0];
1954+
ValidateGeolocation(obj);
1955+
1956+
obj = configuration.Get<Geolocation[]>()[0];
1957+
ValidateGeolocation(obj);
1958+
1959+
obj = configuration.Get<IReadOnlyList<Geolocation>>()[0];
1960+
ValidateGeolocation(obj);
1961+
}
1962+
1963+
private void ValidateGeolocation(Geolocation location)
1964+
{
1965+
Assert.Equal(3, location.Latitude);
1966+
Assert.Equal(4, location.Longitude);
1967+
}
19031968
}
19041969
}

0 commit comments

Comments
 (0)