From 5864743c345b5b940031d35788c2f29f1b18d391 Mon Sep 17 00:00:00 2001 From: Layomi Akinrinade Date: Tue, 18 Jul 2023 17:05:20 -0700 Subject: [PATCH] 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 --- .../gen/Helpers/Emitter/CoreBindingHelper.cs | 2 +- .../Common/ConfigurationBinderTests.TestClasses.cs | 32 +++++++++++ .../tests/Common/ConfigurationBinderTests.cs | 65 ++++++++++++++++++++++ 3 files changed, 98 insertions(+), 1 deletion(-) diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/Emitter/CoreBindingHelper.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/Emitter/CoreBindingHelper.cs index bdf5606..dd13ee8 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/Emitter/CoreBindingHelper.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/Emitter/CoreBindingHelper.cs @@ -731,7 +731,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration """); } - EmitBindCoreCall(elementType, $"{Identifier.element}!", Identifier.section, InitializationKind.None); + EmitBindCoreCall(elementType, Identifier.element, Identifier.section, InitializationKind.None); _writer.WriteLine($"{objIdentifier}[{parsedKeyExpr}] = {Identifier.element};"); } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/Common/ConfigurationBinderTests.TestClasses.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/Common/ConfigurationBinderTests.TestClasses.cs index 5e4855a..df894d6 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/Common/ConfigurationBinderTests.TestClasses.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/Common/ConfigurationBinderTests.TestClasses.cs @@ -3,6 +3,8 @@ using System; using System.Collections.Generic; +using System.ComponentModel; +using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.Linq; using Microsoft.Extensions.Configuration; @@ -664,5 +666,35 @@ namespace Microsoft.Extensions public int MyInt { get; } } + + [TypeConverter(typeof(GeolocationTypeConverter))] + public struct Geolocation + { + public static readonly Geolocation Zero = new(0, 0); + + public Geolocation(double latitude, double longitude) + { + Latitude = latitude; + Longitude = longitude; + } + + public double Latitude { get; set; } + + public double Longitude { get; set; } + + private sealed class GeolocationTypeConverter : TypeConverter + { + public override bool CanConvertFrom(ITypeDescriptorContext? context, Type sourceType) => + throw new NotImplementedException(); + + public override object? ConvertFrom(ITypeDescriptorContext? context, CultureInfo? culture, object value) => + throw new NotImplementedException(); + } + } + + public class GeolocationWrapper + { + public Geolocation Location { get; set; } + } } } 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 d9dfefe..b1af371 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/Common/ConfigurationBinderTests.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/Common/ConfigurationBinderTests.cs @@ -1900,5 +1900,70 @@ if (!System.Diagnostics.Debugger.IsAttached) { System.Diagnostics.Debugger.Launc GenericOptionsWithParamCtor obj2 = configuration.Get>(); Assert.Equal("MyString", obj2.Value); } + + [Fact] + public void ObjWith_TypeConverter() + { + var configuration = TestHelpers.GetConfigurationFromJsonString(""" + { + "Location": + { + "Latitude": 3, + "Longitude": 4, + } + } + """); + + // TypeConverter impl is not honored (https://github.com/dotnet/runtime/issues/83599). + + GeolocationWrapper obj = configuration.Get(); + ValidateGeolocation(obj.Location); + + configuration = TestHelpers.GetConfigurationFromJsonString(""" { "Geolocation": "3, 4", } """); + obj = configuration.Get(); + Assert.Equal(Geolocation.Zero, obj.Location); + } + + [Fact] + public void ComplexObj_As_Dictionary_Element() + { + var configuration = TestHelpers.GetConfigurationFromJsonString(""" + { + "First": + { + "Latitude": 3, + "Longitude": 4, + } + } + """); + + Geolocation obj = configuration.Get>()["First"]; + ValidateGeolocation(obj); + + obj = configuration.Get>()["First"]; + ValidateGeolocation(obj); + } + + [Fact] + public void ComplexObj_As_Enumerable_Element() + { + var configuration = TestHelpers.GetConfigurationFromJsonString("""{ "Enumerable": [{ "Latitude": 3, "Longitude": 4 }] }""") + .GetSection("Enumerable"); + + Geolocation obj = configuration.Get>()[0]; + ValidateGeolocation(obj); + + obj = configuration.Get()[0]; + ValidateGeolocation(obj); + + obj = configuration.Get>()[0]; + ValidateGeolocation(obj); + } + + private void ValidateGeolocation(Geolocation location) + { + Assert.Equal(3, location.Latitude); + Assert.Equal(4, location.Longitude); + } } } -- 2.7.4