From 78f22c7b0e64807701821d2c441cc9a8bf283017 Mon Sep 17 00:00:00 2001 From: pedrobsaila Date: Thu, 3 Aug 2023 19:51:39 +0200 Subject: [PATCH 01/17] Address feedback from config binding gen PR to improve enum parsing --- .../ConfigurationBindingGenerator.Parser.cs | 11 ++++++- .../gen/Helpers/Emitter/CoreBindingHelpers.cs | 23 ++++--------- .../gen/Model/SourceGenerationSpec.cs | 2 ++ .../Baselines/Primitives.generated.txt | 32 +++++++++---------- 4 files changed, 35 insertions(+), 33 deletions(-) diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/ConfigurationBindingGenerator.Parser.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/ConfigurationBindingGenerator.Parser.cs index 64db4eb58b1f7..6b271be8a5216 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/ConfigurationBindingGenerator.Parser.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/ConfigurationBindingGenerator.Parser.cs @@ -63,6 +63,15 @@ public Parser(SourceProductionContext context, KnownTypeSymbols typeSymbols, Imm } } + foreach (var typeSymbol in _createdSpecs.Keys) + { + if (IsEnum(typeSymbol)) + { + _sourceGenSpec.EmitEnumParseMethod = true; + break; + } + } + return _sourceGenSpec; } @@ -126,7 +135,7 @@ type.TypeKind is TypeKind.TypeParameter or TypeKind.Pointer or TypeKind.Error || { ParsableFromStringSpec stringParsableSpec = new(type) { StringParsableTypeKind = specialTypeKind }; - if (stringParsableSpec.StringParsableTypeKind is not StringParsableTypeKind.AssignFromSectionValue) + if (stringParsableSpec.StringParsableTypeKind != StringParsableTypeKind.AssignFromSectionValue && stringParsableSpec.StringParsableTypeKind != StringParsableTypeKind.Enum) { _sourceGenSpec.PrimitivesForHelperGen.Add(stringParsableSpec); } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/Emitter/CoreBindingHelpers.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/Emitter/CoreBindingHelpers.cs index f30408fad596d..5d12e8fed9012 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/Emitter/CoreBindingHelpers.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/Emitter/CoreBindingHelpers.cs @@ -413,24 +413,17 @@ private void EmitHelperMethods() EmitGetBinderOptionsHelper(); } - bool enumTypeExists = false; + if (_sourceGenSpec.EmitEnumParseMethod) + { + _writer.WriteLine(); + EmitEnumParseMethod(); + _emitBlankLineBeforeNextStatement = true; + } foreach (ParsableFromStringSpec type in _sourceGenSpec.PrimitivesForHelperGen) { EmitBlankLineIfRequired(); - - if (type.StringParsableTypeKind == StringParsableTypeKind.Enum) - { - if (!enumTypeExists) - { - EmitEnumParseMethod(); - enumTypeExists = true; - } - } - else - { - EmitPrimitiveParseMethod(type); - } + EmitPrimitiveParseMethod(type); } } @@ -549,8 +542,6 @@ private void EmitPrimitiveParseMethod(ParsableFromStringSpec type) switch (typeKind) { - case StringParsableTypeKind.Enum: - return; case StringParsableTypeKind.ByteArray: { parsedValueExpr = $"Convert.FromBase64String({Identifier.value})"; diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Model/SourceGenerationSpec.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Model/SourceGenerationSpec.cs index 760d57b1dcc88..d50043e2908bb 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Model/SourceGenerationSpec.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Model/SourceGenerationSpec.cs @@ -27,5 +27,7 @@ internal sealed record SourceGenerationSpec public MethodsToGen_ConfigurationBinder MethodsToGen_ConfigurationBinder { get; set; } public MethodsToGen_Extensions_OptionsBuilder MethodsToGen_OptionsBuilderExt { get; set; } public MethodsToGen_Extensions_ServiceCollection MethodsToGen_ServiceCollectionExt { get; set; } + + public bool EmitEnumParseMethod { get; set; } } } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/Primitives.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/Primitives.generated.txt index 1bf110454ec7b..db542637efba4 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/Primitives.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/Primitives.generated.txt @@ -214,6 +214,22 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration } } + public static T ParseEnum(string value, Func getPath) where T : struct + { + try + { + #if NETFRAMEWORK || NETSTANDARD2_0 + return (T)Enum.Parse(typeof(T), value, ignoreCase: true); + #else + return Enum.Parse(value, ignoreCase: true); + #endif + } + catch (Exception exception) + { + throw new InvalidOperationException($"Failed to convert configuration value at '{getPath()}' to type '{typeof(T)}'.", exception); + } + } + public static bool ParseBool(string value, Func getPath) { try @@ -454,22 +470,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration } } - public static T ParseEnum(string value, Func getPath) where T : struct - { - try - { - #if NETFRAMEWORK || NETSTANDARD2_0 - return (T)Enum.Parse(typeof(T), value, ignoreCase: true); - #else - return Enum.Parse(value, ignoreCase: true); - #endif - } - catch (Exception exception) - { - throw new InvalidOperationException($"Failed to convert configuration value at '{getPath()}' to type '{typeof(T)}'.", exception); - } - } - public static Int128 ParseInt128(string value, Func getPath) { try From 135be177437154c4e3ab58e5528cc1f92786e35b Mon Sep 17 00:00:00 2001 From: pedrobsaila Date: Sat, 12 Aug 2023 14:50:16 +0200 Subject: [PATCH 02/17] drop preprocessors and generate ArgumentNullException.ThrowIfNull when applicable --- .../ConfigurationBindingGenerator.Parser.cs | 19 +- .../gen/Helpers/Emitter/CoreBindingHelpers.cs | 7 +- .../gen/Helpers/Emitter/Helpers.cs | 9 +- .../gen/Model/KnownTypeSymbols.cs | 6 + .../gen/Model/SourceGenerationSpec.cs | 4 + .../Baselines/Collections.generated.txt | 5 +- .../Collections.net462.generated.txt | 302 ++++++++++ .../ConfigurationBinder/Bind.generated.txt | 22 +- .../Bind.net462.generated.txt | 184 +++++++ .../Bind_Instance.generated.txt | 11 +- .../Bind_Instance.net462.generated.txt | 160 ++++++ .../Bind_Instance_BinderOptions.generated.txt | 11 +- ...nstance_BinderOptions.net462.generated.txt | 178 ++++++ .../Bind_Key_Instance.generated.txt | 11 +- .../Bind_Key_Instance.net462.generated.txt | 160 ++++++ .../ConfigurationBinder/Get.generated.txt | 5 +- .../Get.net462.generated.txt | 240 ++++++++ .../GetValue.generated.txt | 5 +- .../GetValue.net462.generated.txt | 118 ++++ .../GetValue_T_Key.generated.txt | 5 +- .../GetValue_T_Key.net462.generated.txt | 58 ++ .../GetValue_T_Key_DefaultValue.generated.txt | 5 +- ...ue_T_Key_DefaultValue.net462.generated.txt | 58 ++ .../GetValue_TypeOf_Key.generated.txt | 5 +- .../GetValue_TypeOf_Key.net462.generated.txt | 58 ++ ...alue_TypeOf_Key_DefaultValue.generated.txt | 5 +- ...peOf_Key_DefaultValue.net462.generated.txt | 58 ++ .../ConfigurationBinder/Get_T.generated.txt | 5 +- .../Get_T.net462.generated.txt | 208 +++++++ .../Get_T_BinderOptions.generated.txt | 5 +- .../Get_T_BinderOptions.net462.generated.txt | 208 +++++++ .../Get_TypeOf.generated.txt | 5 +- .../Get_TypeOf.net462.generated.txt | 136 +++++ .../Get_TypeOf_BinderOptions.generated.txt | 5 +- ..._TypeOf_BinderOptions.net462.generated.txt | 136 +++++ .../BindConfiguration.generated.txt | 5 +- .../BindConfiguration.net462.generated.txt | 183 +++++++ .../OptionsBuilder/Bind_T.generated.txt | 21 +- .../Bind_T.net462.generated.txt | 201 +++++++ .../Bind_T_BinderOptions.generated.txt | 21 +- .../Bind_T_BinderOptions.net462.generated.txt | 195 +++++++ .../Baselines/Primitives.generated.txt | 17 +- .../Baselines/Primitives.net462.generated.txt | 517 ++++++++++++++++++ .../Configure_T.generated.txt | 5 +- .../Configure_T.net462.generated.txt | 246 +++++++++ .../Configure_T_BinderOptions.generated.txt | 5 +- ...igure_T_BinderOptions.net462.generated.txt | 246 +++++++++ .../Configure_T_name.generated.txt | 5 +- .../Configure_T_name.net462.generated.txt | 246 +++++++++ ...nfigure_T_name_BinderOptions.generated.txt | 5 +- ..._T_name_BinderOptions.net462.generated.txt | 240 ++++++++ .../GeneratorTests.Baselines.Options.cs | 41 +- .../GeneratorTests.Baselines.cs | 297 ++++++++-- 53 files changed, 4689 insertions(+), 224 deletions(-) create mode 100644 src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/Collections.net462.generated.txt create mode 100644 src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Bind.net462.generated.txt create mode 100644 src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Bind_Instance.net462.generated.txt create mode 100644 src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Bind_Instance_BinderOptions.net462.generated.txt create mode 100644 src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Bind_Key_Instance.net462.generated.txt create mode 100644 src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Get.net462.generated.txt create mode 100644 src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/GetValue.net462.generated.txt create mode 100644 src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/GetValue_T_Key.net462.generated.txt create mode 100644 src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/GetValue_T_Key_DefaultValue.net462.generated.txt create mode 100644 src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/GetValue_TypeOf_Key.net462.generated.txt create mode 100644 src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/GetValue_TypeOf_Key_DefaultValue.net462.generated.txt create mode 100644 src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Get_T.net462.generated.txt create mode 100644 src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Get_T_BinderOptions.net462.generated.txt create mode 100644 src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Get_TypeOf.net462.generated.txt create mode 100644 src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Get_TypeOf_BinderOptions.net462.generated.txt create mode 100644 src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/OptionsBuilder/BindConfiguration.net462.generated.txt create mode 100644 src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/OptionsBuilder/Bind_T.net462.generated.txt create mode 100644 src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/OptionsBuilder/Bind_T_BinderOptions.net462.generated.txt create mode 100644 src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/Primitives.net462.generated.txt create mode 100644 src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ServiceCollection/Configure_T.net462.generated.txt create mode 100644 src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ServiceCollection/Configure_T_BinderOptions.net462.generated.txt create mode 100644 src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ServiceCollection/Configure_T_name.net462.generated.txt create mode 100644 src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ServiceCollection/Configure_T_name_BinderOptions.net462.generated.txt diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/ConfigurationBindingGenerator.Parser.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/ConfigurationBindingGenerator.Parser.cs index 6b271be8a5216..891fe3dd1f50b 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/ConfigurationBindingGenerator.Parser.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/ConfigurationBindingGenerator.Parser.cs @@ -63,14 +63,7 @@ public Parser(SourceProductionContext context, KnownTypeSymbols typeSymbols, Imm } } - foreach (var typeSymbol in _createdSpecs.Keys) - { - if (IsEnum(typeSymbol)) - { - _sourceGenSpec.EmitEnumParseMethod = true; - break; - } - } + _sourceGenSpec.EmitThrowIfNullMethod = !_typeSymbols.ArgumentNullException.GetMembers("ThrowIfNull").IsEmpty; return _sourceGenSpec; } @@ -135,7 +128,15 @@ type.TypeKind is TypeKind.TypeParameter or TypeKind.Pointer or TypeKind.Error || { ParsableFromStringSpec stringParsableSpec = new(type) { StringParsableTypeKind = specialTypeKind }; - if (stringParsableSpec.StringParsableTypeKind != StringParsableTypeKind.AssignFromSectionValue && stringParsableSpec.StringParsableTypeKind != StringParsableTypeKind.Enum) + if (specialTypeKind is StringParsableTypeKind.Enum) + { + if (!_sourceGenSpec.EmitEnumParseMethod) + { + _sourceGenSpec.EmitEnumParseMethod = true; + _sourceGenSpec.EmitGenericParseEnum = _typeSymbols.Enum.GetMembers("Parse").Any(m => m is IMethodSymbol methodSymbol && methodSymbol.IsGenericMethod); + } + } + else if (specialTypeKind is not StringParsableTypeKind.AssignFromSectionValue) { _sourceGenSpec.PrimitivesForHelperGen.Add(stringParsableSpec); } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/Emitter/CoreBindingHelpers.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/Emitter/CoreBindingHelpers.cs index 5d12e8fed9012..187032ca5738b 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/Emitter/CoreBindingHelpers.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/Emitter/CoreBindingHelpers.cs @@ -513,16 +513,13 @@ private void EmitEnumParseMethod() { string exceptionArg1 = string.Format(ExceptionMessages.FailedBinding, $"{{{Identifier.getPath}()}}", $"{{typeof(T)}}"); + string parseEnumCall = _sourceGenSpec.EmitGenericParseEnum ? "Enum.Parse(value, ignoreCase: true)" : "(T)Enum.Parse(typeof(T), value, ignoreCase: true)"; _writer.WriteLine($$""" public static T ParseEnum(string value, Func getPath) where T : struct { try { - #if NETFRAMEWORK || NETSTANDARD2_0 - return (T)Enum.Parse(typeof(T), value, ignoreCase: true); - #else - return Enum.Parse(value, ignoreCase: true); - #endif + return {{parseEnumCall}}; } catch ({{Identifier.Exception}} {{Identifier.exception}}) { diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/Emitter/Helpers.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/Emitter/Helpers.cs index bad56b7ce3275..9aa01a18a272b 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/Emitter/Helpers.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/Emitter/Helpers.cs @@ -213,12 +213,19 @@ private void EmitBlankLineIfRequired() private void EmitCheckForNullArgument_WithBlankLine(string paramName) { - _writer.WriteLine($$""" + if (_sourceGenSpec.EmitThrowIfNullMethod) + { + _writer.WriteLine($"ArgumentNullException.ThrowIfNull({paramName});"); + } + else + { + _writer.WriteLine($$""" if ({{paramName}} is null) { throw new ArgumentNullException(nameof({{paramName}})); } """); + } _writer.WriteLine(); } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Model/KnownTypeSymbols.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Model/KnownTypeSymbols.cs index e3a4f67ed396b..80b964047cce3 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Model/KnownTypeSymbols.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Model/KnownTypeSymbols.cs @@ -54,6 +54,8 @@ internal sealed record KnownTypeSymbols public INamedTypeSymbol? ISet_Unbound { get; } public INamedTypeSymbol? ISet { get; } public INamedTypeSymbol? List { get; } + public INamedTypeSymbol? Enum { get; } + public INamedTypeSymbol? ArgumentNullException { get; } public KnownTypeSymbols(CSharpCompilation compilation) { @@ -108,6 +110,10 @@ public KnownTypeSymbols(CSharpCompilation compilation) IReadOnlyList_Unbound = compilation.GetBestTypeByMetadataName(typeof(IReadOnlyList<>))?.ConstructUnboundGenericType(); IReadOnlySet_Unbound = compilation.GetBestTypeByMetadataName("System.Collections.Generic.IReadOnlySet`1")?.ConstructUnboundGenericType(); ISet_Unbound = ISet?.ConstructUnboundGenericType(); + + // needed to be able to know if a member exist inside the compilation unit + Enum = compilation.GetBestTypeByMetadataName(typeof(Enum)); + ArgumentNullException = compilation.GetBestTypeByMetadataName(typeof(ArgumentNullException)); } } } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Model/SourceGenerationSpec.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Model/SourceGenerationSpec.cs index d50043e2908bb..976fa0fe3610e 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Model/SourceGenerationSpec.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Model/SourceGenerationSpec.cs @@ -29,5 +29,9 @@ internal sealed record SourceGenerationSpec public MethodsToGen_Extensions_ServiceCollection MethodsToGen_ServiceCollectionExt { get; set; } public bool EmitEnumParseMethod { get; set; } + + public bool EmitGenericParseEnum { get; set; } + + public bool EmitThrowIfNullMethod { get; set; } } } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/Collections.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/Collections.generated.txt index 528847cfeb3a3..cc89078dc8ba7 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/Collections.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/Collections.generated.txt @@ -41,10 +41,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration public static object? GetCore(this IConfiguration configuration, Type type, Action? configureOptions) { - if (configuration is null) - { - throw new ArgumentNullException(nameof(configuration)); - } + ArgumentNullException.ThrowIfNull(configuration); BinderOptions? binderOptions = GetBinderOptions(configureOptions); diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/Collections.net462.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/Collections.net462.generated.txt new file mode 100644 index 0000000000000..2149dcaaa0714 --- /dev/null +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/Collections.net462.generated.txt @@ -0,0 +1,302 @@ +// +#nullable enable +#pragma warning disable CS0612, CS0618 // Suppress warnings about [Obsolete] member usage in generated code. + +/// Generated helper providing an AOT and linking compatible implementation for configuration binding. +[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")] +internal static class GeneratedConfigurationBinder +{ + /// Attempts to bind the configuration instance to a new instance of type T. + public static T? Get(this global::Microsoft.Extensions.Configuration.IConfiguration configuration) => (T?)(global::Microsoft.Extensions.Configuration.Binder.SourceGeneration.CoreBindingHelper.GetCore(configuration, typeof(T), configureOptions: null) ?? default(T)); +} + +namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration +{ + using Microsoft.Extensions.Configuration; + using System; + using System.CodeDom.Compiler; + using System.Collections.Generic; + using System.Globalization; + using System.Linq; + + /// Provide core binding logic. + [GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")] + file static class CoreBindingHelper + { + private readonly static Lazy> s_configKeys_ProgramMyClassWithCustomCollections = new(() => new HashSet(StringComparer.OrdinalIgnoreCase) { "CustomDictionary", "CustomList", "IReadOnlyList", "IReadOnlyDictionary" }); + + public static object? GetCore(this IConfiguration configuration, Type type, Action? configureOptions) + { + if (configuration is null) + { + throw new ArgumentNullException(nameof(configuration)); + } + + BinderOptions? binderOptions = GetBinderOptions(configureOptions); + + if (!HasValueOrChildren(configuration)) + { + return null; + } + + if (type == typeof(Program.MyClassWithCustomCollections)) + { + var obj = new Program.MyClassWithCustomCollections(); + BindCore(configuration, ref obj, binderOptions); + return obj; + } + + throw new global::System.NotSupportedException($"Unable to bind to type '{type}': generator did not detect the type as input."); + } + + public static void BindCore(IConfiguration configuration, ref Program.CustomDictionary obj, BinderOptions? binderOptions) + { + if (obj is null) + { + throw new ArgumentNullException(nameof(obj)); + } + + foreach (IConfigurationSection section in configuration.GetChildren()) + { + if (section.Value is string value) + { + obj[section.Key] = ParseInt(value, () => section.Path); + } + } + } + + public static void BindCore(IConfiguration configuration, ref Program.CustomList obj, BinderOptions? binderOptions) + { + if (obj is null) + { + throw new ArgumentNullException(nameof(obj)); + } + + foreach (IConfigurationSection section in configuration.GetChildren()) + { + if (section.Value is string value) + { + obj.Add(value); + } + } + } + + public static void BindCore(IConfiguration configuration, ref List obj, BinderOptions? binderOptions) + { + if (obj is null) + { + throw new ArgumentNullException(nameof(obj)); + } + + foreach (IConfigurationSection section in configuration.GetChildren()) + { + if (section.Value is string value) + { + obj.Add(ParseInt(value, () => section.Path)); + } + } + } + + public static void BindCore(IConfiguration configuration, ref ICollection obj, BinderOptions? binderOptions) + { + if (obj is null) + { + throw new ArgumentNullException(nameof(obj)); + } + + foreach (IConfigurationSection section in configuration.GetChildren()) + { + if (section.Value is string value) + { + obj.Add(ParseInt(value, () => section.Path)); + } + } + } + + public static void BindCore(IConfiguration configuration, ref IReadOnlyList obj, BinderOptions? binderOptions) + { + if (obj is null) + { + throw new ArgumentNullException(nameof(obj)); + } + + if (obj is not ICollection temp) + { + return; + } + + foreach (IConfigurationSection section in configuration.GetChildren()) + { + if (section.Value is string value) + { + temp.Add(ParseInt(value, () => section.Path)); + } + } + } + + public static void BindCore(IConfiguration configuration, ref Dictionary obj, BinderOptions? binderOptions) + { + if (obj is null) + { + throw new ArgumentNullException(nameof(obj)); + } + + foreach (IConfigurationSection section in configuration.GetChildren()) + { + if (section.Value is string value) + { + obj[section.Key] = ParseInt(value, () => section.Path); + } + } + } + + public static void BindCore(IConfiguration configuration, ref IDictionary obj, BinderOptions? binderOptions) + { + if (obj is null) + { + throw new ArgumentNullException(nameof(obj)); + } + + foreach (IConfigurationSection section in configuration.GetChildren()) + { + if (section.Value is string value) + { + obj[section.Key] = ParseInt(value, () => section.Path); + } + } + } + + public static void BindCore(IConfiguration configuration, ref IReadOnlyDictionary obj, BinderOptions? binderOptions) + { + if (obj is null) + { + throw new ArgumentNullException(nameof(obj)); + } + + if (obj is not IDictionary temp) + { + return; + } + + foreach (IConfigurationSection section in configuration.GetChildren()) + { + if (section.Value is string value) + { + temp[section.Key] = ParseInt(value, () => section.Path); + } + } + } + + public static void BindCore(IConfiguration configuration, ref Program.MyClassWithCustomCollections obj, BinderOptions? binderOptions) + { + if (obj is null) + { + throw new ArgumentNullException(nameof(obj)); + } + + ValidateConfigurationKeys(typeof(Program.MyClassWithCustomCollections), s_configKeys_ProgramMyClassWithCustomCollections, configuration, binderOptions); + + if (AsConfigWithChildren(configuration.GetSection("CustomDictionary")) is IConfigurationSection section1) + { + Program.CustomDictionary? temp3 = obj.CustomDictionary; + temp3 ??= new Program.CustomDictionary(); + BindCore(section1, ref temp3, binderOptions); + obj.CustomDictionary = temp3; + } + + if (AsConfigWithChildren(configuration.GetSection("CustomList")) is IConfigurationSection section4) + { + Program.CustomList? temp6 = obj.CustomList; + temp6 ??= new Program.CustomList(); + BindCore(section4, ref temp6, binderOptions); + obj.CustomList = temp6; + } + + if (AsConfigWithChildren(configuration.GetSection("IReadOnlyList")) is IConfigurationSection section7) + { + IReadOnlyList? temp9 = obj.IReadOnlyList; + temp9 = temp9 is null ? new List() : new List(temp9); + BindCore(section7, ref temp9, binderOptions); + obj.IReadOnlyList = temp9; + } + + if (AsConfigWithChildren(configuration.GetSection("IReadOnlyDictionary")) is IConfigurationSection section10) + { + IReadOnlyDictionary? temp12 = obj.IReadOnlyDictionary; + temp12 = temp12 is null ? new Dictionary() : temp12.ToDictionary(pair => pair.Key, pair => pair.Value); + BindCore(section10, ref temp12, binderOptions); + obj.IReadOnlyDictionary = temp12; + } + } + + /// If required by the binder options, validates that there are no unknown keys in the input configuration object. + public static void ValidateConfigurationKeys(Type type, Lazy> keys, IConfiguration configuration, BinderOptions? binderOptions) + { + if (binderOptions?.ErrorOnUnknownConfiguration is true) + { + List? temp = null; + + foreach (IConfigurationSection section in configuration.GetChildren()) + { + if (!keys.Value.Contains(section.Key)) + { + (temp ??= new List()).Add($"'{section.Key}'"); + } + } + + if (temp is not null) + { + throw new InvalidOperationException($"'ErrorOnUnknownConfiguration' was set on the provided BinderOptions, but the following properties were not found on the instance of {type}: {string.Join(", ", temp)}"); + } + } + } + + public static bool HasValueOrChildren(IConfiguration configuration) + { + if ((configuration as IConfigurationSection)?.Value is not null) + { + return true; + } + return AsConfigWithChildren(configuration) is not null; + } + + public static IConfiguration? AsConfigWithChildren(IConfiguration configuration) + { + foreach (IConfigurationSection _ in configuration.GetChildren()) + { + return configuration; + } + return null; + } + + public static BinderOptions? GetBinderOptions(Action? configureOptions) + { + if (configureOptions is null) + { + return null; + } + + BinderOptions binderOptions = new(); + configureOptions(binderOptions); + + if (binderOptions.BindNonPublicProperties) + { + throw new global::System.NotSupportedException($"The configuration binding source generator does not support 'BinderOptions.BindNonPublicProperties'."); + } + + return binderOptions; + } + + public static int ParseInt(string value, Func getPath) + { + try + { + return int.Parse(value, NumberStyles.Integer, CultureInfo.InvariantCulture); + } + catch (Exception exception) + { + throw new InvalidOperationException($"Failed to convert configuration value at '{getPath()}' to type '{typeof(int)}'.", exception); + } + } + } +} diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Bind.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Bind.generated.txt index 36ac12fd31f83..bc4ab24e91344 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Bind.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Bind.generated.txt @@ -34,15 +34,8 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration [InterceptsLocationAttribute(@"src-0.cs", 13, 18)] public static void Bind_ProgramMyClass(this IConfiguration configuration, object? obj) { - if (configuration is null) - { - throw new ArgumentNullException(nameof(configuration)); - } - - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } + ArgumentNullException.ThrowIfNull(configuration); + ArgumentNullException.ThrowIfNull(obj); var typedObj = (Program.MyClass)obj; BindCore(configuration, ref typedObj, binderOptions: null); @@ -70,15 +63,8 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration [InterceptsLocationAttribute(@"src-0.cs", 15, 24)] public static void Bind_ProgramMyClass(this IConfiguration configuration, string key, object? obj) { - if (configuration is null) - { - throw new ArgumentNullException(nameof(configuration)); - } - - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } + ArgumentNullException.ThrowIfNull(configuration); + ArgumentNullException.ThrowIfNull(obj); var typedObj = (Program.MyClass)obj; BindCore(configuration.GetSection(key), ref typedObj, binderOptions: null); diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Bind.net462.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Bind.net462.generated.txt new file mode 100644 index 0000000000000..406e8db671677 --- /dev/null +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Bind.net462.generated.txt @@ -0,0 +1,184 @@ +// +#nullable enable +#pragma warning disable CS0612, CS0618 // Suppress warnings about [Obsolete] member usage in generated code. + +/// Generated helper providing an AOT and linking compatible implementation for configuration binding. +[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")] +internal static class GeneratedConfigurationBinder +{ + /// Attempts to bind the given object instance to configuration values by matching property names against configuration keys recursively. + public static void Bind(this global::Microsoft.Extensions.Configuration.IConfiguration configuration, global::Program.MyClass obj) => global::Microsoft.Extensions.Configuration.Binder.SourceGeneration.CoreBindingHelper.BindCore(configuration, ref obj, binderOptions: null); + + /// Attempts to bind the given object instance to configuration values by matching property names against configuration keys recursively. + public static void Bind(this global::Microsoft.Extensions.Configuration.IConfiguration configuration, global::Program.MyClass obj, global::System.Action? configureOptions) => global::Microsoft.Extensions.Configuration.Binder.SourceGeneration.CoreBindingHelper.BindCore(configuration, ref obj, global::Microsoft.Extensions.Configuration.Binder.SourceGeneration.CoreBindingHelper.GetBinderOptions(configureOptions)); + + /// Attempts to bind the given object instance to configuration values by matching property names against configuration keys recursively. + public static void Bind(this global::Microsoft.Extensions.Configuration.IConfiguration configuration, string key, global::Program.MyClass obj) => global::Microsoft.Extensions.Configuration.Binder.SourceGeneration.CoreBindingHelper.BindCore(configuration.GetSection(key), ref obj, binderOptions: null); +} + +namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration +{ + using Microsoft.Extensions.Configuration; + using System; + using System.CodeDom.Compiler; + using System.Collections.Generic; + using System.Globalization; + + /// Provide core binding logic. + [GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")] + file static class CoreBindingHelper + { + private readonly static Lazy> s_configKeys_ProgramMyClass = new(() => new HashSet(StringComparer.OrdinalIgnoreCase) { "MyString", "MyInt", "MyList", "MyDictionary", "MyComplexDictionary" }); + + public static void BindCore(IConfiguration configuration, ref List obj, BinderOptions? binderOptions) + { + if (obj is null) + { + throw new ArgumentNullException(nameof(obj)); + } + + foreach (IConfigurationSection section in configuration.GetChildren()) + { + if (section.Value is string value) + { + obj.Add(ParseInt(value, () => section.Path)); + } + } + } + + public static void BindCore(IConfiguration configuration, ref Dictionary obj, BinderOptions? binderOptions) + { + if (obj is null) + { + throw new ArgumentNullException(nameof(obj)); + } + + foreach (IConfigurationSection section in configuration.GetChildren()) + { + if (section.Value is string value) + { + obj[section.Key] = value; + } + } + } + + public static void BindCore(IConfiguration configuration, ref Dictionary obj, BinderOptions? binderOptions) + { + if (obj is null) + { + throw new ArgumentNullException(nameof(obj)); + } + + foreach (IConfigurationSection section in configuration.GetChildren()) + { + if (!(obj.TryGetValue(section.Key, out Program.MyClass2? element) && element is not null)) + { + element = new Program.MyClass2(); + } + obj[section.Key] = element; + } + } + + public static void BindCore(IConfiguration configuration, ref Program.MyClass obj, BinderOptions? binderOptions) + { + if (obj is null) + { + throw new ArgumentNullException(nameof(obj)); + } + + ValidateConfigurationKeys(typeof(Program.MyClass), s_configKeys_ProgramMyClass, configuration, binderOptions); + + obj.MyString = configuration["MyString"]!; + + if (configuration["MyInt"] is string value1) + { + obj.MyInt = ParseInt(value1, () => configuration.GetSection("MyInt").Path); + } + + if (AsConfigWithChildren(configuration.GetSection("MyList")) is IConfigurationSection section2) + { + List? temp4 = obj.MyList; + temp4 ??= new List(); + BindCore(section2, ref temp4, binderOptions); + obj.MyList = temp4; + } + + if (AsConfigWithChildren(configuration.GetSection("MyDictionary")) is IConfigurationSection section5) + { + Dictionary? temp7 = obj.MyDictionary; + temp7 ??= new Dictionary(); + BindCore(section5, ref temp7, binderOptions); + obj.MyDictionary = temp7; + } + + if (AsConfigWithChildren(configuration.GetSection("MyComplexDictionary")) is IConfigurationSection section8) + { + Dictionary? temp10 = obj.MyComplexDictionary; + temp10 ??= new Dictionary(); + BindCore(section8, ref temp10, binderOptions); + obj.MyComplexDictionary = temp10; + } + } + + /// If required by the binder options, validates that there are no unknown keys in the input configuration object. + public static void ValidateConfigurationKeys(Type type, Lazy> keys, IConfiguration configuration, BinderOptions? binderOptions) + { + if (binderOptions?.ErrorOnUnknownConfiguration is true) + { + List? temp = null; + + foreach (IConfigurationSection section in configuration.GetChildren()) + { + if (!keys.Value.Contains(section.Key)) + { + (temp ??= new List()).Add($"'{section.Key}'"); + } + } + + if (temp is not null) + { + throw new InvalidOperationException($"'ErrorOnUnknownConfiguration' was set on the provided BinderOptions, but the following properties were not found on the instance of {type}: {string.Join(", ", temp)}"); + } + } + } + + public static IConfiguration? AsConfigWithChildren(IConfiguration configuration) + { + foreach (IConfigurationSection _ in configuration.GetChildren()) + { + return configuration; + } + return null; + } + + public static BinderOptions? GetBinderOptions(Action? configureOptions) + { + if (configureOptions is null) + { + return null; + } + + BinderOptions binderOptions = new(); + configureOptions(binderOptions); + + if (binderOptions.BindNonPublicProperties) + { + throw new global::System.NotSupportedException($"The configuration binding source generator does not support 'BinderOptions.BindNonPublicProperties'."); + } + + return binderOptions; + } + + public static int ParseInt(string value, Func getPath) + { + try + { + return int.Parse(value, NumberStyles.Integer, CultureInfo.InvariantCulture); + } + catch (Exception exception) + { + throw new InvalidOperationException($"Failed to convert configuration value at '{getPath()}' to type '{typeof(int)}'.", exception); + } + } + } +} diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Bind_Instance.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Bind_Instance.generated.txt index 02fb06957bb3d..aa3d330fd0ea6 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Bind_Instance.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Bind_Instance.generated.txt @@ -34,15 +34,8 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration [InterceptsLocationAttribute(@"src-0.cs", 12, 20)] public static void Bind_ProgramMyClass(this IConfiguration configuration, object? obj) { - if (configuration is null) - { - throw new ArgumentNullException(nameof(configuration)); - } - - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } + ArgumentNullException.ThrowIfNull(configuration); + ArgumentNullException.ThrowIfNull(obj); var typedObj = (Program.MyClass)obj; BindCore(configuration, ref typedObj, binderOptions: null); diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Bind_Instance.net462.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Bind_Instance.net462.generated.txt new file mode 100644 index 0000000000000..106e01795369e --- /dev/null +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Bind_Instance.net462.generated.txt @@ -0,0 +1,160 @@ +// +#nullable enable +#pragma warning disable CS0612, CS0618 // Suppress warnings about [Obsolete] member usage in generated code. + +/// Generated helper providing an AOT and linking compatible implementation for configuration binding. +[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")] +internal static class GeneratedConfigurationBinder +{ + /// Attempts to bind the given object instance to configuration values by matching property names against configuration keys recursively. + public static void Bind(this global::Microsoft.Extensions.Configuration.IConfiguration configuration, global::Program.MyClass obj) => global::Microsoft.Extensions.Configuration.Binder.SourceGeneration.CoreBindingHelper.BindCore(configuration, ref obj, binderOptions: null); +} + +namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration +{ + using Microsoft.Extensions.Configuration; + using System; + using System.CodeDom.Compiler; + using System.Collections.Generic; + using System.Globalization; + + /// Provide core binding logic. + [GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")] + file static class CoreBindingHelper + { + private readonly static Lazy> s_configKeys_ProgramMyClass = new(() => new HashSet(StringComparer.OrdinalIgnoreCase) { "MyString", "MyInt", "MyList", "MyDictionary", "MyComplexDictionary" }); + + public static void BindCore(IConfiguration configuration, ref List obj, BinderOptions? binderOptions) + { + if (obj is null) + { + throw new ArgumentNullException(nameof(obj)); + } + + foreach (IConfigurationSection section in configuration.GetChildren()) + { + if (section.Value is string value) + { + obj.Add(ParseInt(value, () => section.Path)); + } + } + } + + public static void BindCore(IConfiguration configuration, ref Dictionary obj, BinderOptions? binderOptions) + { + if (obj is null) + { + throw new ArgumentNullException(nameof(obj)); + } + + foreach (IConfigurationSection section in configuration.GetChildren()) + { + if (section.Value is string value) + { + obj[section.Key] = value; + } + } + } + + public static void BindCore(IConfiguration configuration, ref Dictionary obj, BinderOptions? binderOptions) + { + if (obj is null) + { + throw new ArgumentNullException(nameof(obj)); + } + + foreach (IConfigurationSection section in configuration.GetChildren()) + { + if (!(obj.TryGetValue(section.Key, out Program.MyClass2? element) && element is not null)) + { + element = new Program.MyClass2(); + } + obj[section.Key] = element; + } + } + + public static void BindCore(IConfiguration configuration, ref Program.MyClass obj, BinderOptions? binderOptions) + { + if (obj is null) + { + throw new ArgumentNullException(nameof(obj)); + } + + ValidateConfigurationKeys(typeof(Program.MyClass), s_configKeys_ProgramMyClass, configuration, binderOptions); + + obj.MyString = configuration["MyString"]!; + + if (configuration["MyInt"] is string value1) + { + obj.MyInt = ParseInt(value1, () => configuration.GetSection("MyInt").Path); + } + + if (AsConfigWithChildren(configuration.GetSection("MyList")) is IConfigurationSection section2) + { + List? temp4 = obj.MyList; + temp4 ??= new List(); + BindCore(section2, ref temp4, binderOptions); + obj.MyList = temp4; + } + + if (AsConfigWithChildren(configuration.GetSection("MyDictionary")) is IConfigurationSection section5) + { + Dictionary? temp7 = obj.MyDictionary; + temp7 ??= new Dictionary(); + BindCore(section5, ref temp7, binderOptions); + obj.MyDictionary = temp7; + } + + if (AsConfigWithChildren(configuration.GetSection("MyComplexDictionary")) is IConfigurationSection section8) + { + Dictionary? temp10 = obj.MyComplexDictionary; + temp10 ??= new Dictionary(); + BindCore(section8, ref temp10, binderOptions); + obj.MyComplexDictionary = temp10; + } + } + + /// If required by the binder options, validates that there are no unknown keys in the input configuration object. + public static void ValidateConfigurationKeys(Type type, Lazy> keys, IConfiguration configuration, BinderOptions? binderOptions) + { + if (binderOptions?.ErrorOnUnknownConfiguration is true) + { + List? temp = null; + + foreach (IConfigurationSection section in configuration.GetChildren()) + { + if (!keys.Value.Contains(section.Key)) + { + (temp ??= new List()).Add($"'{section.Key}'"); + } + } + + if (temp is not null) + { + throw new InvalidOperationException($"'ErrorOnUnknownConfiguration' was set on the provided BinderOptions, but the following properties were not found on the instance of {type}: {string.Join(", ", temp)}"); + } + } + } + + public static IConfiguration? AsConfigWithChildren(IConfiguration configuration) + { + foreach (IConfigurationSection _ in configuration.GetChildren()) + { + return configuration; + } + return null; + } + + public static int ParseInt(string value, Func getPath) + { + try + { + return int.Parse(value, NumberStyles.Integer, CultureInfo.InvariantCulture); + } + catch (Exception exception) + { + throw new InvalidOperationException($"Failed to convert configuration value at '{getPath()}' to type '{typeof(int)}'.", exception); + } + } + } +} diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Bind_Instance_BinderOptions.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Bind_Instance_BinderOptions.generated.txt index 4703980996b88..2cbc192b2867d 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Bind_Instance_BinderOptions.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Bind_Instance_BinderOptions.generated.txt @@ -34,15 +34,8 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration [InterceptsLocationAttribute(@"src-0.cs", 12, 20)] public static void Bind_ProgramMyClass(this IConfiguration configuration, object? obj, Action? configureOptions) { - if (configuration is null) - { - throw new ArgumentNullException(nameof(configuration)); - } - - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } + ArgumentNullException.ThrowIfNull(configuration); + ArgumentNullException.ThrowIfNull(obj); var typedObj = (Program.MyClass)obj; BindCore(configuration, ref typedObj, GetBinderOptions(configureOptions)); diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Bind_Instance_BinderOptions.net462.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Bind_Instance_BinderOptions.net462.generated.txt new file mode 100644 index 0000000000000..a1cb7d6b93b5d --- /dev/null +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Bind_Instance_BinderOptions.net462.generated.txt @@ -0,0 +1,178 @@ +// +#nullable enable +#pragma warning disable CS0612, CS0618 // Suppress warnings about [Obsolete] member usage in generated code. + +/// Generated helper providing an AOT and linking compatible implementation for configuration binding. +[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")] +internal static class GeneratedConfigurationBinder +{ + /// Attempts to bind the given object instance to configuration values by matching property names against configuration keys recursively. + public static void Bind(this global::Microsoft.Extensions.Configuration.IConfiguration configuration, global::Program.MyClass obj, global::System.Action? configureOptions) => global::Microsoft.Extensions.Configuration.Binder.SourceGeneration.CoreBindingHelper.BindCore(configuration, ref obj, global::Microsoft.Extensions.Configuration.Binder.SourceGeneration.CoreBindingHelper.GetBinderOptions(configureOptions)); +} + +namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration +{ + using Microsoft.Extensions.Configuration; + using System; + using System.CodeDom.Compiler; + using System.Collections.Generic; + using System.Globalization; + + /// Provide core binding logic. + [GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")] + file static class CoreBindingHelper + { + private readonly static Lazy> s_configKeys_ProgramMyClass = new(() => new HashSet(StringComparer.OrdinalIgnoreCase) { "MyString", "MyInt", "MyList", "MyDictionary", "MyComplexDictionary" }); + + public static void BindCore(IConfiguration configuration, ref List obj, BinderOptions? binderOptions) + { + if (obj is null) + { + throw new ArgumentNullException(nameof(obj)); + } + + foreach (IConfigurationSection section in configuration.GetChildren()) + { + if (section.Value is string value) + { + obj.Add(ParseInt(value, () => section.Path)); + } + } + } + + public static void BindCore(IConfiguration configuration, ref Dictionary obj, BinderOptions? binderOptions) + { + if (obj is null) + { + throw new ArgumentNullException(nameof(obj)); + } + + foreach (IConfigurationSection section in configuration.GetChildren()) + { + if (section.Value is string value) + { + obj[section.Key] = value; + } + } + } + + public static void BindCore(IConfiguration configuration, ref Dictionary obj, BinderOptions? binderOptions) + { + if (obj is null) + { + throw new ArgumentNullException(nameof(obj)); + } + + foreach (IConfigurationSection section in configuration.GetChildren()) + { + if (!(obj.TryGetValue(section.Key, out Program.MyClass2? element) && element is not null)) + { + element = new Program.MyClass2(); + } + obj[section.Key] = element; + } + } + + public static void BindCore(IConfiguration configuration, ref Program.MyClass obj, BinderOptions? binderOptions) + { + if (obj is null) + { + throw new ArgumentNullException(nameof(obj)); + } + + ValidateConfigurationKeys(typeof(Program.MyClass), s_configKeys_ProgramMyClass, configuration, binderOptions); + + obj.MyString = configuration["MyString"]!; + + if (configuration["MyInt"] is string value1) + { + obj.MyInt = ParseInt(value1, () => configuration.GetSection("MyInt").Path); + } + + if (AsConfigWithChildren(configuration.GetSection("MyList")) is IConfigurationSection section2) + { + List? temp4 = obj.MyList; + temp4 ??= new List(); + BindCore(section2, ref temp4, binderOptions); + obj.MyList = temp4; + } + + if (AsConfigWithChildren(configuration.GetSection("MyDictionary")) is IConfigurationSection section5) + { + Dictionary? temp7 = obj.MyDictionary; + temp7 ??= new Dictionary(); + BindCore(section5, ref temp7, binderOptions); + obj.MyDictionary = temp7; + } + + if (AsConfigWithChildren(configuration.GetSection("MyComplexDictionary")) is IConfigurationSection section8) + { + Dictionary? temp10 = obj.MyComplexDictionary; + temp10 ??= new Dictionary(); + BindCore(section8, ref temp10, binderOptions); + obj.MyComplexDictionary = temp10; + } + } + + /// If required by the binder options, validates that there are no unknown keys in the input configuration object. + public static void ValidateConfigurationKeys(Type type, Lazy> keys, IConfiguration configuration, BinderOptions? binderOptions) + { + if (binderOptions?.ErrorOnUnknownConfiguration is true) + { + List? temp = null; + + foreach (IConfigurationSection section in configuration.GetChildren()) + { + if (!keys.Value.Contains(section.Key)) + { + (temp ??= new List()).Add($"'{section.Key}'"); + } + } + + if (temp is not null) + { + throw new InvalidOperationException($"'ErrorOnUnknownConfiguration' was set on the provided BinderOptions, but the following properties were not found on the instance of {type}: {string.Join(", ", temp)}"); + } + } + } + + public static IConfiguration? AsConfigWithChildren(IConfiguration configuration) + { + foreach (IConfigurationSection _ in configuration.GetChildren()) + { + return configuration; + } + return null; + } + + public static BinderOptions? GetBinderOptions(Action? configureOptions) + { + if (configureOptions is null) + { + return null; + } + + BinderOptions binderOptions = new(); + configureOptions(binderOptions); + + if (binderOptions.BindNonPublicProperties) + { + throw new global::System.NotSupportedException($"The configuration binding source generator does not support 'BinderOptions.BindNonPublicProperties'."); + } + + return binderOptions; + } + + public static int ParseInt(string value, Func getPath) + { + try + { + return int.Parse(value, NumberStyles.Integer, CultureInfo.InvariantCulture); + } + catch (Exception exception) + { + throw new InvalidOperationException($"Failed to convert configuration value at '{getPath()}' to type '{typeof(int)}'.", exception); + } + } + } +} diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Bind_Key_Instance.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Bind_Key_Instance.generated.txt index 9937129699716..48dceb11e053f 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Bind_Key_Instance.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Bind_Key_Instance.generated.txt @@ -34,15 +34,8 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration [InterceptsLocationAttribute(@"src-0.cs", 12, 20)] public static void Bind_ProgramMyClass(this IConfiguration configuration, string key, object? obj) { - if (configuration is null) - { - throw new ArgumentNullException(nameof(configuration)); - } - - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } + ArgumentNullException.ThrowIfNull(configuration); + ArgumentNullException.ThrowIfNull(obj); var typedObj = (Program.MyClass)obj; BindCore(configuration.GetSection(key), ref typedObj, binderOptions: null); diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Bind_Key_Instance.net462.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Bind_Key_Instance.net462.generated.txt new file mode 100644 index 0000000000000..f3ee8a9ff4384 --- /dev/null +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Bind_Key_Instance.net462.generated.txt @@ -0,0 +1,160 @@ +// +#nullable enable +#pragma warning disable CS0612, CS0618 // Suppress warnings about [Obsolete] member usage in generated code. + +/// Generated helper providing an AOT and linking compatible implementation for configuration binding. +[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")] +internal static class GeneratedConfigurationBinder +{ + /// Attempts to bind the given object instance to configuration values by matching property names against configuration keys recursively. + public static void Bind(this global::Microsoft.Extensions.Configuration.IConfiguration configuration, string key, global::Program.MyClass obj) => global::Microsoft.Extensions.Configuration.Binder.SourceGeneration.CoreBindingHelper.BindCore(configuration.GetSection(key), ref obj, binderOptions: null); +} + +namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration +{ + using Microsoft.Extensions.Configuration; + using System; + using System.CodeDom.Compiler; + using System.Collections.Generic; + using System.Globalization; + + /// Provide core binding logic. + [GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")] + file static class CoreBindingHelper + { + private readonly static Lazy> s_configKeys_ProgramMyClass = new(() => new HashSet(StringComparer.OrdinalIgnoreCase) { "MyString", "MyInt", "MyList", "MyDictionary", "MyComplexDictionary" }); + + public static void BindCore(IConfiguration configuration, ref List obj, BinderOptions? binderOptions) + { + if (obj is null) + { + throw new ArgumentNullException(nameof(obj)); + } + + foreach (IConfigurationSection section in configuration.GetChildren()) + { + if (section.Value is string value) + { + obj.Add(ParseInt(value, () => section.Path)); + } + } + } + + public static void BindCore(IConfiguration configuration, ref Dictionary obj, BinderOptions? binderOptions) + { + if (obj is null) + { + throw new ArgumentNullException(nameof(obj)); + } + + foreach (IConfigurationSection section in configuration.GetChildren()) + { + if (section.Value is string value) + { + obj[section.Key] = value; + } + } + } + + public static void BindCore(IConfiguration configuration, ref Dictionary obj, BinderOptions? binderOptions) + { + if (obj is null) + { + throw new ArgumentNullException(nameof(obj)); + } + + foreach (IConfigurationSection section in configuration.GetChildren()) + { + if (!(obj.TryGetValue(section.Key, out Program.MyClass2? element) && element is not null)) + { + element = new Program.MyClass2(); + } + obj[section.Key] = element; + } + } + + public static void BindCore(IConfiguration configuration, ref Program.MyClass obj, BinderOptions? binderOptions) + { + if (obj is null) + { + throw new ArgumentNullException(nameof(obj)); + } + + ValidateConfigurationKeys(typeof(Program.MyClass), s_configKeys_ProgramMyClass, configuration, binderOptions); + + obj.MyString = configuration["MyString"]!; + + if (configuration["MyInt"] is string value1) + { + obj.MyInt = ParseInt(value1, () => configuration.GetSection("MyInt").Path); + } + + if (AsConfigWithChildren(configuration.GetSection("MyList")) is IConfigurationSection section2) + { + List? temp4 = obj.MyList; + temp4 ??= new List(); + BindCore(section2, ref temp4, binderOptions); + obj.MyList = temp4; + } + + if (AsConfigWithChildren(configuration.GetSection("MyDictionary")) is IConfigurationSection section5) + { + Dictionary? temp7 = obj.MyDictionary; + temp7 ??= new Dictionary(); + BindCore(section5, ref temp7, binderOptions); + obj.MyDictionary = temp7; + } + + if (AsConfigWithChildren(configuration.GetSection("MyComplexDictionary")) is IConfigurationSection section8) + { + Dictionary? temp10 = obj.MyComplexDictionary; + temp10 ??= new Dictionary(); + BindCore(section8, ref temp10, binderOptions); + obj.MyComplexDictionary = temp10; + } + } + + /// If required by the binder options, validates that there are no unknown keys in the input configuration object. + public static void ValidateConfigurationKeys(Type type, Lazy> keys, IConfiguration configuration, BinderOptions? binderOptions) + { + if (binderOptions?.ErrorOnUnknownConfiguration is true) + { + List? temp = null; + + foreach (IConfigurationSection section in configuration.GetChildren()) + { + if (!keys.Value.Contains(section.Key)) + { + (temp ??= new List()).Add($"'{section.Key}'"); + } + } + + if (temp is not null) + { + throw new InvalidOperationException($"'ErrorOnUnknownConfiguration' was set on the provided BinderOptions, but the following properties were not found on the instance of {type}: {string.Join(", ", temp)}"); + } + } + } + + public static IConfiguration? AsConfigWithChildren(IConfiguration configuration) + { + foreach (IConfigurationSection _ in configuration.GetChildren()) + { + return configuration; + } + return null; + } + + public static int ParseInt(string value, Func getPath) + { + try + { + return int.Parse(value, NumberStyles.Integer, CultureInfo.InvariantCulture); + } + catch (Exception exception) + { + throw new InvalidOperationException($"Failed to convert configuration value at '{getPath()}' to type '{typeof(int)}'.", exception); + } + } + } +} diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Get.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Get.generated.txt index 3e6ce1459b289..086b53ffb5d02 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Get.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Get.generated.txt @@ -53,10 +53,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration public static object? GetCore(this IConfiguration configuration, Type type, Action? configureOptions) { - if (configuration is null) - { - throw new ArgumentNullException(nameof(configuration)); - } + ArgumentNullException.ThrowIfNull(configuration); BinderOptions? binderOptions = GetBinderOptions(configureOptions); diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Get.net462.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Get.net462.generated.txt new file mode 100644 index 0000000000000..fb71c70b4dd3b --- /dev/null +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Get.net462.generated.txt @@ -0,0 +1,240 @@ +// +#nullable enable +#pragma warning disable CS0612, CS0618 // Suppress warnings about [Obsolete] member usage in generated code. + +/// Generated helper providing an AOT and linking compatible implementation for configuration binding. +[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")] +internal static class GeneratedConfigurationBinder +{ + /// Attempts to bind the configuration instance to a new instance of type T. + public static T? Get(this global::Microsoft.Extensions.Configuration.IConfiguration configuration) => (T?)(global::Microsoft.Extensions.Configuration.Binder.SourceGeneration.CoreBindingHelper.GetCore(configuration, typeof(T), configureOptions: null) ?? default(T)); + + /// Attempts to bind the configuration instance to a new instance of type T. + public static T? Get(this global::Microsoft.Extensions.Configuration.IConfiguration configuration, global::System.Action? configureOptions) => (T?)(global::Microsoft.Extensions.Configuration.Binder.SourceGeneration.CoreBindingHelper.GetCore(configuration, typeof(T), configureOptions) ?? default(T)); + + /// Attempts to bind the configuration instance to a new instance of type T. + public static object? Get(this global::Microsoft.Extensions.Configuration.IConfiguration configuration, global::System.Type type) => global::Microsoft.Extensions.Configuration.Binder.SourceGeneration.CoreBindingHelper.GetCore(configuration, type, configureOptions: null); + + /// Attempts to bind the configuration instance to a new instance of type T. + public static object? Get(this global::Microsoft.Extensions.Configuration.IConfiguration configuration, global::System.Type type, global::System.Action? configureOptions) => global::Microsoft.Extensions.Configuration.Binder.SourceGeneration.CoreBindingHelper.GetCore(configuration, type, configureOptions); +} + +namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration +{ + using Microsoft.Extensions.Configuration; + using System; + using System.CodeDom.Compiler; + using System.Collections.Generic; + using System.Globalization; + + /// Provide core binding logic. + [GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")] + file static class CoreBindingHelper + { + private readonly static Lazy> s_configKeys_ProgramMyClass = new(() => new HashSet(StringComparer.OrdinalIgnoreCase) { "MyString", "MyInt", "MyList", "MyArray", "MyDictionary" }); + private readonly static Lazy> s_configKeys_ProgramMyClass2 = new(() => new HashSet(StringComparer.OrdinalIgnoreCase) { "MyInt" }); + + public static object? GetCore(this IConfiguration configuration, Type type, Action? configureOptions) + { + if (configuration is null) + { + throw new ArgumentNullException(nameof(configuration)); + } + + BinderOptions? binderOptions = GetBinderOptions(configureOptions); + + if (!HasValueOrChildren(configuration)) + { + return null; + } + + if (type == typeof(Program.MyClass)) + { + var obj = new Program.MyClass(); + BindCore(configuration, ref obj, binderOptions); + return obj; + } + + if (type == typeof(Program.MyClass2)) + { + var obj = new Program.MyClass2(); + BindCore(configuration, ref obj, binderOptions); + return obj; + } + + throw new global::System.NotSupportedException($"Unable to bind to type '{type}': generator did not detect the type as input."); + } + + public static void BindCore(IConfiguration configuration, ref List obj, BinderOptions? binderOptions) + { + if (obj is null) + { + throw new ArgumentNullException(nameof(obj)); + } + + foreach (IConfigurationSection section in configuration.GetChildren()) + { + if (section.Value is string value) + { + obj.Add(ParseInt(value, () => section.Path)); + } + } + } + + public static void BindCore(IConfiguration configuration, ref int[] obj, BinderOptions? binderOptions) + { + if (obj is null) + { + throw new ArgumentNullException(nameof(obj)); + } + + var temp2 = new List(); + BindCore(configuration, ref temp2, binderOptions); + int originalCount = obj.Length; + Array.Resize(ref obj, originalCount + temp2.Count); + temp2.CopyTo(obj, originalCount); + } + + public static void BindCore(IConfiguration configuration, ref Dictionary obj, BinderOptions? binderOptions) + { + if (obj is null) + { + throw new ArgumentNullException(nameof(obj)); + } + + foreach (IConfigurationSection section in configuration.GetChildren()) + { + if (section.Value is string value) + { + obj[section.Key] = value; + } + } + } + + public static void BindCore(IConfiguration configuration, ref Program.MyClass obj, BinderOptions? binderOptions) + { + if (obj is null) + { + throw new ArgumentNullException(nameof(obj)); + } + + ValidateConfigurationKeys(typeof(Program.MyClass), s_configKeys_ProgramMyClass, configuration, binderOptions); + + obj.MyString = configuration["MyString"]!; + + if (configuration["MyInt"] is string value5) + { + obj.MyInt = ParseInt(value5, () => configuration.GetSection("MyInt").Path); + } + + if (AsConfigWithChildren(configuration.GetSection("MyList")) is IConfigurationSection section6) + { + List? temp8 = obj.MyList; + temp8 ??= new List(); + BindCore(section6, ref temp8, binderOptions); + obj.MyList = temp8; + } + + if (AsConfigWithChildren(configuration.GetSection("MyArray")) is IConfigurationSection section9) + { + int[]? temp11 = obj.MyArray; + temp11 ??= new int[0]; + BindCore(section9, ref temp11, binderOptions); + obj.MyArray = temp11; + } + + if (AsConfigWithChildren(configuration.GetSection("MyDictionary")) is IConfigurationSection section12) + { + Dictionary? temp14 = obj.MyDictionary; + temp14 ??= new Dictionary(); + BindCore(section12, ref temp14, binderOptions); + obj.MyDictionary = temp14; + } + } + + public static void BindCore(IConfiguration configuration, ref Program.MyClass2 obj, BinderOptions? binderOptions) + { + if (obj is null) + { + throw new ArgumentNullException(nameof(obj)); + } + + ValidateConfigurationKeys(typeof(Program.MyClass2), s_configKeys_ProgramMyClass2, configuration, binderOptions); + + if (configuration["MyInt"] is string value15) + { + obj.MyInt = ParseInt(value15, () => configuration.GetSection("MyInt").Path); + } + } + + /// If required by the binder options, validates that there are no unknown keys in the input configuration object. + public static void ValidateConfigurationKeys(Type type, Lazy> keys, IConfiguration configuration, BinderOptions? binderOptions) + { + if (binderOptions?.ErrorOnUnknownConfiguration is true) + { + List? temp = null; + + foreach (IConfigurationSection section in configuration.GetChildren()) + { + if (!keys.Value.Contains(section.Key)) + { + (temp ??= new List()).Add($"'{section.Key}'"); + } + } + + if (temp is not null) + { + throw new InvalidOperationException($"'ErrorOnUnknownConfiguration' was set on the provided BinderOptions, but the following properties were not found on the instance of {type}: {string.Join(", ", temp)}"); + } + } + } + + public static bool HasValueOrChildren(IConfiguration configuration) + { + if ((configuration as IConfigurationSection)?.Value is not null) + { + return true; + } + return AsConfigWithChildren(configuration) is not null; + } + + public static IConfiguration? AsConfigWithChildren(IConfiguration configuration) + { + foreach (IConfigurationSection _ in configuration.GetChildren()) + { + return configuration; + } + return null; + } + + public static BinderOptions? GetBinderOptions(Action? configureOptions) + { + if (configureOptions is null) + { + return null; + } + + BinderOptions binderOptions = new(); + configureOptions(binderOptions); + + if (binderOptions.BindNonPublicProperties) + { + throw new global::System.NotSupportedException($"The configuration binding source generator does not support 'BinderOptions.BindNonPublicProperties'."); + } + + return binderOptions; + } + + public static int ParseInt(string value, Func getPath) + { + try + { + return int.Parse(value, NumberStyles.Integer, CultureInfo.InvariantCulture); + } + catch (Exception exception) + { + throw new InvalidOperationException($"Failed to convert configuration value at '{getPath()}' to type '{typeof(int)}'.", exception); + } + } + } +} diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/GetValue.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/GetValue.generated.txt index e4bcaf6a9b7c9..7f953e8bee734 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/GetValue.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/GetValue.generated.txt @@ -49,10 +49,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration #region Core binding extensions. public static object? GetValueCore(this IConfiguration configuration, Type type, string key) { - if (configuration is null) - { - throw new ArgumentNullException(nameof(configuration)); - } + ArgumentNullException.ThrowIfNull(configuration); IConfigurationSection section = configuration.GetSection(key); diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/GetValue.net462.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/GetValue.net462.generated.txt new file mode 100644 index 0000000000000..c9d49faa93724 --- /dev/null +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/GetValue.net462.generated.txt @@ -0,0 +1,118 @@ +// +#nullable enable +#pragma warning disable CS0612, CS0618 // Suppress warnings about [Obsolete] member usage in generated code. + +/// Generated helper providing an AOT and linking compatible implementation for configuration binding. +[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")] +internal static class GeneratedConfigurationBinder +{ + /// Extracts the value with the specified key and converts it to the specified type. + public static T? GetValue(this global::Microsoft.Extensions.Configuration.IConfiguration configuration, string key) => (T?)(global::Microsoft.Extensions.Configuration.Binder.SourceGeneration.CoreBindingHelper.GetValueCore(configuration, typeof(T), key) ?? default(T)); + + /// Extracts the value with the specified key and converts it to the specified type. + public static T? GetValue(this global::Microsoft.Extensions.Configuration.IConfiguration configuration, string key, T defaultValue) => (T?)(global::Microsoft.Extensions.Configuration.Binder.SourceGeneration.CoreBindingHelper.GetValueCore(configuration, typeof(T), key) ?? defaultValue); + + /// Extracts the value with the specified key and converts it to the specified type. + public static object? GetValue(this global::Microsoft.Extensions.Configuration.IConfiguration configuration, global::System.Type type, string key) => global::Microsoft.Extensions.Configuration.Binder.SourceGeneration.CoreBindingHelper.GetValueCore(configuration, type, key); + + /// Extracts the value with the specified key and converts it to the specified type. + public static object? GetValue(this global::Microsoft.Extensions.Configuration.IConfiguration configuration, global::System.Type type, string key, object? defaultValue) => global::Microsoft.Extensions.Configuration.Binder.SourceGeneration.CoreBindingHelper.GetValueCore(configuration, type, key) ?? defaultValue; +} + +namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration +{ + using Microsoft.Extensions.Configuration; + using System; + using System.CodeDom.Compiler; + using System.Globalization; + + /// Provide core binding logic. + [GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")] + file static class CoreBindingHelper + { + public static object? GetValueCore(this IConfiguration configuration, Type type, string key) + { + if (configuration is null) + { + throw new ArgumentNullException(nameof(configuration)); + } + + IConfigurationSection section = configuration.GetSection(key); + + if (section.Value is not string value) + { + return null; + } + + if (type == typeof(int)) + { + return ParseInt(value, () => section.Path); + } + + if (type == typeof(bool?)) + { + return ParseBool(value, () => section.Path); + } + + if (type == typeof(byte[])) + { + return ParseByteArray(value, () => section.Path); + } + + if (type == typeof(CultureInfo)) + { + return ParseCultureInfo(value, () => section.Path); + } + + return null; + } + + public static int ParseInt(string value, Func getPath) + { + try + { + return int.Parse(value, NumberStyles.Integer, CultureInfo.InvariantCulture); + } + catch (Exception exception) + { + throw new InvalidOperationException($"Failed to convert configuration value at '{getPath()}' to type '{typeof(int)}'.", exception); + } + } + + public static bool ParseBool(string value, Func getPath) + { + try + { + return bool.Parse(value); + } + catch (Exception exception) + { + throw new InvalidOperationException($"Failed to convert configuration value at '{getPath()}' to type '{typeof(bool)}'.", exception); + } + } + + public static byte[] ParseByteArray(string value, Func getPath) + { + try + { + return Convert.FromBase64String(value); + } + catch (Exception exception) + { + throw new InvalidOperationException($"Failed to convert configuration value at '{getPath()}' to type '{typeof(byte[])}'.", exception); + } + } + + public static CultureInfo ParseCultureInfo(string value, Func getPath) + { + try + { + return CultureInfo.GetCultureInfo(value); + } + catch (Exception exception) + { + throw new InvalidOperationException($"Failed to convert configuration value at '{getPath()}' to type '{typeof(CultureInfo)}'.", exception); + } + } + } +} diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/GetValue_T_Key.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/GetValue_T_Key.generated.txt index 2438cf530ca4c..e32282a61de77 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/GetValue_T_Key.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/GetValue_T_Key.generated.txt @@ -37,10 +37,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration #region Core binding extensions. public static object? GetValueCore(this IConfiguration configuration, Type type, string key) { - if (configuration is null) - { - throw new ArgumentNullException(nameof(configuration)); - } + ArgumentNullException.ThrowIfNull(configuration); IConfigurationSection section = configuration.GetSection(key); diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/GetValue_T_Key.net462.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/GetValue_T_Key.net462.generated.txt new file mode 100644 index 0000000000000..17c963bd980a7 --- /dev/null +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/GetValue_T_Key.net462.generated.txt @@ -0,0 +1,58 @@ +// +#nullable enable +#pragma warning disable CS0612, CS0618 // Suppress warnings about [Obsolete] member usage in generated code. + +/// Generated helper providing an AOT and linking compatible implementation for configuration binding. +[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")] +internal static class GeneratedConfigurationBinder +{ + /// Extracts the value with the specified key and converts it to the specified type. + public static T? GetValue(this global::Microsoft.Extensions.Configuration.IConfiguration configuration, string key) => (T?)(global::Microsoft.Extensions.Configuration.Binder.SourceGeneration.CoreBindingHelper.GetValueCore(configuration, typeof(T), key) ?? default(T)); +} + +namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration +{ + using Microsoft.Extensions.Configuration; + using System; + using System.CodeDom.Compiler; + using System.Globalization; + + /// Provide core binding logic. + [GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")] + file static class CoreBindingHelper + { + public static object? GetValueCore(this IConfiguration configuration, Type type, string key) + { + if (configuration is null) + { + throw new ArgumentNullException(nameof(configuration)); + } + + IConfigurationSection section = configuration.GetSection(key); + + if (section.Value is not string value) + { + return null; + } + + if (type == typeof(int)) + { + return ParseInt(value, () => section.Path); + } + + return null; + } + + public static int ParseInt(string value, Func getPath) + { + try + { + return int.Parse(value, NumberStyles.Integer, CultureInfo.InvariantCulture); + } + catch (Exception exception) + { + throw new InvalidOperationException($"Failed to convert configuration value at '{getPath()}' to type '{typeof(int)}'.", exception); + } + } + } +} diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/GetValue_T_Key_DefaultValue.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/GetValue_T_Key_DefaultValue.generated.txt index e6db24d522f3c..1d2ef31f595c7 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/GetValue_T_Key_DefaultValue.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/GetValue_T_Key_DefaultValue.generated.txt @@ -37,10 +37,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration #region Core binding extensions. public static object? GetValueCore(this IConfiguration configuration, Type type, string key) { - if (configuration is null) - { - throw new ArgumentNullException(nameof(configuration)); - } + ArgumentNullException.ThrowIfNull(configuration); IConfigurationSection section = configuration.GetSection(key); diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/GetValue_T_Key_DefaultValue.net462.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/GetValue_T_Key_DefaultValue.net462.generated.txt new file mode 100644 index 0000000000000..1148109b9f5a8 --- /dev/null +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/GetValue_T_Key_DefaultValue.net462.generated.txt @@ -0,0 +1,58 @@ +// +#nullable enable +#pragma warning disable CS0612, CS0618 // Suppress warnings about [Obsolete] member usage in generated code. + +/// Generated helper providing an AOT and linking compatible implementation for configuration binding. +[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")] +internal static class GeneratedConfigurationBinder +{ + /// Extracts the value with the specified key and converts it to the specified type. + public static T? GetValue(this global::Microsoft.Extensions.Configuration.IConfiguration configuration, string key, T defaultValue) => (T?)(global::Microsoft.Extensions.Configuration.Binder.SourceGeneration.CoreBindingHelper.GetValueCore(configuration, typeof(T), key) ?? defaultValue); +} + +namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration +{ + using Microsoft.Extensions.Configuration; + using System; + using System.CodeDom.Compiler; + using System.Globalization; + + /// Provide core binding logic. + [GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")] + file static class CoreBindingHelper + { + public static object? GetValueCore(this IConfiguration configuration, Type type, string key) + { + if (configuration is null) + { + throw new ArgumentNullException(nameof(configuration)); + } + + IConfigurationSection section = configuration.GetSection(key); + + if (section.Value is not string value) + { + return null; + } + + if (type == typeof(int)) + { + return ParseInt(value, () => section.Path); + } + + return null; + } + + public static int ParseInt(string value, Func getPath) + { + try + { + return int.Parse(value, NumberStyles.Integer, CultureInfo.InvariantCulture); + } + catch (Exception exception) + { + throw new InvalidOperationException($"Failed to convert configuration value at '{getPath()}' to type '{typeof(int)}'.", exception); + } + } + } +} diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/GetValue_TypeOf_Key.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/GetValue_TypeOf_Key.generated.txt index a36f9fafebcff..e82cb9516c514 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/GetValue_TypeOf_Key.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/GetValue_TypeOf_Key.generated.txt @@ -37,10 +37,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration #region Core binding extensions. public static object? GetValueCore(this IConfiguration configuration, Type type, string key) { - if (configuration is null) - { - throw new ArgumentNullException(nameof(configuration)); - } + ArgumentNullException.ThrowIfNull(configuration); IConfigurationSection section = configuration.GetSection(key); diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/GetValue_TypeOf_Key.net462.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/GetValue_TypeOf_Key.net462.generated.txt new file mode 100644 index 0000000000000..c833b20f18dcf --- /dev/null +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/GetValue_TypeOf_Key.net462.generated.txt @@ -0,0 +1,58 @@ +// +#nullable enable +#pragma warning disable CS0612, CS0618 // Suppress warnings about [Obsolete] member usage in generated code. + +/// Generated helper providing an AOT and linking compatible implementation for configuration binding. +[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")] +internal static class GeneratedConfigurationBinder +{ + /// Extracts the value with the specified key and converts it to the specified type. + public static object? GetValue(this global::Microsoft.Extensions.Configuration.IConfiguration configuration, global::System.Type type, string key) => global::Microsoft.Extensions.Configuration.Binder.SourceGeneration.CoreBindingHelper.GetValueCore(configuration, type, key); +} + +namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration +{ + using Microsoft.Extensions.Configuration; + using System; + using System.CodeDom.Compiler; + using System.Globalization; + + /// Provide core binding logic. + [GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")] + file static class CoreBindingHelper + { + public static object? GetValueCore(this IConfiguration configuration, Type type, string key) + { + if (configuration is null) + { + throw new ArgumentNullException(nameof(configuration)); + } + + IConfigurationSection section = configuration.GetSection(key); + + if (section.Value is not string value) + { + return null; + } + + if (type == typeof(bool?)) + { + return ParseBool(value, () => section.Path); + } + + return null; + } + + public static bool ParseBool(string value, Func getPath) + { + try + { + return bool.Parse(value); + } + catch (Exception exception) + { + throw new InvalidOperationException($"Failed to convert configuration value at '{getPath()}' to type '{typeof(bool)}'.", exception); + } + } + } +} diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/GetValue_TypeOf_Key_DefaultValue.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/GetValue_TypeOf_Key_DefaultValue.generated.txt index 356f6bb1a933e..5973a4a315f15 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/GetValue_TypeOf_Key_DefaultValue.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/GetValue_TypeOf_Key_DefaultValue.generated.txt @@ -37,10 +37,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration #region Core binding extensions. public static object? GetValueCore(this IConfiguration configuration, Type type, string key) { - if (configuration is null) - { - throw new ArgumentNullException(nameof(configuration)); - } + ArgumentNullException.ThrowIfNull(configuration); IConfigurationSection section = configuration.GetSection(key); diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/GetValue_TypeOf_Key_DefaultValue.net462.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/GetValue_TypeOf_Key_DefaultValue.net462.generated.txt new file mode 100644 index 0000000000000..f773f79ce6c2c --- /dev/null +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/GetValue_TypeOf_Key_DefaultValue.net462.generated.txt @@ -0,0 +1,58 @@ +// +#nullable enable +#pragma warning disable CS0612, CS0618 // Suppress warnings about [Obsolete] member usage in generated code. + +/// Generated helper providing an AOT and linking compatible implementation for configuration binding. +[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")] +internal static class GeneratedConfigurationBinder +{ + /// Extracts the value with the specified key and converts it to the specified type. + public static object? GetValue(this global::Microsoft.Extensions.Configuration.IConfiguration configuration, global::System.Type type, string key, object? defaultValue) => global::Microsoft.Extensions.Configuration.Binder.SourceGeneration.CoreBindingHelper.GetValueCore(configuration, type, key) ?? defaultValue; +} + +namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration +{ + using Microsoft.Extensions.Configuration; + using System; + using System.CodeDom.Compiler; + using System.Globalization; + + /// Provide core binding logic. + [GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")] + file static class CoreBindingHelper + { + public static object? GetValueCore(this IConfiguration configuration, Type type, string key) + { + if (configuration is null) + { + throw new ArgumentNullException(nameof(configuration)); + } + + IConfigurationSection section = configuration.GetSection(key); + + if (section.Value is not string value) + { + return null; + } + + if (type == typeof(CultureInfo)) + { + return ParseCultureInfo(value, () => section.Path); + } + + return null; + } + + public static CultureInfo ParseCultureInfo(string value, Func getPath) + { + try + { + return CultureInfo.GetCultureInfo(value); + } + catch (Exception exception) + { + throw new InvalidOperationException($"Failed to convert configuration value at '{getPath()}' to type '{typeof(CultureInfo)}'.", exception); + } + } + } +} diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Get_T.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Get_T.generated.txt index 85d0901de3ff6..7f0927705f914 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Get_T.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Get_T.generated.txt @@ -40,10 +40,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration public static object? GetCore(this IConfiguration configuration, Type type, Action? configureOptions) { - if (configuration is null) - { - throw new ArgumentNullException(nameof(configuration)); - } + ArgumentNullException.ThrowIfNull(configuration); BinderOptions? binderOptions = GetBinderOptions(configureOptions); diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Get_T.net462.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Get_T.net462.generated.txt new file mode 100644 index 0000000000000..de8201fe6fed2 --- /dev/null +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Get_T.net462.generated.txt @@ -0,0 +1,208 @@ +// +#nullable enable +#pragma warning disable CS0612, CS0618 // Suppress warnings about [Obsolete] member usage in generated code. + +/// Generated helper providing an AOT and linking compatible implementation for configuration binding. +[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")] +internal static class GeneratedConfigurationBinder +{ + /// Attempts to bind the configuration instance to a new instance of type T. + public static T? Get(this global::Microsoft.Extensions.Configuration.IConfiguration configuration) => (T?)(global::Microsoft.Extensions.Configuration.Binder.SourceGeneration.CoreBindingHelper.GetCore(configuration, typeof(T), configureOptions: null) ?? default(T)); +} + +namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration +{ + using Microsoft.Extensions.Configuration; + using System; + using System.CodeDom.Compiler; + using System.Collections.Generic; + using System.Globalization; + + /// Provide core binding logic. + [GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")] + file static class CoreBindingHelper + { + private readonly static Lazy> s_configKeys_ProgramMyClass = new(() => new HashSet(StringComparer.OrdinalIgnoreCase) { "MyString", "MyInt", "MyList", "MyArray", "MyDictionary" }); + + public static object? GetCore(this IConfiguration configuration, Type type, Action? configureOptions) + { + if (configuration is null) + { + throw new ArgumentNullException(nameof(configuration)); + } + + BinderOptions? binderOptions = GetBinderOptions(configureOptions); + + if (!HasValueOrChildren(configuration)) + { + return null; + } + + if (type == typeof(Program.MyClass)) + { + var obj = new Program.MyClass(); + BindCore(configuration, ref obj, binderOptions); + return obj; + } + + throw new global::System.NotSupportedException($"Unable to bind to type '{type}': generator did not detect the type as input."); + } + + public static void BindCore(IConfiguration configuration, ref List obj, BinderOptions? binderOptions) + { + if (obj is null) + { + throw new ArgumentNullException(nameof(obj)); + } + + foreach (IConfigurationSection section in configuration.GetChildren()) + { + if (section.Value is string value) + { + obj.Add(ParseInt(value, () => section.Path)); + } + } + } + + public static void BindCore(IConfiguration configuration, ref int[] obj, BinderOptions? binderOptions) + { + if (obj is null) + { + throw new ArgumentNullException(nameof(obj)); + } + + var temp1 = new List(); + BindCore(configuration, ref temp1, binderOptions); + int originalCount = obj.Length; + Array.Resize(ref obj, originalCount + temp1.Count); + temp1.CopyTo(obj, originalCount); + } + + public static void BindCore(IConfiguration configuration, ref Dictionary obj, BinderOptions? binderOptions) + { + if (obj is null) + { + throw new ArgumentNullException(nameof(obj)); + } + + foreach (IConfigurationSection section in configuration.GetChildren()) + { + if (section.Value is string value) + { + obj[section.Key] = value; + } + } + } + + public static void BindCore(IConfiguration configuration, ref Program.MyClass obj, BinderOptions? binderOptions) + { + if (obj is null) + { + throw new ArgumentNullException(nameof(obj)); + } + + ValidateConfigurationKeys(typeof(Program.MyClass), s_configKeys_ProgramMyClass, configuration, binderOptions); + + obj.MyString = configuration["MyString"]!; + + if (configuration["MyInt"] is string value4) + { + obj.MyInt = ParseInt(value4, () => configuration.GetSection("MyInt").Path); + } + + if (AsConfigWithChildren(configuration.GetSection("MyList")) is IConfigurationSection section5) + { + List? temp7 = obj.MyList; + temp7 ??= new List(); + BindCore(section5, ref temp7, binderOptions); + obj.MyList = temp7; + } + + if (AsConfigWithChildren(configuration.GetSection("MyArray")) is IConfigurationSection section8) + { + int[]? temp10 = obj.MyArray; + temp10 ??= new int[0]; + BindCore(section8, ref temp10, binderOptions); + obj.MyArray = temp10; + } + + if (AsConfigWithChildren(configuration.GetSection("MyDictionary")) is IConfigurationSection section11) + { + Dictionary? temp13 = obj.MyDictionary; + temp13 ??= new Dictionary(); + BindCore(section11, ref temp13, binderOptions); + obj.MyDictionary = temp13; + } + } + + /// If required by the binder options, validates that there are no unknown keys in the input configuration object. + public static void ValidateConfigurationKeys(Type type, Lazy> keys, IConfiguration configuration, BinderOptions? binderOptions) + { + if (binderOptions?.ErrorOnUnknownConfiguration is true) + { + List? temp = null; + + foreach (IConfigurationSection section in configuration.GetChildren()) + { + if (!keys.Value.Contains(section.Key)) + { + (temp ??= new List()).Add($"'{section.Key}'"); + } + } + + if (temp is not null) + { + throw new InvalidOperationException($"'ErrorOnUnknownConfiguration' was set on the provided BinderOptions, but the following properties were not found on the instance of {type}: {string.Join(", ", temp)}"); + } + } + } + + public static bool HasValueOrChildren(IConfiguration configuration) + { + if ((configuration as IConfigurationSection)?.Value is not null) + { + return true; + } + return AsConfigWithChildren(configuration) is not null; + } + + public static IConfiguration? AsConfigWithChildren(IConfiguration configuration) + { + foreach (IConfigurationSection _ in configuration.GetChildren()) + { + return configuration; + } + return null; + } + + public static BinderOptions? GetBinderOptions(Action? configureOptions) + { + if (configureOptions is null) + { + return null; + } + + BinderOptions binderOptions = new(); + configureOptions(binderOptions); + + if (binderOptions.BindNonPublicProperties) + { + throw new global::System.NotSupportedException($"The configuration binding source generator does not support 'BinderOptions.BindNonPublicProperties'."); + } + + return binderOptions; + } + + public static int ParseInt(string value, Func getPath) + { + try + { + return int.Parse(value, NumberStyles.Integer, CultureInfo.InvariantCulture); + } + catch (Exception exception) + { + throw new InvalidOperationException($"Failed to convert configuration value at '{getPath()}' to type '{typeof(int)}'.", exception); + } + } + } +} diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Get_T_BinderOptions.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Get_T_BinderOptions.generated.txt index d394cc7b269f7..911a6d894a4ac 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Get_T_BinderOptions.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Get_T_BinderOptions.generated.txt @@ -40,10 +40,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration public static object? GetCore(this IConfiguration configuration, Type type, Action? configureOptions) { - if (configuration is null) - { - throw new ArgumentNullException(nameof(configuration)); - } + ArgumentNullException.ThrowIfNull(configuration); BinderOptions? binderOptions = GetBinderOptions(configureOptions); diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Get_T_BinderOptions.net462.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Get_T_BinderOptions.net462.generated.txt new file mode 100644 index 0000000000000..34fadacace146 --- /dev/null +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Get_T_BinderOptions.net462.generated.txt @@ -0,0 +1,208 @@ +// +#nullable enable +#pragma warning disable CS0612, CS0618 // Suppress warnings about [Obsolete] member usage in generated code. + +/// Generated helper providing an AOT and linking compatible implementation for configuration binding. +[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")] +internal static class GeneratedConfigurationBinder +{ + /// Attempts to bind the configuration instance to a new instance of type T. + public static T? Get(this global::Microsoft.Extensions.Configuration.IConfiguration configuration, global::System.Action? configureOptions) => (T?)(global::Microsoft.Extensions.Configuration.Binder.SourceGeneration.CoreBindingHelper.GetCore(configuration, typeof(T), configureOptions) ?? default(T)); +} + +namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration +{ + using Microsoft.Extensions.Configuration; + using System; + using System.CodeDom.Compiler; + using System.Collections.Generic; + using System.Globalization; + + /// Provide core binding logic. + [GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")] + file static class CoreBindingHelper + { + private readonly static Lazy> s_configKeys_ProgramMyClass = new(() => new HashSet(StringComparer.OrdinalIgnoreCase) { "MyString", "MyInt", "MyList", "MyArray", "MyDictionary" }); + + public static object? GetCore(this IConfiguration configuration, Type type, Action? configureOptions) + { + if (configuration is null) + { + throw new ArgumentNullException(nameof(configuration)); + } + + BinderOptions? binderOptions = GetBinderOptions(configureOptions); + + if (!HasValueOrChildren(configuration)) + { + return null; + } + + if (type == typeof(Program.MyClass)) + { + var obj = new Program.MyClass(); + BindCore(configuration, ref obj, binderOptions); + return obj; + } + + throw new global::System.NotSupportedException($"Unable to bind to type '{type}': generator did not detect the type as input."); + } + + public static void BindCore(IConfiguration configuration, ref List obj, BinderOptions? binderOptions) + { + if (obj is null) + { + throw new ArgumentNullException(nameof(obj)); + } + + foreach (IConfigurationSection section in configuration.GetChildren()) + { + if (section.Value is string value) + { + obj.Add(ParseInt(value, () => section.Path)); + } + } + } + + public static void BindCore(IConfiguration configuration, ref int[] obj, BinderOptions? binderOptions) + { + if (obj is null) + { + throw new ArgumentNullException(nameof(obj)); + } + + var temp1 = new List(); + BindCore(configuration, ref temp1, binderOptions); + int originalCount = obj.Length; + Array.Resize(ref obj, originalCount + temp1.Count); + temp1.CopyTo(obj, originalCount); + } + + public static void BindCore(IConfiguration configuration, ref Dictionary obj, BinderOptions? binderOptions) + { + if (obj is null) + { + throw new ArgumentNullException(nameof(obj)); + } + + foreach (IConfigurationSection section in configuration.GetChildren()) + { + if (section.Value is string value) + { + obj[section.Key] = value; + } + } + } + + public static void BindCore(IConfiguration configuration, ref Program.MyClass obj, BinderOptions? binderOptions) + { + if (obj is null) + { + throw new ArgumentNullException(nameof(obj)); + } + + ValidateConfigurationKeys(typeof(Program.MyClass), s_configKeys_ProgramMyClass, configuration, binderOptions); + + obj.MyString = configuration["MyString"]!; + + if (configuration["MyInt"] is string value4) + { + obj.MyInt = ParseInt(value4, () => configuration.GetSection("MyInt").Path); + } + + if (AsConfigWithChildren(configuration.GetSection("MyList")) is IConfigurationSection section5) + { + List? temp7 = obj.MyList; + temp7 ??= new List(); + BindCore(section5, ref temp7, binderOptions); + obj.MyList = temp7; + } + + if (AsConfigWithChildren(configuration.GetSection("MyArray")) is IConfigurationSection section8) + { + int[]? temp10 = obj.MyArray; + temp10 ??= new int[0]; + BindCore(section8, ref temp10, binderOptions); + obj.MyArray = temp10; + } + + if (AsConfigWithChildren(configuration.GetSection("MyDictionary")) is IConfigurationSection section11) + { + Dictionary? temp13 = obj.MyDictionary; + temp13 ??= new Dictionary(); + BindCore(section11, ref temp13, binderOptions); + obj.MyDictionary = temp13; + } + } + + /// If required by the binder options, validates that there are no unknown keys in the input configuration object. + public static void ValidateConfigurationKeys(Type type, Lazy> keys, IConfiguration configuration, BinderOptions? binderOptions) + { + if (binderOptions?.ErrorOnUnknownConfiguration is true) + { + List? temp = null; + + foreach (IConfigurationSection section in configuration.GetChildren()) + { + if (!keys.Value.Contains(section.Key)) + { + (temp ??= new List()).Add($"'{section.Key}'"); + } + } + + if (temp is not null) + { + throw new InvalidOperationException($"'ErrorOnUnknownConfiguration' was set on the provided BinderOptions, but the following properties were not found on the instance of {type}: {string.Join(", ", temp)}"); + } + } + } + + public static bool HasValueOrChildren(IConfiguration configuration) + { + if ((configuration as IConfigurationSection)?.Value is not null) + { + return true; + } + return AsConfigWithChildren(configuration) is not null; + } + + public static IConfiguration? AsConfigWithChildren(IConfiguration configuration) + { + foreach (IConfigurationSection _ in configuration.GetChildren()) + { + return configuration; + } + return null; + } + + public static BinderOptions? GetBinderOptions(Action? configureOptions) + { + if (configureOptions is null) + { + return null; + } + + BinderOptions binderOptions = new(); + configureOptions(binderOptions); + + if (binderOptions.BindNonPublicProperties) + { + throw new global::System.NotSupportedException($"The configuration binding source generator does not support 'BinderOptions.BindNonPublicProperties'."); + } + + return binderOptions; + } + + public static int ParseInt(string value, Func getPath) + { + try + { + return int.Parse(value, NumberStyles.Integer, CultureInfo.InvariantCulture); + } + catch (Exception exception) + { + throw new InvalidOperationException($"Failed to convert configuration value at '{getPath()}' to type '{typeof(int)}'.", exception); + } + } + } +} diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Get_TypeOf.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Get_TypeOf.generated.txt index 83cd88561310a..ccf8e72babcc9 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Get_TypeOf.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Get_TypeOf.generated.txt @@ -40,10 +40,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration public static object? GetCore(this IConfiguration configuration, Type type, Action? configureOptions) { - if (configuration is null) - { - throw new ArgumentNullException(nameof(configuration)); - } + ArgumentNullException.ThrowIfNull(configuration); BinderOptions? binderOptions = GetBinderOptions(configureOptions); diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Get_TypeOf.net462.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Get_TypeOf.net462.generated.txt new file mode 100644 index 0000000000000..16a98c931a705 --- /dev/null +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Get_TypeOf.net462.generated.txt @@ -0,0 +1,136 @@ +// +#nullable enable +#pragma warning disable CS0612, CS0618 // Suppress warnings about [Obsolete] member usage in generated code. + +/// Generated helper providing an AOT and linking compatible implementation for configuration binding. +[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")] +internal static class GeneratedConfigurationBinder +{ + /// Attempts to bind the configuration instance to a new instance of type T. + public static object? Get(this global::Microsoft.Extensions.Configuration.IConfiguration configuration, global::System.Type type) => global::Microsoft.Extensions.Configuration.Binder.SourceGeneration.CoreBindingHelper.GetCore(configuration, type, configureOptions: null); +} + +namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration +{ + using Microsoft.Extensions.Configuration; + using System; + using System.CodeDom.Compiler; + using System.Collections.Generic; + using System.Globalization; + + /// Provide core binding logic. + [GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")] + file static class CoreBindingHelper + { + private readonly static Lazy> s_configKeys_ProgramMyClass2 = new(() => new HashSet(StringComparer.OrdinalIgnoreCase) { "MyInt" }); + + public static object? GetCore(this IConfiguration configuration, Type type, Action? configureOptions) + { + if (configuration is null) + { + throw new ArgumentNullException(nameof(configuration)); + } + + BinderOptions? binderOptions = GetBinderOptions(configureOptions); + + if (!HasValueOrChildren(configuration)) + { + return null; + } + + if (type == typeof(Program.MyClass2)) + { + var obj = new Program.MyClass2(); + BindCore(configuration, ref obj, binderOptions); + return obj; + } + + throw new global::System.NotSupportedException($"Unable to bind to type '{type}': generator did not detect the type as input."); + } + + public static void BindCore(IConfiguration configuration, ref Program.MyClass2 obj, BinderOptions? binderOptions) + { + if (obj is null) + { + throw new ArgumentNullException(nameof(obj)); + } + + ValidateConfigurationKeys(typeof(Program.MyClass2), s_configKeys_ProgramMyClass2, configuration, binderOptions); + + if (configuration["MyInt"] is string value1) + { + obj.MyInt = ParseInt(value1, () => configuration.GetSection("MyInt").Path); + } + } + + /// If required by the binder options, validates that there are no unknown keys in the input configuration object. + public static void ValidateConfigurationKeys(Type type, Lazy> keys, IConfiguration configuration, BinderOptions? binderOptions) + { + if (binderOptions?.ErrorOnUnknownConfiguration is true) + { + List? temp = null; + + foreach (IConfigurationSection section in configuration.GetChildren()) + { + if (!keys.Value.Contains(section.Key)) + { + (temp ??= new List()).Add($"'{section.Key}'"); + } + } + + if (temp is not null) + { + throw new InvalidOperationException($"'ErrorOnUnknownConfiguration' was set on the provided BinderOptions, but the following properties were not found on the instance of {type}: {string.Join(", ", temp)}"); + } + } + } + + public static bool HasValueOrChildren(IConfiguration configuration) + { + if ((configuration as IConfigurationSection)?.Value is not null) + { + return true; + } + return AsConfigWithChildren(configuration) is not null; + } + + public static IConfiguration? AsConfigWithChildren(IConfiguration configuration) + { + foreach (IConfigurationSection _ in configuration.GetChildren()) + { + return configuration; + } + return null; + } + + public static BinderOptions? GetBinderOptions(Action? configureOptions) + { + if (configureOptions is null) + { + return null; + } + + BinderOptions binderOptions = new(); + configureOptions(binderOptions); + + if (binderOptions.BindNonPublicProperties) + { + throw new global::System.NotSupportedException($"The configuration binding source generator does not support 'BinderOptions.BindNonPublicProperties'."); + } + + return binderOptions; + } + + public static int ParseInt(string value, Func getPath) + { + try + { + return int.Parse(value, NumberStyles.Integer, CultureInfo.InvariantCulture); + } + catch (Exception exception) + { + throw new InvalidOperationException($"Failed to convert configuration value at '{getPath()}' to type '{typeof(int)}'.", exception); + } + } + } +} diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Get_TypeOf_BinderOptions.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Get_TypeOf_BinderOptions.generated.txt index 91714c80cd013..76cbc01b77eee 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Get_TypeOf_BinderOptions.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Get_TypeOf_BinderOptions.generated.txt @@ -40,10 +40,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration public static object? GetCore(this IConfiguration configuration, Type type, Action? configureOptions) { - if (configuration is null) - { - throw new ArgumentNullException(nameof(configuration)); - } + ArgumentNullException.ThrowIfNull(configuration); BinderOptions? binderOptions = GetBinderOptions(configureOptions); diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Get_TypeOf_BinderOptions.net462.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Get_TypeOf_BinderOptions.net462.generated.txt new file mode 100644 index 0000000000000..8d1ee9ed3cd9a --- /dev/null +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Get_TypeOf_BinderOptions.net462.generated.txt @@ -0,0 +1,136 @@ +// +#nullable enable +#pragma warning disable CS0612, CS0618 // Suppress warnings about [Obsolete] member usage in generated code. + +/// Generated helper providing an AOT and linking compatible implementation for configuration binding. +[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")] +internal static class GeneratedConfigurationBinder +{ + /// Attempts to bind the configuration instance to a new instance of type T. + public static object? Get(this global::Microsoft.Extensions.Configuration.IConfiguration configuration, global::System.Type type, global::System.Action? configureOptions) => global::Microsoft.Extensions.Configuration.Binder.SourceGeneration.CoreBindingHelper.GetCore(configuration, type, configureOptions); +} + +namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration +{ + using Microsoft.Extensions.Configuration; + using System; + using System.CodeDom.Compiler; + using System.Collections.Generic; + using System.Globalization; + + /// Provide core binding logic. + [GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")] + file static class CoreBindingHelper + { + private readonly static Lazy> s_configKeys_ProgramMyClass2 = new(() => new HashSet(StringComparer.OrdinalIgnoreCase) { "MyInt" }); + + public static object? GetCore(this IConfiguration configuration, Type type, Action? configureOptions) + { + if (configuration is null) + { + throw new ArgumentNullException(nameof(configuration)); + } + + BinderOptions? binderOptions = GetBinderOptions(configureOptions); + + if (!HasValueOrChildren(configuration)) + { + return null; + } + + if (type == typeof(Program.MyClass2)) + { + var obj = new Program.MyClass2(); + BindCore(configuration, ref obj, binderOptions); + return obj; + } + + throw new global::System.NotSupportedException($"Unable to bind to type '{type}': generator did not detect the type as input."); + } + + public static void BindCore(IConfiguration configuration, ref Program.MyClass2 obj, BinderOptions? binderOptions) + { + if (obj is null) + { + throw new ArgumentNullException(nameof(obj)); + } + + ValidateConfigurationKeys(typeof(Program.MyClass2), s_configKeys_ProgramMyClass2, configuration, binderOptions); + + if (configuration["MyInt"] is string value1) + { + obj.MyInt = ParseInt(value1, () => configuration.GetSection("MyInt").Path); + } + } + + /// If required by the binder options, validates that there are no unknown keys in the input configuration object. + public static void ValidateConfigurationKeys(Type type, Lazy> keys, IConfiguration configuration, BinderOptions? binderOptions) + { + if (binderOptions?.ErrorOnUnknownConfiguration is true) + { + List? temp = null; + + foreach (IConfigurationSection section in configuration.GetChildren()) + { + if (!keys.Value.Contains(section.Key)) + { + (temp ??= new List()).Add($"'{section.Key}'"); + } + } + + if (temp is not null) + { + throw new InvalidOperationException($"'ErrorOnUnknownConfiguration' was set on the provided BinderOptions, but the following properties were not found on the instance of {type}: {string.Join(", ", temp)}"); + } + } + } + + public static bool HasValueOrChildren(IConfiguration configuration) + { + if ((configuration as IConfigurationSection)?.Value is not null) + { + return true; + } + return AsConfigWithChildren(configuration) is not null; + } + + public static IConfiguration? AsConfigWithChildren(IConfiguration configuration) + { + foreach (IConfigurationSection _ in configuration.GetChildren()) + { + return configuration; + } + return null; + } + + public static BinderOptions? GetBinderOptions(Action? configureOptions) + { + if (configureOptions is null) + { + return null; + } + + BinderOptions binderOptions = new(); + configureOptions(binderOptions); + + if (binderOptions.BindNonPublicProperties) + { + throw new global::System.NotSupportedException($"The configuration binding source generator does not support 'BinderOptions.BindNonPublicProperties'."); + } + + return binderOptions; + } + + public static int ParseInt(string value, Func getPath) + { + try + { + return int.Parse(value, NumberStyles.Integer, CultureInfo.InvariantCulture); + } + catch (Exception exception) + { + throw new InvalidOperationException($"Failed to convert configuration value at '{getPath()}' to type '{typeof(int)}'.", exception); + } + } + } +} diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/OptionsBuilder/BindConfiguration.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/OptionsBuilder/BindConfiguration.generated.txt index 88b35037c22c3..37fad91482e8e 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/OptionsBuilder/BindConfiguration.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/OptionsBuilder/BindConfiguration.generated.txt @@ -72,10 +72,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration public static void BindCoreMain(IConfiguration configuration, object obj, Type type, Action? configureOptions) { - if (configuration is null) - { - throw new ArgumentNullException(nameof(configuration)); - } + ArgumentNullException.ThrowIfNull(configuration); if (obj is null) { diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/OptionsBuilder/BindConfiguration.net462.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/OptionsBuilder/BindConfiguration.net462.generated.txt new file mode 100644 index 0000000000000..a74dbfdd04b5b --- /dev/null +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/OptionsBuilder/BindConfiguration.net462.generated.txt @@ -0,0 +1,183 @@ +// +#nullable enable +#pragma warning disable CS0612, CS0618 // Suppress warnings about [Obsolete] member usage in generated code. + +/// Generated helper providing an AOT and linking compatible implementation for configuration binding. +[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")] +internal static class GeneratedOptionsBuilderBinder +{ + /// Registers the dependency injection container to bind against the obtained from the DI service provider. + public static global::Microsoft.Extensions.Options.OptionsBuilder BindConfiguration(this global::Microsoft.Extensions.Options.OptionsBuilder optionsBuilder, string configSectionPath, global::System.Action? configureOptions = null) where TOptions : class + { + if (optionsBuilder is null) + { + throw new global::System.ArgumentNullException(nameof(optionsBuilder)); + } + + if (configSectionPath is null) + { + throw new global::System.ArgumentNullException(nameof(configSectionPath)); + } + + optionsBuilder.Configure((obj, configuration) => + { + global::Microsoft.Extensions.Configuration.IConfiguration section = string.Equals(string.Empty, configSectionPath, global::System.StringComparison.OrdinalIgnoreCase) ? configuration : configuration.GetSection(configSectionPath); + global::Microsoft.Extensions.Configuration.Binder.SourceGeneration.CoreBindingHelper.BindCoreUntyped(section, obj, typeof(TOptions), configureOptions); + }); + + global::Microsoft.Extensions.DependencyInjection.ServiceCollectionServiceExtensions.AddSingleton, global::Microsoft.Extensions.Options.ConfigurationChangeTokenSource>(optionsBuilder.Services); + return optionsBuilder; + } +} + +namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration +{ + using Microsoft.Extensions.Configuration; + using Microsoft.Extensions.DependencyInjection; + using System; + using System.CodeDom.Compiler; + using System.Collections.Generic; + using System.Globalization; + + /// Provide core binding logic. + [GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")] + file static class CoreBindingHelper + { + private readonly static Lazy> s_configKeys_ProgramMyClass = new(() => new HashSet(StringComparer.OrdinalIgnoreCase) { "MyString", "MyInt", "MyList" }); + + public static void BindCoreUntyped(this IConfiguration configuration, object obj, Type type, Action? configureOptions) + { + if (configuration is null) + { + throw new ArgumentNullException(nameof(configuration)); + } + + BinderOptions? binderOptions = GetBinderOptions(configureOptions); + + if (!HasValueOrChildren(configuration)) + { + return; + } + + if (type == typeof(Program.MyClass)) + { + var temp = (Program.MyClass)obj; + BindCore(configuration, ref temp, binderOptions); + return; + } + + throw new global::System.NotSupportedException($"Unable to bind to type '{type}': generator did not detect the type as input."); + } + + public static void BindCore(IConfiguration configuration, ref List obj, BinderOptions? binderOptions) + { + if (obj is null) + { + throw new ArgumentNullException(nameof(obj)); + } + + foreach (IConfigurationSection section in configuration.GetChildren()) + { + if (section.Value is string value) + { + obj.Add(ParseInt(value, () => section.Path)); + } + } + } + + public static void BindCore(IConfiguration configuration, ref Program.MyClass obj, BinderOptions? binderOptions) + { + if (obj is null) + { + throw new ArgumentNullException(nameof(obj)); + } + + ValidateConfigurationKeys(typeof(Program.MyClass), s_configKeys_ProgramMyClass, configuration, binderOptions); + + obj.MyString = configuration["MyString"]!; + + if (configuration["MyInt"] is string value2) + { + obj.MyInt = ParseInt(value2, () => configuration.GetSection("MyInt").Path); + } + + if (AsConfigWithChildren(configuration.GetSection("MyList")) is IConfigurationSection section3) + { + List? temp5 = obj.MyList; + temp5 ??= new List(); + BindCore(section3, ref temp5, binderOptions); + obj.MyList = temp5; + } + } + + /// If required by the binder options, validates that there are no unknown keys in the input configuration object. + public static void ValidateConfigurationKeys(Type type, Lazy> keys, IConfiguration configuration, BinderOptions? binderOptions) + { + if (binderOptions?.ErrorOnUnknownConfiguration is true) + { + List? temp = null; + + foreach (IConfigurationSection section in configuration.GetChildren()) + { + if (!keys.Value.Contains(section.Key)) + { + (temp ??= new List()).Add($"'{section.Key}'"); + } + } + + if (temp is not null) + { + throw new InvalidOperationException($"'ErrorOnUnknownConfiguration' was set on the provided BinderOptions, but the following properties were not found on the instance of {type}: {string.Join(", ", temp)}"); + } + } + } + + public static bool HasValueOrChildren(IConfiguration configuration) + { + if ((configuration as IConfigurationSection)?.Value is not null) + { + return true; + } + return AsConfigWithChildren(configuration) is not null; + } + + public static IConfiguration? AsConfigWithChildren(IConfiguration configuration) + { + foreach (IConfigurationSection _ in configuration.GetChildren()) + { + return configuration; + } + return null; + } + + public static BinderOptions? GetBinderOptions(Action? configureOptions) + { + if (configureOptions is null) + { + return null; + } + + BinderOptions binderOptions = new(); + configureOptions(binderOptions); + + if (binderOptions.BindNonPublicProperties) + { + throw new global::System.NotSupportedException($"The configuration binding source generator does not support 'BinderOptions.BindNonPublicProperties'."); + } + + return binderOptions; + } + + public static int ParseInt(string value, Func getPath) + { + try + { + return int.Parse(value, NumberStyles.Integer, CultureInfo.InvariantCulture); + } + catch (Exception exception) + { + throw new InvalidOperationException($"Failed to convert configuration value at '{getPath()}' to type '{typeof(int)}'.", exception); + } + } + } +} diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/OptionsBuilder/Bind_T.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/OptionsBuilder/Bind_T.generated.txt index 633196e7a742d..b948dbfd180cb 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/OptionsBuilder/Bind_T.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/OptionsBuilder/Bind_T.generated.txt @@ -42,10 +42,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration /// Registers a configuration instance which will bind against. public static OptionsBuilder Bind(this OptionsBuilder optionsBuilder, IConfiguration configuration, Action? configureOptions) where TOptions : class { - if (optionsBuilder is null) - { - throw new ArgumentNullException(nameof(optionsBuilder)); - } + ArgumentNullException.ThrowIfNull(optionsBuilder); Configure(optionsBuilder.Services, optionsBuilder.Name, configuration, configureOptions); return optionsBuilder; @@ -56,15 +53,8 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration /// Registers a configuration instance which TOptions will bind against. public static IServiceCollection Configure(this IServiceCollection services, string? name, IConfiguration configuration, Action? configureOptions) where TOptions : class { - if (services is null) - { - throw new ArgumentNullException(nameof(services)); - } - - if (configuration is null) - { - throw new ArgumentNullException(nameof(configuration)); - } + ArgumentNullException.ThrowIfNull(services); + ArgumentNullException.ThrowIfNull(configuration); OptionsServiceCollectionExtensions.AddOptions(services); services.AddSingleton>(new ConfigurationChangeTokenSource(name, configuration)); @@ -77,10 +67,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration public static void BindCoreMain(IConfiguration configuration, object obj, Type type, Action? configureOptions) { - if (configuration is null) - { - throw new ArgumentNullException(nameof(configuration)); - } + ArgumentNullException.ThrowIfNull(configuration); if (obj is null) { diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/OptionsBuilder/Bind_T.net462.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/OptionsBuilder/Bind_T.net462.generated.txt new file mode 100644 index 0000000000000..ac53b58f24da2 --- /dev/null +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/OptionsBuilder/Bind_T.net462.generated.txt @@ -0,0 +1,201 @@ +// +#nullable enable +#pragma warning disable CS0612, CS0618 // Suppress warnings about [Obsolete] member usage in generated code. + +/// Generated helper providing an AOT and linking compatible implementation for configuration binding. +[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")] +internal static class GeneratedOptionsBuilderBinder +{ + /// Registers a configuration instance which will bind against. + public static global::Microsoft.Extensions.Options.OptionsBuilder Bind(this global::Microsoft.Extensions.Options.OptionsBuilder optionsBuilder, global::Microsoft.Extensions.Configuration.IConfiguration configuration) where TOptions : class + { + return global::GeneratedOptionsBuilderBinder.Bind(optionsBuilder, configuration, configureOptions: null); + } + + /// Registers a configuration instance which will bind against. + public static global::Microsoft.Extensions.Options.OptionsBuilder Bind(this global::Microsoft.Extensions.Options.OptionsBuilder optionsBuilder, global::Microsoft.Extensions.Configuration.IConfiguration configuration, global::System.Action? configureOptions) where TOptions : class + { + if (optionsBuilder is null) + { + throw new global::System.ArgumentNullException(nameof(optionsBuilder)); + } + + global::GeneratedServiceCollectionBinder.Configure(optionsBuilder.Services, optionsBuilder.Name, configuration, configureOptions); + return optionsBuilder; + } +} + +/// Generated helper providing an AOT and linking compatible implementation for configuration binding. +[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")] +internal static class GeneratedServiceCollectionBinder +{ + /// Registers a configuration instance which TOptions will bind against. + public static global::Microsoft.Extensions.DependencyInjection.IServiceCollection Configure(this global::Microsoft.Extensions.DependencyInjection.IServiceCollection services, string? name, global::Microsoft.Extensions.Configuration.IConfiguration configuration, global::System.Action? configureOptions) where TOptions : class + { + if (services is null) + { + throw new global::System.ArgumentNullException(nameof(services)); + } + + if (configuration is null) + { + throw new global::System.ArgumentNullException(nameof(configuration)); + } + + global::Microsoft.Extensions.DependencyInjection.OptionsServiceCollectionExtensions.AddOptions(services); + global::Microsoft.Extensions.DependencyInjection.ServiceCollectionServiceExtensions.AddSingleton>(services, new global::Microsoft.Extensions.Options.ConfigurationChangeTokenSource(name, configuration)); + return global::Microsoft.Extensions.DependencyInjection.ServiceCollectionServiceExtensions.AddSingleton>(services, new global::Microsoft.Extensions.Options.ConfigureNamedOptions(name, obj => global::Microsoft.Extensions.Configuration.Binder.SourceGeneration.CoreBindingHelper.BindCoreUntyped(configuration, obj, typeof(TOptions), configureOptions))); + } +} + +namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration +{ + using Microsoft.Extensions.Configuration; + using Microsoft.Extensions.DependencyInjection; + using System; + using System.CodeDom.Compiler; + using System.Collections.Generic; + using System.Globalization; + + /// Provide core binding logic. + [GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")] + file static class CoreBindingHelper + { + private readonly static Lazy> s_configKeys_ProgramMyClass = new(() => new HashSet(StringComparer.OrdinalIgnoreCase) { "MyString", "MyInt", "MyList" }); + + public static void BindCoreUntyped(this IConfiguration configuration, object obj, Type type, Action? configureOptions) + { + if (configuration is null) + { + throw new ArgumentNullException(nameof(configuration)); + } + + BinderOptions? binderOptions = GetBinderOptions(configureOptions); + + if (!HasValueOrChildren(configuration)) + { + return; + } + + if (type == typeof(Program.MyClass)) + { + var temp = (Program.MyClass)obj; + BindCore(configuration, ref temp, binderOptions); + return; + } + + throw new global::System.NotSupportedException($"Unable to bind to type '{type}': generator did not detect the type as input."); + } + + public static void BindCore(IConfiguration configuration, ref List obj, BinderOptions? binderOptions) + { + if (obj is null) + { + throw new ArgumentNullException(nameof(obj)); + } + + foreach (IConfigurationSection section in configuration.GetChildren()) + { + if (section.Value is string value) + { + obj.Add(ParseInt(value, () => section.Path)); + } + } + } + + public static void BindCore(IConfiguration configuration, ref Program.MyClass obj, BinderOptions? binderOptions) + { + if (obj is null) + { + throw new ArgumentNullException(nameof(obj)); + } + + ValidateConfigurationKeys(typeof(Program.MyClass), s_configKeys_ProgramMyClass, configuration, binderOptions); + + obj.MyString = configuration["MyString"]!; + + if (configuration["MyInt"] is string value2) + { + obj.MyInt = ParseInt(value2, () => configuration.GetSection("MyInt").Path); + } + + if (AsConfigWithChildren(configuration.GetSection("MyList")) is IConfigurationSection section3) + { + List? temp5 = obj.MyList; + temp5 ??= new List(); + BindCore(section3, ref temp5, binderOptions); + obj.MyList = temp5; + } + } + + /// If required by the binder options, validates that there are no unknown keys in the input configuration object. + public static void ValidateConfigurationKeys(Type type, Lazy> keys, IConfiguration configuration, BinderOptions? binderOptions) + { + if (binderOptions?.ErrorOnUnknownConfiguration is true) + { + List? temp = null; + + foreach (IConfigurationSection section in configuration.GetChildren()) + { + if (!keys.Value.Contains(section.Key)) + { + (temp ??= new List()).Add($"'{section.Key}'"); + } + } + + if (temp is not null) + { + throw new InvalidOperationException($"'ErrorOnUnknownConfiguration' was set on the provided BinderOptions, but the following properties were not found on the instance of {type}: {string.Join(", ", temp)}"); + } + } + } + + public static bool HasValueOrChildren(IConfiguration configuration) + { + if ((configuration as IConfigurationSection)?.Value is not null) + { + return true; + } + return AsConfigWithChildren(configuration) is not null; + } + + public static IConfiguration? AsConfigWithChildren(IConfiguration configuration) + { + foreach (IConfigurationSection _ in configuration.GetChildren()) + { + return configuration; + } + return null; + } + + public static BinderOptions? GetBinderOptions(Action? configureOptions) + { + if (configureOptions is null) + { + return null; + } + + BinderOptions binderOptions = new(); + configureOptions(binderOptions); + + if (binderOptions.BindNonPublicProperties) + { + throw new global::System.NotSupportedException($"The configuration binding source generator does not support 'BinderOptions.BindNonPublicProperties'."); + } + + return binderOptions; + } + + public static int ParseInt(string value, Func getPath) + { + try + { + return int.Parse(value, NumberStyles.Integer, CultureInfo.InvariantCulture); + } + catch (Exception exception) + { + throw new InvalidOperationException($"Failed to convert configuration value at '{getPath()}' to type '{typeof(int)}'.", exception); + } + } + } +} diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/OptionsBuilder/Bind_T_BinderOptions.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/OptionsBuilder/Bind_T_BinderOptions.generated.txt index fb5b4b4ad721d..e6ae7533798a3 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/OptionsBuilder/Bind_T_BinderOptions.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/OptionsBuilder/Bind_T_BinderOptions.generated.txt @@ -36,10 +36,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration [InterceptsLocationAttribute(@"src-0.cs", 15, 24)] public static OptionsBuilder Bind(this OptionsBuilder optionsBuilder, IConfiguration configuration, Action? configureOptions) where TOptions : class { - if (optionsBuilder is null) - { - throw new ArgumentNullException(nameof(optionsBuilder)); - } + ArgumentNullException.ThrowIfNull(optionsBuilder); Configure(optionsBuilder.Services, optionsBuilder.Name, configuration, configureOptions); return optionsBuilder; @@ -50,15 +47,8 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration /// Registers a configuration instance which TOptions will bind against. public static IServiceCollection Configure(this IServiceCollection services, string? name, IConfiguration configuration, Action? configureOptions) where TOptions : class { - if (services is null) - { - throw new ArgumentNullException(nameof(services)); - } - - if (configuration is null) - { - throw new ArgumentNullException(nameof(configuration)); - } + ArgumentNullException.ThrowIfNull(services); + ArgumentNullException.ThrowIfNull(configuration); OptionsServiceCollectionExtensions.AddOptions(services); services.AddSingleton>(new ConfigurationChangeTokenSource(name, configuration)); @@ -71,10 +61,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration public static void BindCoreMain(IConfiguration configuration, object obj, Type type, Action? configureOptions) { - if (configuration is null) - { - throw new ArgumentNullException(nameof(configuration)); - } + ArgumentNullException.ThrowIfNull(configuration); if (obj is null) { diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/OptionsBuilder/Bind_T_BinderOptions.net462.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/OptionsBuilder/Bind_T_BinderOptions.net462.generated.txt new file mode 100644 index 0000000000000..fd3ec70a8a328 --- /dev/null +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/OptionsBuilder/Bind_T_BinderOptions.net462.generated.txt @@ -0,0 +1,195 @@ +// +#nullable enable +#pragma warning disable CS0612, CS0618 // Suppress warnings about [Obsolete] member usage in generated code. + +/// Generated helper providing an AOT and linking compatible implementation for configuration binding. +[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")] +internal static class GeneratedOptionsBuilderBinder +{ + /// Registers a configuration instance which will bind against. + public static global::Microsoft.Extensions.Options.OptionsBuilder Bind(this global::Microsoft.Extensions.Options.OptionsBuilder optionsBuilder, global::Microsoft.Extensions.Configuration.IConfiguration configuration, global::System.Action? configureOptions) where TOptions : class + { + if (optionsBuilder is null) + { + throw new global::System.ArgumentNullException(nameof(optionsBuilder)); + } + + global::GeneratedServiceCollectionBinder.Configure(optionsBuilder.Services, optionsBuilder.Name, configuration, configureOptions); + return optionsBuilder; + } +} + +/// Generated helper providing an AOT and linking compatible implementation for configuration binding. +[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")] +internal static class GeneratedServiceCollectionBinder +{ + /// Registers a configuration instance which TOptions will bind against. + public static global::Microsoft.Extensions.DependencyInjection.IServiceCollection Configure(this global::Microsoft.Extensions.DependencyInjection.IServiceCollection services, string? name, global::Microsoft.Extensions.Configuration.IConfiguration configuration, global::System.Action? configureOptions) where TOptions : class + { + if (services is null) + { + throw new global::System.ArgumentNullException(nameof(services)); + } + + if (configuration is null) + { + throw new global::System.ArgumentNullException(nameof(configuration)); + } + + global::Microsoft.Extensions.DependencyInjection.OptionsServiceCollectionExtensions.AddOptions(services); + global::Microsoft.Extensions.DependencyInjection.ServiceCollectionServiceExtensions.AddSingleton>(services, new global::Microsoft.Extensions.Options.ConfigurationChangeTokenSource(name, configuration)); + return global::Microsoft.Extensions.DependencyInjection.ServiceCollectionServiceExtensions.AddSingleton>(services, new global::Microsoft.Extensions.Options.ConfigureNamedOptions(name, obj => global::Microsoft.Extensions.Configuration.Binder.SourceGeneration.CoreBindingHelper.BindCoreUntyped(configuration, obj, typeof(TOptions), configureOptions))); + } +} + +namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration +{ + using Microsoft.Extensions.Configuration; + using Microsoft.Extensions.DependencyInjection; + using System; + using System.CodeDom.Compiler; + using System.Collections.Generic; + using System.Globalization; + + /// Provide core binding logic. + [GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")] + file static class CoreBindingHelper + { + private readonly static Lazy> s_configKeys_ProgramMyClass = new(() => new HashSet(StringComparer.OrdinalIgnoreCase) { "MyString", "MyInt", "MyList" }); + + public static void BindCoreUntyped(this IConfiguration configuration, object obj, Type type, Action? configureOptions) + { + if (configuration is null) + { + throw new ArgumentNullException(nameof(configuration)); + } + + BinderOptions? binderOptions = GetBinderOptions(configureOptions); + + if (!HasValueOrChildren(configuration)) + { + return; + } + + if (type == typeof(Program.MyClass)) + { + var temp = (Program.MyClass)obj; + BindCore(configuration, ref temp, binderOptions); + return; + } + + throw new global::System.NotSupportedException($"Unable to bind to type '{type}': generator did not detect the type as input."); + } + + public static void BindCore(IConfiguration configuration, ref List obj, BinderOptions? binderOptions) + { + if (obj is null) + { + throw new ArgumentNullException(nameof(obj)); + } + + foreach (IConfigurationSection section in configuration.GetChildren()) + { + if (section.Value is string value) + { + obj.Add(ParseInt(value, () => section.Path)); + } + } + } + + public static void BindCore(IConfiguration configuration, ref Program.MyClass obj, BinderOptions? binderOptions) + { + if (obj is null) + { + throw new ArgumentNullException(nameof(obj)); + } + + ValidateConfigurationKeys(typeof(Program.MyClass), s_configKeys_ProgramMyClass, configuration, binderOptions); + + obj.MyString = configuration["MyString"]!; + + if (configuration["MyInt"] is string value2) + { + obj.MyInt = ParseInt(value2, () => configuration.GetSection("MyInt").Path); + } + + if (AsConfigWithChildren(configuration.GetSection("MyList")) is IConfigurationSection section3) + { + List? temp5 = obj.MyList; + temp5 ??= new List(); + BindCore(section3, ref temp5, binderOptions); + obj.MyList = temp5; + } + } + + /// If required by the binder options, validates that there are no unknown keys in the input configuration object. + public static void ValidateConfigurationKeys(Type type, Lazy> keys, IConfiguration configuration, BinderOptions? binderOptions) + { + if (binderOptions?.ErrorOnUnknownConfiguration is true) + { + List? temp = null; + + foreach (IConfigurationSection section in configuration.GetChildren()) + { + if (!keys.Value.Contains(section.Key)) + { + (temp ??= new List()).Add($"'{section.Key}'"); + } + } + + if (temp is not null) + { + throw new InvalidOperationException($"'ErrorOnUnknownConfiguration' was set on the provided BinderOptions, but the following properties were not found on the instance of {type}: {string.Join(", ", temp)}"); + } + } + } + + public static bool HasValueOrChildren(IConfiguration configuration) + { + if ((configuration as IConfigurationSection)?.Value is not null) + { + return true; + } + return AsConfigWithChildren(configuration) is not null; + } + + public static IConfiguration? AsConfigWithChildren(IConfiguration configuration) + { + foreach (IConfigurationSection _ in configuration.GetChildren()) + { + return configuration; + } + return null; + } + + public static BinderOptions? GetBinderOptions(Action? configureOptions) + { + if (configureOptions is null) + { + return null; + } + + BinderOptions binderOptions = new(); + configureOptions(binderOptions); + + if (binderOptions.BindNonPublicProperties) + { + throw new global::System.NotSupportedException($"The configuration binding source generator does not support 'BinderOptions.BindNonPublicProperties'."); + } + + return binderOptions; + } + + public static int ParseInt(string value, Func getPath) + { + try + { + return int.Parse(value, NumberStyles.Integer, CultureInfo.InvariantCulture); + } + catch (Exception exception) + { + throw new InvalidOperationException($"Failed to convert configuration value at '{getPath()}' to type '{typeof(int)}'.", exception); + } + } + } +} diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/Primitives.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/Primitives.generated.txt index db542637efba4..2a5a6e73b2b45 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/Primitives.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/Primitives.generated.txt @@ -34,15 +34,8 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration [InterceptsLocationAttribute(@"src-0.cs", 13, 16)] public static void Bind_ProgramMyClass(this IConfiguration configuration, object? obj) { - if (configuration is null) - { - throw new ArgumentNullException(nameof(configuration)); - } - - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } + ArgumentNullException.ThrowIfNull(configuration); + ArgumentNullException.ThrowIfNull(obj); var typedObj = (Program.MyClass)obj; BindCore(configuration, ref typedObj, binderOptions: null); @@ -218,11 +211,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration { try { - #if NETFRAMEWORK || NETSTANDARD2_0 - return (T)Enum.Parse(typeof(T), value, ignoreCase: true); - #else - return Enum.Parse(value, ignoreCase: true); - #endif + return Enum.Parse(value, ignoreCase: true); } catch (Exception exception) { diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/Primitives.net462.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/Primitives.net462.generated.txt new file mode 100644 index 0000000000000..159afe5f18273 --- /dev/null +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/Primitives.net462.generated.txt @@ -0,0 +1,517 @@ +// +#nullable enable +#pragma warning disable CS0612, CS0618 // Suppress warnings about [Obsolete] member usage in generated code. + +/// Generated helper providing an AOT and linking compatible implementation for configuration binding. +[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")] +internal static class GeneratedConfigurationBinder +{ + /// Attempts to bind the given object instance to configuration values by matching property names against configuration keys recursively. + public static void Bind(this global::Microsoft.Extensions.Configuration.IConfiguration configuration, global::Program.MyClass obj) => global::Microsoft.Extensions.Configuration.Binder.SourceGeneration.CoreBindingHelper.BindCore(configuration, ref obj, binderOptions: null); +} + +namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration +{ + using Microsoft.Extensions.Configuration; + using System; + using System.CodeDom.Compiler; + using System.Collections.Generic; + using System.Globalization; + + /// Provide core binding logic. + [GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")] + file static class CoreBindingHelper + { + private readonly static Lazy> s_configKeys_ProgramMyClass = new(() => new HashSet(StringComparer.OrdinalIgnoreCase) { "Prop0", "Prop1", "Prop2", "Prop3", "Prop4", "Prop5", "Prop6", "Prop8", "Prop9", "Prop10", "Prop13", "Prop14", "Prop15", "Prop16", "Prop17", "Prop19", "Prop20", "Prop21", "Prop23", "Prop24", "Prop25", "Prop26", "Prop27", "Prop7", "Prop11", "Prop12", "Prop18", "Prop22" }); + + public static void BindCore(IConfiguration configuration, ref Program.MyClass obj, BinderOptions? binderOptions) + { + if (obj is null) + { + throw new ArgumentNullException(nameof(obj)); + } + + ValidateConfigurationKeys(typeof(Program.MyClass), s_configKeys_ProgramMyClass, configuration, binderOptions); + + if (configuration["Prop0"] is string value0) + { + obj.Prop0 = ParseBool(value0, () => configuration.GetSection("Prop0").Path); + } + + if (configuration["Prop1"] is string value1) + { + obj.Prop1 = ParseByte(value1, () => configuration.GetSection("Prop1").Path); + } + + if (configuration["Prop2"] is string value2) + { + obj.Prop2 = ParseSbyte(value2, () => configuration.GetSection("Prop2").Path); + } + + if (configuration["Prop3"] is string value3) + { + obj.Prop3 = ParseChar(value3, () => configuration.GetSection("Prop3").Path); + } + + if (configuration["Prop4"] is string value4) + { + obj.Prop4 = ParseDouble(value4, () => configuration.GetSection("Prop4").Path); + } + + obj.Prop5 = configuration["Prop5"]!; + + if (configuration["Prop6"] is string value6) + { + obj.Prop6 = ParseInt(value6, () => configuration.GetSection("Prop6").Path); + } + + if (configuration["Prop8"] is string value7) + { + obj.Prop8 = ParseShort(value7, () => configuration.GetSection("Prop8").Path); + } + + if (configuration["Prop9"] is string value8) + { + obj.Prop9 = ParseLong(value8, () => configuration.GetSection("Prop9").Path); + } + + if (configuration["Prop10"] is string value9) + { + obj.Prop10 = ParseFloat(value9, () => configuration.GetSection("Prop10").Path); + } + + if (configuration["Prop13"] is string value10) + { + obj.Prop13 = ParseUshort(value10, () => configuration.GetSection("Prop13").Path); + } + + if (configuration["Prop14"] is string value11) + { + obj.Prop14 = ParseUint(value11, () => configuration.GetSection("Prop14").Path); + } + + if (configuration["Prop15"] is string value12) + { + obj.Prop15 = ParseUlong(value12, () => configuration.GetSection("Prop15").Path); + } + + obj.Prop16 = configuration["Prop16"]!; + + if (configuration["Prop17"] is string value14) + { + obj.Prop17 = ParseCultureInfo(value14, () => configuration.GetSection("Prop17").Path); + } + + if (configuration["Prop19"] is string value15) + { + obj.Prop19 = ParseDateTime(value15, () => configuration.GetSection("Prop19").Path); + } + + if (configuration["Prop20"] is string value16) + { + obj.Prop20 = ParseDateTimeOffset(value16, () => configuration.GetSection("Prop20").Path); + } + + if (configuration["Prop21"] is string value17) + { + obj.Prop21 = ParseDecimal(value17, () => configuration.GetSection("Prop21").Path); + } + + if (configuration["Prop23"] is string value18) + { + obj.Prop23 = ParseInt(value18, () => configuration.GetSection("Prop23").Path); + } + + if (configuration["Prop24"] is string value19) + { + obj.Prop24 = ParseDateTime(value19, () => configuration.GetSection("Prop24").Path); + } + + if (configuration["Prop25"] is string value20) + { + obj.Prop25 = ParseUri(value20, () => configuration.GetSection("Prop25").Path); + } + + if (configuration["Prop26"] is string value21) + { + obj.Prop26 = ParseVersion(value21, () => configuration.GetSection("Prop26").Path); + } + + if (configuration["Prop27"] is string value22) + { + obj.Prop27 = ParseEnum(value22, () => configuration.GetSection("Prop27").Path); + } + + if (configuration["Prop7"] is string value23) + { + obj.Prop7 = ParseInt128(value23, () => configuration.GetSection("Prop7").Path); + } + + if (configuration["Prop11"] is string value24) + { + obj.Prop11 = ParseHalf(value24, () => configuration.GetSection("Prop11").Path); + } + + if (configuration["Prop12"] is string value25) + { + obj.Prop12 = ParseUInt128(value25, () => configuration.GetSection("Prop12").Path); + } + + if (configuration["Prop18"] is string value26) + { + obj.Prop18 = ParseDateOnly(value26, () => configuration.GetSection("Prop18").Path); + } + + if (configuration["Prop22"] is string value27) + { + obj.Prop22 = ParseByteArray(value27, () => configuration.GetSection("Prop22").Path); + } + } + + /// If required by the binder options, validates that there are no unknown keys in the input configuration object. + public static void ValidateConfigurationKeys(Type type, Lazy> keys, IConfiguration configuration, BinderOptions? binderOptions) + { + if (binderOptions?.ErrorOnUnknownConfiguration is true) + { + List? temp = null; + + foreach (IConfigurationSection section in configuration.GetChildren()) + { + if (!keys.Value.Contains(section.Key)) + { + (temp ??= new List()).Add($"'{section.Key}'"); + } + } + + if (temp is not null) + { + throw new InvalidOperationException($"'ErrorOnUnknownConfiguration' was set on the provided BinderOptions, but the following properties were not found on the instance of {type}: {string.Join(", ", temp)}"); + } + } + } + + public static T ParseEnum(string value, Func getPath) where T : struct + { + try + { + return (T)Enum.Parse(typeof(T), value, ignoreCase: true); + } + catch (Exception exception) + { + throw new InvalidOperationException($"Failed to convert configuration value at '{getPath()}' to type '{typeof(T)}'.", exception); + } + } + + public static bool ParseBool(string value, Func getPath) + { + try + { + return bool.Parse(value); + } + catch (Exception exception) + { + throw new InvalidOperationException($"Failed to convert configuration value at '{getPath()}' to type '{typeof(bool)}'.", exception); + } + } + + public static byte ParseByte(string value, Func getPath) + { + try + { + return byte.Parse(value, NumberStyles.Integer, CultureInfo.InvariantCulture); + } + catch (Exception exception) + { + throw new InvalidOperationException($"Failed to convert configuration value at '{getPath()}' to type '{typeof(byte)}'.", exception); + } + } + + public static sbyte ParseSbyte(string value, Func getPath) + { + try + { + return sbyte.Parse(value, NumberStyles.Integer, CultureInfo.InvariantCulture); + } + catch (Exception exception) + { + throw new InvalidOperationException($"Failed to convert configuration value at '{getPath()}' to type '{typeof(sbyte)}'.", exception); + } + } + + public static char ParseChar(string value, Func getPath) + { + try + { + return char.Parse(value); + } + catch (Exception exception) + { + throw new InvalidOperationException($"Failed to convert configuration value at '{getPath()}' to type '{typeof(char)}'.", exception); + } + } + + public static double ParseDouble(string value, Func getPath) + { + try + { + return double.Parse(value, NumberStyles.Float, CultureInfo.InvariantCulture); + } + catch (Exception exception) + { + throw new InvalidOperationException($"Failed to convert configuration value at '{getPath()}' to type '{typeof(double)}'.", exception); + } + } + + public static int ParseInt(string value, Func getPath) + { + try + { + return int.Parse(value, NumberStyles.Integer, CultureInfo.InvariantCulture); + } + catch (Exception exception) + { + throw new InvalidOperationException($"Failed to convert configuration value at '{getPath()}' to type '{typeof(int)}'.", exception); + } + } + + public static short ParseShort(string value, Func getPath) + { + try + { + return short.Parse(value, NumberStyles.Integer, CultureInfo.InvariantCulture); + } + catch (Exception exception) + { + throw new InvalidOperationException($"Failed to convert configuration value at '{getPath()}' to type '{typeof(short)}'.", exception); + } + } + + public static long ParseLong(string value, Func getPath) + { + try + { + return long.Parse(value, NumberStyles.Integer, CultureInfo.InvariantCulture); + } + catch (Exception exception) + { + throw new InvalidOperationException($"Failed to convert configuration value at '{getPath()}' to type '{typeof(long)}'.", exception); + } + } + + public static float ParseFloat(string value, Func getPath) + { + try + { + return float.Parse(value, NumberStyles.Float, CultureInfo.InvariantCulture); + } + catch (Exception exception) + { + throw new InvalidOperationException($"Failed to convert configuration value at '{getPath()}' to type '{typeof(float)}'.", exception); + } + } + + public static ushort ParseUshort(string value, Func getPath) + { + try + { + return ushort.Parse(value, NumberStyles.Integer, CultureInfo.InvariantCulture); + } + catch (Exception exception) + { + throw new InvalidOperationException($"Failed to convert configuration value at '{getPath()}' to type '{typeof(ushort)}'.", exception); + } + } + + public static uint ParseUint(string value, Func getPath) + { + try + { + return uint.Parse(value, NumberStyles.Integer, CultureInfo.InvariantCulture); + } + catch (Exception exception) + { + throw new InvalidOperationException($"Failed to convert configuration value at '{getPath()}' to type '{typeof(uint)}'.", exception); + } + } + + public static ulong ParseUlong(string value, Func getPath) + { + try + { + return ulong.Parse(value, NumberStyles.Integer, CultureInfo.InvariantCulture); + } + catch (Exception exception) + { + throw new InvalidOperationException($"Failed to convert configuration value at '{getPath()}' to type '{typeof(ulong)}'.", exception); + } + } + + public static CultureInfo ParseCultureInfo(string value, Func getPath) + { + try + { + return CultureInfo.GetCultureInfo(value); + } + catch (Exception exception) + { + throw new InvalidOperationException($"Failed to convert configuration value at '{getPath()}' to type '{typeof(CultureInfo)}'.", exception); + } + } + + public static DateTime ParseDateTime(string value, Func getPath) + { + try + { + return DateTime.Parse(value, CultureInfo.InvariantCulture); + } + catch (Exception exception) + { + throw new InvalidOperationException($"Failed to convert configuration value at '{getPath()}' to type '{typeof(DateTime)}'.", exception); + } + } + + public static DateTimeOffset ParseDateTimeOffset(string value, Func getPath) + { + try + { + return DateTimeOffset.Parse(value, CultureInfo.InvariantCulture); + } + catch (Exception exception) + { + throw new InvalidOperationException($"Failed to convert configuration value at '{getPath()}' to type '{typeof(DateTimeOffset)}'.", exception); + } + } + + public static decimal ParseDecimal(string value, Func getPath) + { + try + { + return decimal.Parse(value, NumberStyles.Float, CultureInfo.InvariantCulture); + } + catch (Exception exception) + { + throw new InvalidOperationException($"Failed to convert configuration value at '{getPath()}' to type '{typeof(decimal)}'.", exception); + } + } + + public static TimeSpan ParseTimeSpan(string value, Func getPath) + { + try + { + return TimeSpan.Parse(value, CultureInfo.InvariantCulture); + } + catch (Exception exception) + { + throw new InvalidOperationException($"Failed to convert configuration value at '{getPath()}' to type '{typeof(TimeSpan)}'.", exception); + } + } + + public static Guid ParseGuid(string value, Func getPath) + { + try + { + return Guid.Parse(value); + } + catch (Exception exception) + { + throw new InvalidOperationException($"Failed to convert configuration value at '{getPath()}' to type '{typeof(Guid)}'.", exception); + } + } + + public static Uri ParseUri(string value, Func getPath) + { + try + { + return new Uri(value, UriKind.RelativeOrAbsolute); + } + catch (Exception exception) + { + throw new InvalidOperationException($"Failed to convert configuration value at '{getPath()}' to type '{typeof(Uri)}'.", exception); + } + } + + public static Version ParseVersion(string value, Func getPath) + { + try + { + return Version.Parse(value); + } + catch (Exception exception) + { + throw new InvalidOperationException($"Failed to convert configuration value at '{getPath()}' to type '{typeof(Version)}'.", exception); + } + } + + public static Int128 ParseInt128(string value, Func getPath) + { + try + { + return Int128.Parse(value, CultureInfo.InvariantCulture); + } + catch (Exception exception) + { + throw new InvalidOperationException($"Failed to convert configuration value at '{getPath()}' to type '{typeof(Int128)}'.", exception); + } + } + + public static Half ParseHalf(string value, Func getPath) + { + try + { + return Half.Parse(value, CultureInfo.InvariantCulture); + } + catch (Exception exception) + { + throw new InvalidOperationException($"Failed to convert configuration value at '{getPath()}' to type '{typeof(Half)}'.", exception); + } + } + + public static UInt128 ParseUInt128(string value, Func getPath) + { + try + { + return UInt128.Parse(value, CultureInfo.InvariantCulture); + } + catch (Exception exception) + { + throw new InvalidOperationException($"Failed to convert configuration value at '{getPath()}' to type '{typeof(UInt128)}'.", exception); + } + } + + public static DateOnly ParseDateOnly(string value, Func getPath) + { + try + { + return DateOnly.Parse(value, CultureInfo.InvariantCulture); + } + catch (Exception exception) + { + throw new InvalidOperationException($"Failed to convert configuration value at '{getPath()}' to type '{typeof(DateOnly)}'.", exception); + } + } + + public static TimeOnly ParseTimeOnly(string value, Func getPath) + { + try + { + return TimeOnly.Parse(value, CultureInfo.InvariantCulture); + } + catch (Exception exception) + { + throw new InvalidOperationException($"Failed to convert configuration value at '{getPath()}' to type '{typeof(TimeOnly)}'.", exception); + } + } + + public static byte[] ParseByteArray(string value, Func getPath) + { + try + { + return Convert.FromBase64String(value); + } + catch (Exception exception) + { + throw new InvalidOperationException($"Failed to convert configuration value at '{getPath()}' to type '{typeof(byte[])}'.", exception); + } + } + } +} diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ServiceCollection/Configure_T.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ServiceCollection/Configure_T.generated.txt index 7f626f0e27c52..d2aef5a52551d 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ServiceCollection/Configure_T.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ServiceCollection/Configure_T.generated.txt @@ -63,10 +63,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration public static void BindCoreMain(IConfiguration configuration, object obj, Type type, Action? configureOptions) { - if (configuration is null) - { - throw new ArgumentNullException(nameof(configuration)); - } + ArgumentNullException.ThrowIfNull(configuration); if (obj is null) { diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ServiceCollection/Configure_T.net462.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ServiceCollection/Configure_T.net462.generated.txt new file mode 100644 index 0000000000000..461f6050e2fdf --- /dev/null +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ServiceCollection/Configure_T.net462.generated.txt @@ -0,0 +1,246 @@ +// +#nullable enable +#pragma warning disable CS0612, CS0618 // Suppress warnings about [Obsolete] member usage in generated code. + +/// Generated helper providing an AOT and linking compatible implementation for configuration binding. +[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")] +internal static class GeneratedServiceCollectionBinder +{ + /// Registers a configuration instance which TOptions will bind against. + public static global::Microsoft.Extensions.DependencyInjection.IServiceCollection Configure(this global::Microsoft.Extensions.DependencyInjection.IServiceCollection services, global::Microsoft.Extensions.Configuration.IConfiguration configuration) where TOptions : class + { + return global::GeneratedServiceCollectionBinder.Configure(services, string.Empty, configuration, configureOptions: null); + } + + /// Registers a configuration instance which TOptions will bind against. + public static global::Microsoft.Extensions.DependencyInjection.IServiceCollection Configure(this global::Microsoft.Extensions.DependencyInjection.IServiceCollection services, string? name, global::Microsoft.Extensions.Configuration.IConfiguration configuration, global::System.Action? configureOptions) where TOptions : class + { + if (services is null) + { + throw new global::System.ArgumentNullException(nameof(services)); + } + + if (configuration is null) + { + throw new global::System.ArgumentNullException(nameof(configuration)); + } + + global::Microsoft.Extensions.DependencyInjection.OptionsServiceCollectionExtensions.AddOptions(services); + global::Microsoft.Extensions.DependencyInjection.ServiceCollectionServiceExtensions.AddSingleton>(services, new global::Microsoft.Extensions.Options.ConfigurationChangeTokenSource(name, configuration)); + return global::Microsoft.Extensions.DependencyInjection.ServiceCollectionServiceExtensions.AddSingleton>(services, new global::Microsoft.Extensions.Options.ConfigureNamedOptions(name, obj => global::Microsoft.Extensions.Configuration.Binder.SourceGeneration.CoreBindingHelper.BindCoreUntyped(configuration, obj, typeof(TOptions), configureOptions))); + } +} + +namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration +{ + using Microsoft.Extensions.Configuration; + using System; + using System.CodeDom.Compiler; + using System.Collections.Generic; + using System.Globalization; + + /// Provide core binding logic. + [GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")] + file static class CoreBindingHelper + { + private readonly static Lazy> s_configKeys_ProgramMyClass2 = new(() => new HashSet(StringComparer.OrdinalIgnoreCase) { "MyInt" }); + private readonly static Lazy> s_configKeys_ProgramMyClass = new(() => new HashSet(StringComparer.OrdinalIgnoreCase) { "MyString", "MyInt", "MyList", "MyList2", "MyDictionary" }); + + public static void BindCoreUntyped(this IConfiguration configuration, object obj, Type type, Action? configureOptions) + { + if (configuration is null) + { + throw new ArgumentNullException(nameof(configuration)); + } + + BinderOptions? binderOptions = GetBinderOptions(configureOptions); + + if (!HasValueOrChildren(configuration)) + { + return; + } + + if (type == typeof(Program.MyClass)) + { + var temp = (Program.MyClass)obj; + BindCore(configuration, ref temp, binderOptions); + return; + } + + throw new global::System.NotSupportedException($"Unable to bind to type '{type}': generator did not detect the type as input."); + } + + public static void BindCore(IConfiguration configuration, ref List obj, BinderOptions? binderOptions) + { + if (obj is null) + { + throw new ArgumentNullException(nameof(obj)); + } + + foreach (IConfigurationSection section in configuration.GetChildren()) + { + if (section.Value is string value) + { + obj.Add(ParseInt(value, () => section.Path)); + } + } + } + + public static void BindCore(IConfiguration configuration, ref Program.MyClass2 obj, BinderOptions? binderOptions) + { + if (obj is null) + { + throw new ArgumentNullException(nameof(obj)); + } + + ValidateConfigurationKeys(typeof(Program.MyClass2), s_configKeys_ProgramMyClass2, configuration, binderOptions); + + if (configuration["MyInt"] is string value1) + { + obj.MyInt = ParseInt(value1, () => configuration.GetSection("MyInt").Path); + } + } + + public static void BindCore(IConfiguration configuration, ref List obj, BinderOptions? binderOptions) + { + if (obj is null) + { + throw new ArgumentNullException(nameof(obj)); + } + + foreach (IConfigurationSection section in configuration.GetChildren()) + { + var value = new Program.MyClass2(); + BindCore(section, ref value, binderOptions); + obj.Add(value); + } + } + + public static void BindCore(IConfiguration configuration, ref Dictionary obj, BinderOptions? binderOptions) + { + if (obj is null) + { + throw new ArgumentNullException(nameof(obj)); + } + + foreach (IConfigurationSection section in configuration.GetChildren()) + { + if (section.Value is string value) + { + obj[section.Key] = value; + } + } + } + + public static void BindCore(IConfiguration configuration, ref Program.MyClass obj, BinderOptions? binderOptions) + { + if (obj is null) + { + throw new ArgumentNullException(nameof(obj)); + } + + ValidateConfigurationKeys(typeof(Program.MyClass), s_configKeys_ProgramMyClass, configuration, binderOptions); + + obj.MyString = configuration["MyString"]!; + + if (configuration["MyInt"] is string value4) + { + obj.MyInt = ParseInt(value4, () => configuration.GetSection("MyInt").Path); + } + + if (AsConfigWithChildren(configuration.GetSection("MyList")) is IConfigurationSection section5) + { + List? temp7 = obj.MyList; + temp7 ??= new List(); + BindCore(section5, ref temp7, binderOptions); + obj.MyList = temp7; + } + + if (AsConfigWithChildren(configuration.GetSection("MyList2")) is IConfigurationSection section8) + { + List? temp10 = obj.MyList2; + temp10 ??= new List(); + BindCore(section8, ref temp10, binderOptions); + obj.MyList2 = temp10; + } + + if (AsConfigWithChildren(configuration.GetSection("MyDictionary")) is IConfigurationSection section11) + { + Dictionary? temp13 = obj.MyDictionary; + temp13 ??= new Dictionary(); + BindCore(section11, ref temp13, binderOptions); + obj.MyDictionary = temp13; + } + } + + /// If required by the binder options, validates that there are no unknown keys in the input configuration object. + public static void ValidateConfigurationKeys(Type type, Lazy> keys, IConfiguration configuration, BinderOptions? binderOptions) + { + if (binderOptions?.ErrorOnUnknownConfiguration is true) + { + List? temp = null; + + foreach (IConfigurationSection section in configuration.GetChildren()) + { + if (!keys.Value.Contains(section.Key)) + { + (temp ??= new List()).Add($"'{section.Key}'"); + } + } + + if (temp is not null) + { + throw new InvalidOperationException($"'ErrorOnUnknownConfiguration' was set on the provided BinderOptions, but the following properties were not found on the instance of {type}: {string.Join(", ", temp)}"); + } + } + } + + public static bool HasValueOrChildren(IConfiguration configuration) + { + if ((configuration as IConfigurationSection)?.Value is not null) + { + return true; + } + return AsConfigWithChildren(configuration) is not null; + } + + public static IConfiguration? AsConfigWithChildren(IConfiguration configuration) + { + foreach (IConfigurationSection _ in configuration.GetChildren()) + { + return configuration; + } + return null; + } + + public static BinderOptions? GetBinderOptions(Action? configureOptions) + { + if (configureOptions is null) + { + return null; + } + + BinderOptions binderOptions = new(); + configureOptions(binderOptions); + + if (binderOptions.BindNonPublicProperties) + { + throw new global::System.NotSupportedException($"The configuration binding source generator does not support 'BinderOptions.BindNonPublicProperties'."); + } + + return binderOptions; + } + + public static int ParseInt(string value, Func getPath) + { + try + { + return int.Parse(value, NumberStyles.Integer, CultureInfo.InvariantCulture); + } + catch (Exception exception) + { + throw new InvalidOperationException($"Failed to convert configuration value at '{getPath()}' to type '{typeof(int)}'.", exception); + } + } + } +} diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ServiceCollection/Configure_T_BinderOptions.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ServiceCollection/Configure_T_BinderOptions.generated.txt index 5848c2412f9b7..ee47c7a9f5e67 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ServiceCollection/Configure_T_BinderOptions.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ServiceCollection/Configure_T_BinderOptions.generated.txt @@ -63,10 +63,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration public static void BindCoreMain(IConfiguration configuration, object obj, Type type, Action? configureOptions) { - if (configuration is null) - { - throw new ArgumentNullException(nameof(configuration)); - } + ArgumentNullException.ThrowIfNull(configuration); if (obj is null) { diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ServiceCollection/Configure_T_BinderOptions.net462.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ServiceCollection/Configure_T_BinderOptions.net462.generated.txt new file mode 100644 index 0000000000000..a57f652720bc8 --- /dev/null +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ServiceCollection/Configure_T_BinderOptions.net462.generated.txt @@ -0,0 +1,246 @@ +// +#nullable enable +#pragma warning disable CS0612, CS0618 // Suppress warnings about [Obsolete] member usage in generated code. + +/// Generated helper providing an AOT and linking compatible implementation for configuration binding. +[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")] +internal static class GeneratedServiceCollectionBinder +{ + /// Registers a configuration instance which TOptions will bind against. + public static global::Microsoft.Extensions.DependencyInjection.IServiceCollection Configure(this global::Microsoft.Extensions.DependencyInjection.IServiceCollection services, global::Microsoft.Extensions.Configuration.IConfiguration configuration, global::System.Action? configureOptions) where TOptions : class + { + return global::GeneratedServiceCollectionBinder.Configure(services, string.Empty, configuration, configureOptions); + } + + /// Registers a configuration instance which TOptions will bind against. + public static global::Microsoft.Extensions.DependencyInjection.IServiceCollection Configure(this global::Microsoft.Extensions.DependencyInjection.IServiceCollection services, string? name, global::Microsoft.Extensions.Configuration.IConfiguration configuration, global::System.Action? configureOptions) where TOptions : class + { + if (services is null) + { + throw new global::System.ArgumentNullException(nameof(services)); + } + + if (configuration is null) + { + throw new global::System.ArgumentNullException(nameof(configuration)); + } + + global::Microsoft.Extensions.DependencyInjection.OptionsServiceCollectionExtensions.AddOptions(services); + global::Microsoft.Extensions.DependencyInjection.ServiceCollectionServiceExtensions.AddSingleton>(services, new global::Microsoft.Extensions.Options.ConfigurationChangeTokenSource(name, configuration)); + return global::Microsoft.Extensions.DependencyInjection.ServiceCollectionServiceExtensions.AddSingleton>(services, new global::Microsoft.Extensions.Options.ConfigureNamedOptions(name, obj => global::Microsoft.Extensions.Configuration.Binder.SourceGeneration.CoreBindingHelper.BindCoreUntyped(configuration, obj, typeof(TOptions), configureOptions))); + } +} + +namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration +{ + using Microsoft.Extensions.Configuration; + using System; + using System.CodeDom.Compiler; + using System.Collections.Generic; + using System.Globalization; + + /// Provide core binding logic. + [GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")] + file static class CoreBindingHelper + { + private readonly static Lazy> s_configKeys_ProgramMyClass2 = new(() => new HashSet(StringComparer.OrdinalIgnoreCase) { "MyInt" }); + private readonly static Lazy> s_configKeys_ProgramMyClass = new(() => new HashSet(StringComparer.OrdinalIgnoreCase) { "MyString", "MyInt", "MyList", "MyList2", "MyDictionary" }); + + public static void BindCoreUntyped(this IConfiguration configuration, object obj, Type type, Action? configureOptions) + { + if (configuration is null) + { + throw new ArgumentNullException(nameof(configuration)); + } + + BinderOptions? binderOptions = GetBinderOptions(configureOptions); + + if (!HasValueOrChildren(configuration)) + { + return; + } + + if (type == typeof(Program.MyClass)) + { + var temp = (Program.MyClass)obj; + BindCore(configuration, ref temp, binderOptions); + return; + } + + throw new global::System.NotSupportedException($"Unable to bind to type '{type}': generator did not detect the type as input."); + } + + public static void BindCore(IConfiguration configuration, ref List obj, BinderOptions? binderOptions) + { + if (obj is null) + { + throw new ArgumentNullException(nameof(obj)); + } + + foreach (IConfigurationSection section in configuration.GetChildren()) + { + if (section.Value is string value) + { + obj.Add(ParseInt(value, () => section.Path)); + } + } + } + + public static void BindCore(IConfiguration configuration, ref Program.MyClass2 obj, BinderOptions? binderOptions) + { + if (obj is null) + { + throw new ArgumentNullException(nameof(obj)); + } + + ValidateConfigurationKeys(typeof(Program.MyClass2), s_configKeys_ProgramMyClass2, configuration, binderOptions); + + if (configuration["MyInt"] is string value1) + { + obj.MyInt = ParseInt(value1, () => configuration.GetSection("MyInt").Path); + } + } + + public static void BindCore(IConfiguration configuration, ref List obj, BinderOptions? binderOptions) + { + if (obj is null) + { + throw new ArgumentNullException(nameof(obj)); + } + + foreach (IConfigurationSection section in configuration.GetChildren()) + { + var value = new Program.MyClass2(); + BindCore(section, ref value, binderOptions); + obj.Add(value); + } + } + + public static void BindCore(IConfiguration configuration, ref Dictionary obj, BinderOptions? binderOptions) + { + if (obj is null) + { + throw new ArgumentNullException(nameof(obj)); + } + + foreach (IConfigurationSection section in configuration.GetChildren()) + { + if (section.Value is string value) + { + obj[section.Key] = value; + } + } + } + + public static void BindCore(IConfiguration configuration, ref Program.MyClass obj, BinderOptions? binderOptions) + { + if (obj is null) + { + throw new ArgumentNullException(nameof(obj)); + } + + ValidateConfigurationKeys(typeof(Program.MyClass), s_configKeys_ProgramMyClass, configuration, binderOptions); + + obj.MyString = configuration["MyString"]!; + + if (configuration["MyInt"] is string value4) + { + obj.MyInt = ParseInt(value4, () => configuration.GetSection("MyInt").Path); + } + + if (AsConfigWithChildren(configuration.GetSection("MyList")) is IConfigurationSection section5) + { + List? temp7 = obj.MyList; + temp7 ??= new List(); + BindCore(section5, ref temp7, binderOptions); + obj.MyList = temp7; + } + + if (AsConfigWithChildren(configuration.GetSection("MyList2")) is IConfigurationSection section8) + { + List? temp10 = obj.MyList2; + temp10 ??= new List(); + BindCore(section8, ref temp10, binderOptions); + obj.MyList2 = temp10; + } + + if (AsConfigWithChildren(configuration.GetSection("MyDictionary")) is IConfigurationSection section11) + { + Dictionary? temp13 = obj.MyDictionary; + temp13 ??= new Dictionary(); + BindCore(section11, ref temp13, binderOptions); + obj.MyDictionary = temp13; + } + } + + /// If required by the binder options, validates that there are no unknown keys in the input configuration object. + public static void ValidateConfigurationKeys(Type type, Lazy> keys, IConfiguration configuration, BinderOptions? binderOptions) + { + if (binderOptions?.ErrorOnUnknownConfiguration is true) + { + List? temp = null; + + foreach (IConfigurationSection section in configuration.GetChildren()) + { + if (!keys.Value.Contains(section.Key)) + { + (temp ??= new List()).Add($"'{section.Key}'"); + } + } + + if (temp is not null) + { + throw new InvalidOperationException($"'ErrorOnUnknownConfiguration' was set on the provided BinderOptions, but the following properties were not found on the instance of {type}: {string.Join(", ", temp)}"); + } + } + } + + public static bool HasValueOrChildren(IConfiguration configuration) + { + if ((configuration as IConfigurationSection)?.Value is not null) + { + return true; + } + return AsConfigWithChildren(configuration) is not null; + } + + public static IConfiguration? AsConfigWithChildren(IConfiguration configuration) + { + foreach (IConfigurationSection _ in configuration.GetChildren()) + { + return configuration; + } + return null; + } + + public static BinderOptions? GetBinderOptions(Action? configureOptions) + { + if (configureOptions is null) + { + return null; + } + + BinderOptions binderOptions = new(); + configureOptions(binderOptions); + + if (binderOptions.BindNonPublicProperties) + { + throw new global::System.NotSupportedException($"The configuration binding source generator does not support 'BinderOptions.BindNonPublicProperties'."); + } + + return binderOptions; + } + + public static int ParseInt(string value, Func getPath) + { + try + { + return int.Parse(value, NumberStyles.Integer, CultureInfo.InvariantCulture); + } + catch (Exception exception) + { + throw new InvalidOperationException($"Failed to convert configuration value at '{getPath()}' to type '{typeof(int)}'.", exception); + } + } + } +} diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ServiceCollection/Configure_T_name.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ServiceCollection/Configure_T_name.generated.txt index 91226d730166f..7eb3350dd0825 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ServiceCollection/Configure_T_name.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ServiceCollection/Configure_T_name.generated.txt @@ -63,10 +63,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration public static void BindCoreMain(IConfiguration configuration, object obj, Type type, Action? configureOptions) { - if (configuration is null) - { - throw new ArgumentNullException(nameof(configuration)); - } + ArgumentNullException.ThrowIfNull(configuration); if (obj is null) { diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ServiceCollection/Configure_T_name.net462.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ServiceCollection/Configure_T_name.net462.generated.txt new file mode 100644 index 0000000000000..66975c3164d74 --- /dev/null +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ServiceCollection/Configure_T_name.net462.generated.txt @@ -0,0 +1,246 @@ +// +#nullable enable +#pragma warning disable CS0612, CS0618 // Suppress warnings about [Obsolete] member usage in generated code. + +/// Generated helper providing an AOT and linking compatible implementation for configuration binding. +[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")] +internal static class GeneratedServiceCollectionBinder +{ + /// Registers a configuration instance which TOptions will bind against. + public static global::Microsoft.Extensions.DependencyInjection.IServiceCollection Configure(this global::Microsoft.Extensions.DependencyInjection.IServiceCollection services, string? name, global::Microsoft.Extensions.Configuration.IConfiguration configuration) where TOptions : class + { + return global::GeneratedServiceCollectionBinder.Configure(services, name, configuration, configureOptions: null); + } + + /// Registers a configuration instance which TOptions will bind against. + public static global::Microsoft.Extensions.DependencyInjection.IServiceCollection Configure(this global::Microsoft.Extensions.DependencyInjection.IServiceCollection services, string? name, global::Microsoft.Extensions.Configuration.IConfiguration configuration, global::System.Action? configureOptions) where TOptions : class + { + if (services is null) + { + throw new global::System.ArgumentNullException(nameof(services)); + } + + if (configuration is null) + { + throw new global::System.ArgumentNullException(nameof(configuration)); + } + + global::Microsoft.Extensions.DependencyInjection.OptionsServiceCollectionExtensions.AddOptions(services); + global::Microsoft.Extensions.DependencyInjection.ServiceCollectionServiceExtensions.AddSingleton>(services, new global::Microsoft.Extensions.Options.ConfigurationChangeTokenSource(name, configuration)); + return global::Microsoft.Extensions.DependencyInjection.ServiceCollectionServiceExtensions.AddSingleton>(services, new global::Microsoft.Extensions.Options.ConfigureNamedOptions(name, obj => global::Microsoft.Extensions.Configuration.Binder.SourceGeneration.CoreBindingHelper.BindCoreUntyped(configuration, obj, typeof(TOptions), configureOptions))); + } +} + +namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration +{ + using Microsoft.Extensions.Configuration; + using System; + using System.CodeDom.Compiler; + using System.Collections.Generic; + using System.Globalization; + + /// Provide core binding logic. + [GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")] + file static class CoreBindingHelper + { + private readonly static Lazy> s_configKeys_ProgramMyClass2 = new(() => new HashSet(StringComparer.OrdinalIgnoreCase) { "MyInt" }); + private readonly static Lazy> s_configKeys_ProgramMyClass = new(() => new HashSet(StringComparer.OrdinalIgnoreCase) { "MyString", "MyInt", "MyList", "MyList2", "MyDictionary" }); + + public static void BindCoreUntyped(this IConfiguration configuration, object obj, Type type, Action? configureOptions) + { + if (configuration is null) + { + throw new ArgumentNullException(nameof(configuration)); + } + + BinderOptions? binderOptions = GetBinderOptions(configureOptions); + + if (!HasValueOrChildren(configuration)) + { + return; + } + + if (type == typeof(Program.MyClass)) + { + var temp = (Program.MyClass)obj; + BindCore(configuration, ref temp, binderOptions); + return; + } + + throw new global::System.NotSupportedException($"Unable to bind to type '{type}': generator did not detect the type as input."); + } + + public static void BindCore(IConfiguration configuration, ref List obj, BinderOptions? binderOptions) + { + if (obj is null) + { + throw new ArgumentNullException(nameof(obj)); + } + + foreach (IConfigurationSection section in configuration.GetChildren()) + { + if (section.Value is string value) + { + obj.Add(ParseInt(value, () => section.Path)); + } + } + } + + public static void BindCore(IConfiguration configuration, ref Program.MyClass2 obj, BinderOptions? binderOptions) + { + if (obj is null) + { + throw new ArgumentNullException(nameof(obj)); + } + + ValidateConfigurationKeys(typeof(Program.MyClass2), s_configKeys_ProgramMyClass2, configuration, binderOptions); + + if (configuration["MyInt"] is string value1) + { + obj.MyInt = ParseInt(value1, () => configuration.GetSection("MyInt").Path); + } + } + + public static void BindCore(IConfiguration configuration, ref List obj, BinderOptions? binderOptions) + { + if (obj is null) + { + throw new ArgumentNullException(nameof(obj)); + } + + foreach (IConfigurationSection section in configuration.GetChildren()) + { + var value = new Program.MyClass2(); + BindCore(section, ref value, binderOptions); + obj.Add(value); + } + } + + public static void BindCore(IConfiguration configuration, ref Dictionary obj, BinderOptions? binderOptions) + { + if (obj is null) + { + throw new ArgumentNullException(nameof(obj)); + } + + foreach (IConfigurationSection section in configuration.GetChildren()) + { + if (section.Value is string value) + { + obj[section.Key] = value; + } + } + } + + public static void BindCore(IConfiguration configuration, ref Program.MyClass obj, BinderOptions? binderOptions) + { + if (obj is null) + { + throw new ArgumentNullException(nameof(obj)); + } + + ValidateConfigurationKeys(typeof(Program.MyClass), s_configKeys_ProgramMyClass, configuration, binderOptions); + + obj.MyString = configuration["MyString"]!; + + if (configuration["MyInt"] is string value4) + { + obj.MyInt = ParseInt(value4, () => configuration.GetSection("MyInt").Path); + } + + if (AsConfigWithChildren(configuration.GetSection("MyList")) is IConfigurationSection section5) + { + List? temp7 = obj.MyList; + temp7 ??= new List(); + BindCore(section5, ref temp7, binderOptions); + obj.MyList = temp7; + } + + if (AsConfigWithChildren(configuration.GetSection("MyList2")) is IConfigurationSection section8) + { + List? temp10 = obj.MyList2; + temp10 ??= new List(); + BindCore(section8, ref temp10, binderOptions); + obj.MyList2 = temp10; + } + + if (AsConfigWithChildren(configuration.GetSection("MyDictionary")) is IConfigurationSection section11) + { + Dictionary? temp13 = obj.MyDictionary; + temp13 ??= new Dictionary(); + BindCore(section11, ref temp13, binderOptions); + obj.MyDictionary = temp13; + } + } + + /// If required by the binder options, validates that there are no unknown keys in the input configuration object. + public static void ValidateConfigurationKeys(Type type, Lazy> keys, IConfiguration configuration, BinderOptions? binderOptions) + { + if (binderOptions?.ErrorOnUnknownConfiguration is true) + { + List? temp = null; + + foreach (IConfigurationSection section in configuration.GetChildren()) + { + if (!keys.Value.Contains(section.Key)) + { + (temp ??= new List()).Add($"'{section.Key}'"); + } + } + + if (temp is not null) + { + throw new InvalidOperationException($"'ErrorOnUnknownConfiguration' was set on the provided BinderOptions, but the following properties were not found on the instance of {type}: {string.Join(", ", temp)}"); + } + } + } + + public static bool HasValueOrChildren(IConfiguration configuration) + { + if ((configuration as IConfigurationSection)?.Value is not null) + { + return true; + } + return AsConfigWithChildren(configuration) is not null; + } + + public static IConfiguration? AsConfigWithChildren(IConfiguration configuration) + { + foreach (IConfigurationSection _ in configuration.GetChildren()) + { + return configuration; + } + return null; + } + + public static BinderOptions? GetBinderOptions(Action? configureOptions) + { + if (configureOptions is null) + { + return null; + } + + BinderOptions binderOptions = new(); + configureOptions(binderOptions); + + if (binderOptions.BindNonPublicProperties) + { + throw new global::System.NotSupportedException($"The configuration binding source generator does not support 'BinderOptions.BindNonPublicProperties'."); + } + + return binderOptions; + } + + public static int ParseInt(string value, Func getPath) + { + try + { + return int.Parse(value, NumberStyles.Integer, CultureInfo.InvariantCulture); + } + catch (Exception exception) + { + throw new InvalidOperationException($"Failed to convert configuration value at '{getPath()}' to type '{typeof(int)}'.", exception); + } + } + } +} diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ServiceCollection/Configure_T_name_BinderOptions.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ServiceCollection/Configure_T_name_BinderOptions.generated.txt index 8c9ccaa71a779..62dd9ff419a56 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ServiceCollection/Configure_T_name_BinderOptions.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ServiceCollection/Configure_T_name_BinderOptions.generated.txt @@ -57,10 +57,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration public static void BindCoreMain(IConfiguration configuration, object obj, Type type, Action? configureOptions) { - if (configuration is null) - { - throw new ArgumentNullException(nameof(configuration)); - } + ArgumentNullException.ThrowIfNull(configuration); if (obj is null) { diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ServiceCollection/Configure_T_name_BinderOptions.net462.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ServiceCollection/Configure_T_name_BinderOptions.net462.generated.txt new file mode 100644 index 0000000000000..0263ef1217940 --- /dev/null +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ServiceCollection/Configure_T_name_BinderOptions.net462.generated.txt @@ -0,0 +1,240 @@ +// +#nullable enable +#pragma warning disable CS0612, CS0618 // Suppress warnings about [Obsolete] member usage in generated code. + +/// Generated helper providing an AOT and linking compatible implementation for configuration binding. +[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")] +internal static class GeneratedServiceCollectionBinder +{ + /// Registers a configuration instance which TOptions will bind against. + public static global::Microsoft.Extensions.DependencyInjection.IServiceCollection Configure(this global::Microsoft.Extensions.DependencyInjection.IServiceCollection services, string? name, global::Microsoft.Extensions.Configuration.IConfiguration configuration, global::System.Action? configureOptions) where TOptions : class + { + if (services is null) + { + throw new global::System.ArgumentNullException(nameof(services)); + } + + if (configuration is null) + { + throw new global::System.ArgumentNullException(nameof(configuration)); + } + + global::Microsoft.Extensions.DependencyInjection.OptionsServiceCollectionExtensions.AddOptions(services); + global::Microsoft.Extensions.DependencyInjection.ServiceCollectionServiceExtensions.AddSingleton>(services, new global::Microsoft.Extensions.Options.ConfigurationChangeTokenSource(name, configuration)); + return global::Microsoft.Extensions.DependencyInjection.ServiceCollectionServiceExtensions.AddSingleton>(services, new global::Microsoft.Extensions.Options.ConfigureNamedOptions(name, obj => global::Microsoft.Extensions.Configuration.Binder.SourceGeneration.CoreBindingHelper.BindCoreUntyped(configuration, obj, typeof(TOptions), configureOptions))); + } +} + +namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration +{ + using Microsoft.Extensions.Configuration; + using System; + using System.CodeDom.Compiler; + using System.Collections.Generic; + using System.Globalization; + + /// Provide core binding logic. + [GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")] + file static class CoreBindingHelper + { + private readonly static Lazy> s_configKeys_ProgramMyClass2 = new(() => new HashSet(StringComparer.OrdinalIgnoreCase) { "MyInt" }); + private readonly static Lazy> s_configKeys_ProgramMyClass = new(() => new HashSet(StringComparer.OrdinalIgnoreCase) { "MyString", "MyInt", "MyList", "MyList2", "MyDictionary" }); + + public static void BindCoreUntyped(this IConfiguration configuration, object obj, Type type, Action? configureOptions) + { + if (configuration is null) + { + throw new ArgumentNullException(nameof(configuration)); + } + + BinderOptions? binderOptions = GetBinderOptions(configureOptions); + + if (!HasValueOrChildren(configuration)) + { + return; + } + + if (type == typeof(Program.MyClass)) + { + var temp = (Program.MyClass)obj; + BindCore(configuration, ref temp, binderOptions); + return; + } + + throw new global::System.NotSupportedException($"Unable to bind to type '{type}': generator did not detect the type as input."); + } + + public static void BindCore(IConfiguration configuration, ref List obj, BinderOptions? binderOptions) + { + if (obj is null) + { + throw new ArgumentNullException(nameof(obj)); + } + + foreach (IConfigurationSection section in configuration.GetChildren()) + { + if (section.Value is string value) + { + obj.Add(ParseInt(value, () => section.Path)); + } + } + } + + public static void BindCore(IConfiguration configuration, ref Program.MyClass2 obj, BinderOptions? binderOptions) + { + if (obj is null) + { + throw new ArgumentNullException(nameof(obj)); + } + + ValidateConfigurationKeys(typeof(Program.MyClass2), s_configKeys_ProgramMyClass2, configuration, binderOptions); + + if (configuration["MyInt"] is string value1) + { + obj.MyInt = ParseInt(value1, () => configuration.GetSection("MyInt").Path); + } + } + + public static void BindCore(IConfiguration configuration, ref List obj, BinderOptions? binderOptions) + { + if (obj is null) + { + throw new ArgumentNullException(nameof(obj)); + } + + foreach (IConfigurationSection section in configuration.GetChildren()) + { + var value = new Program.MyClass2(); + BindCore(section, ref value, binderOptions); + obj.Add(value); + } + } + + public static void BindCore(IConfiguration configuration, ref Dictionary obj, BinderOptions? binderOptions) + { + if (obj is null) + { + throw new ArgumentNullException(nameof(obj)); + } + + foreach (IConfigurationSection section in configuration.GetChildren()) + { + if (section.Value is string value) + { + obj[section.Key] = value; + } + } + } + + public static void BindCore(IConfiguration configuration, ref Program.MyClass obj, BinderOptions? binderOptions) + { + if (obj is null) + { + throw new ArgumentNullException(nameof(obj)); + } + + ValidateConfigurationKeys(typeof(Program.MyClass), s_configKeys_ProgramMyClass, configuration, binderOptions); + + obj.MyString = configuration["MyString"]!; + + if (configuration["MyInt"] is string value4) + { + obj.MyInt = ParseInt(value4, () => configuration.GetSection("MyInt").Path); + } + + if (AsConfigWithChildren(configuration.GetSection("MyList")) is IConfigurationSection section5) + { + List? temp7 = obj.MyList; + temp7 ??= new List(); + BindCore(section5, ref temp7, binderOptions); + obj.MyList = temp7; + } + + if (AsConfigWithChildren(configuration.GetSection("MyList2")) is IConfigurationSection section8) + { + List? temp10 = obj.MyList2; + temp10 ??= new List(); + BindCore(section8, ref temp10, binderOptions); + obj.MyList2 = temp10; + } + + if (AsConfigWithChildren(configuration.GetSection("MyDictionary")) is IConfigurationSection section11) + { + Dictionary? temp13 = obj.MyDictionary; + temp13 ??= new Dictionary(); + BindCore(section11, ref temp13, binderOptions); + obj.MyDictionary = temp13; + } + } + + /// If required by the binder options, validates that there are no unknown keys in the input configuration object. + public static void ValidateConfigurationKeys(Type type, Lazy> keys, IConfiguration configuration, BinderOptions? binderOptions) + { + if (binderOptions?.ErrorOnUnknownConfiguration is true) + { + List? temp = null; + + foreach (IConfigurationSection section in configuration.GetChildren()) + { + if (!keys.Value.Contains(section.Key)) + { + (temp ??= new List()).Add($"'{section.Key}'"); + } + } + + if (temp is not null) + { + throw new InvalidOperationException($"'ErrorOnUnknownConfiguration' was set on the provided BinderOptions, but the following properties were not found on the instance of {type}: {string.Join(", ", temp)}"); + } + } + } + + public static bool HasValueOrChildren(IConfiguration configuration) + { + if ((configuration as IConfigurationSection)?.Value is not null) + { + return true; + } + return AsConfigWithChildren(configuration) is not null; + } + + public static IConfiguration? AsConfigWithChildren(IConfiguration configuration) + { + foreach (IConfigurationSection _ in configuration.GetChildren()) + { + return configuration; + } + return null; + } + + public static BinderOptions? GetBinderOptions(Action? configureOptions) + { + if (configureOptions is null) + { + return null; + } + + BinderOptions binderOptions = new(); + configureOptions(binderOptions); + + if (binderOptions.BindNonPublicProperties) + { + throw new global::System.NotSupportedException($"The configuration binding source generator does not support 'BinderOptions.BindNonPublicProperties'."); + } + + return binderOptions; + } + + public static int ParseInt(string value, Func getPath) + { + try + { + return int.Parse(value, NumberStyles.Integer, CultureInfo.InvariantCulture); + } + catch (Exception exception) + { + throw new InvalidOperationException($"Failed to convert configuration value at '{getPath()}' to type '{typeof(int)}'.", exception); + } + } + } +} diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/GeneratorTests.Baselines.Options.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/GeneratorTests.Baselines.Options.cs index 0126744eacbfa..ba2698e367f2e 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/GeneratorTests.Baselines.Options.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/GeneratorTests.Baselines.Options.cs @@ -1,6 +1,7 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System; using System.Threading.Tasks; using Xunit; @@ -44,22 +45,38 @@ public class MyClass2 #endregion IServiceCollection extensions. #region OptionsBuilder extensions. - [Fact] + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNetCore))] public async Task Configure_T() => await VerifyAgainstBaselineUsingFile("Configure_T.generated.txt", GetConfigureSource("section"), extType: ExtensionClassType.ServiceCollection); - [Fact] + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNetFramework))] + public async Task Configure_T_NetFwk() => + await VerifyAgainstBaselineUsingFile("Configure_T.net462.generated.txt", GetConfigureSource("section"), extType: ExtensionClassType.ServiceCollection); + + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNetCore))] public async Task Configure_T_name() => await VerifyAgainstBaselineUsingFile("Configure_T_name.generated.txt", GetConfigureSource(@""""", section"), extType: ExtensionClassType.ServiceCollection); - [Fact] + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNetFramework))] + public async Task Configure_T_name_NetFwk() => + await VerifyAgainstBaselineUsingFile("Configure_T_name.net462.generated.txt", GetConfigureSource(@""""", section"), extType: ExtensionClassType.ServiceCollection); + + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNetCore))] public async Task Configure_T_BinderOptions() => await VerifyAgainstBaselineUsingFile("Configure_T_BinderOptions.generated.txt", GetConfigureSource("section, _ => { }"), extType: ExtensionClassType.ServiceCollection); - [Fact] + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNetFramework))] + public async Task Configure_T_BinderOptions_NetFwk() => + await VerifyAgainstBaselineUsingFile("Configure_T_BinderOptions.net462.generated.txt", GetConfigureSource("section, _ => { }"), extType: ExtensionClassType.ServiceCollection); + + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNetCore))] public async Task Configure_T_name_BinderOptions() => await VerifyAgainstBaselineUsingFile("Configure_T_name_BinderOptions.generated.txt", GetConfigureSource(@""""", section, _ => { }"), extType: ExtensionClassType.ServiceCollection); + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNetFramework))] + public async Task Configure_T_name_BinderOptions_NetFwk() => + await VerifyAgainstBaselineUsingFile("Configure_T_name_BinderOptions.net462.generated.txt", GetConfigureSource(@""""", section, _ => { }"), extType: ExtensionClassType.ServiceCollection); + private string GetBindSource(string? configureActions = null) => $$""" using System.Collections.Generic; using Microsoft.Extensions.Configuration; @@ -87,18 +104,30 @@ public class MyClass } """; - [Fact] + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNetCore))] public async Task Bind_T() { await VerifyAgainstBaselineUsingFile("Bind_T.generated.txt", GetBindSource(), extType: ExtensionClassType.OptionsBuilder); } - [Fact] + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNetFramework))] + public async Task Bind_T_NetFwk() + { + await VerifyAgainstBaselineUsingFile("Bind_T.net462.generated.txt", GetBindSource(), extType: ExtensionClassType.OptionsBuilder); + } + + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNetCore))] public async Task Bind_T_BinderOptions() { await VerifyAgainstBaselineUsingFile("Bind_T_BinderOptions.generated.txt", GetBindSource(", _ => { }"), extType: ExtensionClassType.OptionsBuilder); } + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNetFramework))] + public async Task Bind_T_BinderOptions_NetFwk() + { + await VerifyAgainstBaselineUsingFile("Bind_T_BinderOptions.net462.generated.txt", GetBindSource(", _ => { }"), extType: ExtensionClassType.OptionsBuilder); + } + [Fact] public async Task BindConfiguration() { diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/GeneratorTests.Baselines.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/GeneratorTests.Baselines.cs index 65e812d30b420..dafed6787c10d 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/GeneratorTests.Baselines.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/GeneratorTests.Baselines.cs @@ -41,15 +41,20 @@ public class MyClass public class MyClass2 { } }"; - [Theory] + [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsNetCore))] [InlineData(LanguageVersion.Preview)] public async Task Bind(LanguageVersion langVersion) => await VerifyAgainstBaselineUsingFile("Bind.generated.txt", BindCallSampleCode, langVersion, extType: ExtensionClassType.ConfigurationBinder); - [Fact] - public async Task Bind_Instance() + [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsNetFramework))] + [InlineData(LanguageVersion.Preview)] + [InlineData(LanguageVersion.CSharp11)] + public async Task Bind_NetFwk(LanguageVersion langVersion) => + await VerifyAgainstBaselineUsingFile("Bind.net462.generated.txt", BindCallSampleCode, langVersion, extType: ExtensionClassType.ConfigurationBinder); + + private string Bind_Instance_Sources() { - string source = """ + return """ using System.Collections.Generic; using Microsoft.Extensions.Configuration; @@ -76,14 +81,27 @@ public class MyClass public class MyClass2 { } } """; + } + + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNetCore))] + public async Task Bind_Instance() + { + string source = Bind_Instance_Sources(); await VerifyAgainstBaselineUsingFile("Bind_Instance.generated.txt", source, extType: ExtensionClassType.ConfigurationBinder); } - [Fact] - public async Task Bind_Instance_BinderOptions() + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNetFramework))] + public async Task Bind_Instance_Fwk() { - string source = """ + string source = Bind_Instance_Sources(); + + await VerifyAgainstBaselineUsingFile("Bind_Instance.net462.generated.txt", source, extType: ExtensionClassType.ConfigurationBinder); + } + + private string Bind_Instance_BinderOptions_Sources() + { + return """ using System.Collections.Generic; using Microsoft.Extensions.Configuration; @@ -110,14 +128,27 @@ public class MyClass public class MyClass2 { } } """; + } + + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNetCore))] + public async Task Bind_Instance_BinderOptions() + { + string source = Bind_Instance_BinderOptions_Sources(); await VerifyAgainstBaselineUsingFile("Bind_Instance_BinderOptions.generated.txt", source, extType: ExtensionClassType.ConfigurationBinder); } - [Fact] - public async Task Bind_Key_Instance() + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNetFramework))] + public async Task Bind_Instance_BinderOptions_NetFwk() { - string source = """ + string source = Bind_Instance_BinderOptions_Sources(); + + await VerifyAgainstBaselineUsingFile("Bind_Instance_BinderOptions.net462.generated.txt", source, extType: ExtensionClassType.ConfigurationBinder); + } + + private string Bind_Key_Sources() + { + return """ using System.Collections.Generic; using Microsoft.Extensions.Configuration; @@ -144,14 +175,27 @@ public class MyClass public class MyClass2 { } } """; + } + + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNetCore))] + public async Task Bind_Key_Instance() + { + string source = Bind_Key_Sources(); await VerifyAgainstBaselineUsingFile("Bind_Key_Instance.generated.txt", source, extType: ExtensionClassType.ConfigurationBinder); } - [Fact] - public async Task Get() + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNetFramework))] + public async Task Bind_Key_Instance_NetFwk() { - string source = @" + string source = Bind_Key_Sources(); + + await VerifyAgainstBaselineUsingFile("Bind_Key_Instance.net462.generated.txt", source, extType: ExtensionClassType.ConfigurationBinder); + } + + private string GetSources() + { + return @" using System.Collections.Generic; using Microsoft.Extensions.Configuration; @@ -192,14 +236,27 @@ public class MyClass4 public int MyInt { get; set; } } }"; + } + + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNetCore))] + public async Task Get() + { + string source = GetSources(); await VerifyAgainstBaselineUsingFile("Get.generated.txt", source, extType: ExtensionClassType.ConfigurationBinder); } - [Fact] - public async Task Get_T() + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNetFramework))] + public async Task Get_NetFwk() + { + string source = GetSources(); + + await VerifyAgainstBaselineUsingFile("Get.net462.generated.txt", source, extType: ExtensionClassType.ConfigurationBinder); + } + + private string Get_T_Sources() { - string source = """ + return """ using System.Collections.Generic; using Microsoft.Extensions.Configuration; @@ -238,14 +295,27 @@ public class MyClass4 } } """; + } + + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNetCore))] + public async Task Get_T() + { + string source = Get_T_Sources(); await VerifyAgainstBaselineUsingFile("Get_T.generated.txt", source, extType: ExtensionClassType.ConfigurationBinder); } - [Fact] - public async Task Get_T_BinderOptions() + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNetFramework))] + public async Task Get_T_NetFwk() + { + string source = Get_T_Sources(); + + await VerifyAgainstBaselineUsingFile("Get_T.net462.generated.txt", source, extType: ExtensionClassType.ConfigurationBinder); + } + + private string Get_T_BinderOptions_Sources() { - string source = """ + return """ using System.Collections.Generic; using Microsoft.Extensions.Configuration; @@ -284,14 +354,27 @@ public class MyClass4 } } """; + } + + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNetCore))] + public async Task Get_T_BinderOptions() + { + string source = Get_T_BinderOptions_Sources(); await VerifyAgainstBaselineUsingFile("Get_T_BinderOptions.generated.txt", source, extType: ExtensionClassType.ConfigurationBinder); } - [Fact] - public async Task Get_TypeOf() + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNetFramework))] + public async Task Get_T_BinderOptions_NetFwk() + { + string source = Get_T_BinderOptions_Sources(); + + await VerifyAgainstBaselineUsingFile("Get_T_BinderOptions.net462.generated.txt", source, extType: ExtensionClassType.ConfigurationBinder); + } + + private string Get_TypeOf_Sources() { - string source = """ + return """ using System.Collections.Generic; using Microsoft.Extensions.Configuration; @@ -330,14 +413,27 @@ public class MyClass4 } } """; + } + + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNetCore))] + public async Task Get_TypeOf() + { + string source = Get_TypeOf_Sources(); await VerifyAgainstBaselineUsingFile("Get_TypeOf.generated.txt", source, extType: ExtensionClassType.ConfigurationBinder); } - [Fact] - public async Task Get_TypeOf_BinderOptions() + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNetFramework))] + public async Task Get_TypeOf_NetFwk() + { + string source = Get_TypeOf_Sources(); + + await VerifyAgainstBaselineUsingFile("Get_TypeOf.net462.generated.txt", source, extType: ExtensionClassType.ConfigurationBinder); + } + + private string Get_TypeOf_BinderOptions_Sources() { - string source = """ + return """ using System.Collections.Generic; using Microsoft.Extensions.Configuration; @@ -376,14 +472,27 @@ public class MyClass4 } } """; + } + + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNetCore))] + public async Task Get_TypeOf_BinderOptions() + { + string source = Get_TypeOf_BinderOptions_Sources(); await VerifyAgainstBaselineUsingFile("Get_TypeOf_BinderOptions.generated.txt", source, extType: ExtensionClassType.ConfigurationBinder); } - [Fact] - public async Task GetValue() + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNetFramework))] + public async Task Get_TypeOf_BinderOptions_NetFwk() { - string source = @" + string source = Get_TypeOf_BinderOptions_Sources(); + + await VerifyAgainstBaselineUsingFile("Get_TypeOf_BinderOptions.net462.generated.txt", source, extType: ExtensionClassType.ConfigurationBinder); + } + + private string GetValue_Sources() + { + return @" using System.Collections.Generic; using System.Globalization; using Microsoft.Extensions.Configuration; @@ -411,14 +520,27 @@ public class MyClass public Dictionary MyDictionary { get; set; } } }"; + } + + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNetCore))] + public async Task GetValue() + { + string source = GetValue_Sources(); await VerifyAgainstBaselineUsingFile("GetValue.generated.txt", source, extType: ExtensionClassType.ConfigurationBinder); } - [Fact] - public async Task GetValue_T_Key() + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNetFramework))] + public async Task GetValue_NetFwk() + { + string source = GetValue_Sources(); + + await VerifyAgainstBaselineUsingFile("GetValue.net462.generated.txt", source, extType: ExtensionClassType.ConfigurationBinder); + } + + private string GetValue_T_Key_Sources() { - string source = """ + return """ using Microsoft.Extensions.Configuration; public class Program @@ -432,14 +554,27 @@ public static void Main() } } """; + } + + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNetCore))] + public async Task GetValue_T_Key() + { + string source = GetValue_T_Key_Sources(); await VerifyAgainstBaselineUsingFile("GetValue_T_Key.generated.txt", source, extType: ExtensionClassType.ConfigurationBinder); } - [Fact] - public async Task GetValue_T_Key_DefaultValue() + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNetFramework))] + public async Task GetValue_T_Key_NetFwk() + { + string source = GetValue_T_Key_Sources(); + + await VerifyAgainstBaselineUsingFile("GetValue_T_Key.net462.generated.txt", source, extType: ExtensionClassType.ConfigurationBinder); + } + + private string GetValue_T_Key_DefaultValue_Sources() { - string source = """ + return """ using System.Collections.Generic; using System.Globalization; using Microsoft.Extensions.Configuration; @@ -455,14 +590,27 @@ public static void Main() } } """; + } + + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNetCore))] + public async Task GetValue_T_Key_DefaultValue() + { + string source = GetValue_T_Key_DefaultValue_Sources(); await VerifyAgainstBaselineUsingFile("GetValue_T_Key_DefaultValue.generated.txt", source, extType: ExtensionClassType.ConfigurationBinder); } - [Fact] - public async Task GetValue_TypeOf_Key() + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNetFramework))] + public async Task GetValue_T_Key_DefaultValue_NetFwk() { - string source = """ + string source = GetValue_T_Key_DefaultValue_Sources(); + + await VerifyAgainstBaselineUsingFile("GetValue_T_Key_DefaultValue.net462.generated.txt", source, extType: ExtensionClassType.ConfigurationBinder); + } + + private string GetValue_TypeOf_Key_Sources() + { + return """ using Microsoft.Extensions.Configuration; public class Program @@ -476,14 +624,27 @@ public static void Main() } } """; + } + + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNetCore))] + public async Task GetValue_TypeOf_Key() + { + string source = GetValue_TypeOf_Key_Sources(); await VerifyAgainstBaselineUsingFile("GetValue_TypeOf_Key.generated.txt", source, extType: ExtensionClassType.ConfigurationBinder); } - [Fact] - public async Task GetValue_TypeOf_Key_DefaultValue() + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNetFramework))] + public async Task GetValue_TypeOf_Key_NetFwk() + { + string source = GetValue_TypeOf_Key_Sources(); + + await VerifyAgainstBaselineUsingFile("GetValue_TypeOf_Key.net462.generated.txt", source, extType: ExtensionClassType.ConfigurationBinder); + } + + private string GetValue_TypeOf_Key_DefaultValue_Sources() { - string source = """ + return """ using System.Globalization; using Microsoft.Extensions.Configuration; @@ -498,10 +659,24 @@ public static void Main() } } """; + } + + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNetCore))] + public async Task GetValue_TypeOf_Key_DefaultValue() + { + string source = GetValue_TypeOf_Key_DefaultValue_Sources(); await VerifyAgainstBaselineUsingFile("GetValue_TypeOf_Key_DefaultValue.generated.txt", source, extType: ExtensionClassType.ConfigurationBinder); } + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNetFramework))] + public async Task GetValue_TypeOf_Key_DefaultValue_NetFwk() + { + string source = GetValue_TypeOf_Key_DefaultValue_Sources(); + + await VerifyAgainstBaselineUsingFile("GetValue_TypeOf_Key_DefaultValue.net462.generated.txt", source, extType: ExtensionClassType.ConfigurationBinder); + } + [Fact] public async Task None() { @@ -541,10 +716,9 @@ public class MyClass2 Assert.Empty(d); } - [Fact] - public async Task Primitives() + private string GetPrimitivesSource() { - string source = """ + return """ using System; using System.Globalization; using Microsoft.Extensions.Configuration; @@ -596,14 +770,26 @@ public class MyClass } } """; + } + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNetCore))] + public async Task Primitives() + { + string source = GetPrimitivesSource(); await VerifyAgainstBaselineUsingFile("Primitives.generated.txt", source); } - [Fact] - public async Task Collections() + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNetFramework))] + public async Task PrimitivesNetFwk() + { + string source = GetPrimitivesSource(); + + await VerifyAgainstBaselineUsingFile($"Primitives.net462.generated.txt", source); + } + + private string GetCollectionsSource() { - string source = """ + return """ using System.Collections.Generic; using Microsoft.Extensions.Configuration; @@ -646,6 +832,12 @@ public interface ICustomSet : ISet } } """; + } + + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNetCore))] + public async Task Collections() + { + string source = GetCollectionsSource(); await VerifyAgainstBaselineUsingFile("Collections.generated.txt", source, assessDiagnostics: (d) => { @@ -653,5 +845,18 @@ await VerifyAgainstBaselineUsingFile("Collections.generated.txt", source, assess Assert.Equal(6, d.Where(diag => diag.Id == Diagnostics.PropertyNotSupported.Id).Count()); }); } + + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNetFramework))] + public async Task CollectionsFwk() + { + string source = GetCollectionsSource(); + + await VerifyAgainstBaselineUsingFile("Collections.net462.generated.txt", source, assessDiagnostics: (d) => + { + Console.WriteLine((d.Where(diag => diag.Id == Diagnostics.TypeNotSupported.Id).Count(), d.Where(diag => diag.Id == Diagnostics.PropertyNotSupported.Id).Count())); + Assert.Equal(3, d.Where(diag => diag.Id == Diagnostics.TypeNotSupported.Id).Count()); + Assert.Equal(6, d.Where(diag => diag.Id == Diagnostics.PropertyNotSupported.Id).Count()); + }); + } } } From e80c9aedce4e8d9bdead812cfeedb6c9a2428aec Mon Sep 17 00:00:00 2001 From: pedrobsaila Date: Sun, 27 Aug 2023 15:35:16 +0200 Subject: [PATCH 03/17] fix merge issues --- .../Collections.net462.generated.txt | 79 ++++-------- .../ConfigurationBinder/Bind.generated.txt | 12 +- .../Bind.net462.generated.txt | 100 ++++++++++----- .../Bind_Instance.generated.txt | 1 + .../Bind_Instance.net462.generated.txt | 60 +++++---- .../Bind_Instance_BinderOptions.generated.txt | 1 + ...nstance_BinderOptions.net462.generated.txt | 62 ++++++---- .../Bind_Key_Instance.generated.txt | 1 + .../Bind_Key_Instance.net462.generated.txt | 60 +++++---- .../Get.net462.generated.txt | 81 ++++++------ .../GetValue.net462.generated.txt | 57 +++++---- .../GetValue_T_Key.net462.generated.txt | 29 +++-- ...ue_T_Key_DefaultValue.net462.generated.txt | 29 +++-- .../GetValue_TypeOf_Key.net462.generated.txt | 29 +++-- ...peOf_Key_DefaultValue.net462.generated.txt | 29 +++-- .../Get_T.net462.generated.txt | 54 ++++---- .../Get_T_BinderOptions.net462.generated.txt | 54 ++++---- .../Get_TypeOf.net462.generated.txt | 39 +++--- ..._TypeOf_BinderOptions.net462.generated.txt | 39 +++--- .../BindConfiguration.generated.txt | 25 +--- .../BindConfiguration.net462.generated.txt | 96 ++++++++------ .../OptionsBuilder/Bind_T.generated.txt | 6 +- .../Bind_T.net462.generated.txt | 117 ++++++++++-------- .../Bind_T_BinderOptions.generated.txt | 6 +- .../Bind_T_BinderOptions.net462.generated.txt | 105 +++++++++------- .../Baselines/Primitives.generated.txt | 1 + .../Baselines/Primitives.net462.generated.txt | 45 +++++-- .../Configure_T.generated.txt | 15 +-- .../Configure_T.net462.generated.txt | 101 ++++++++------- .../Configure_T_BinderOptions.generated.txt | 15 +-- ...igure_T_BinderOptions.net462.generated.txt | 101 ++++++++------- .../Configure_T_name.generated.txt | 15 +-- .../Configure_T_name.net462.generated.txt | 101 ++++++++------- ...nfigure_T_name_BinderOptions.generated.txt | 15 +-- ..._T_name_BinderOptions.net462.generated.txt | 91 +++++++------- 35 files changed, 896 insertions(+), 775 deletions(-) diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/Collections.net462.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/Collections.net462.generated.txt index 2149dcaaa0714..528847cfeb3a3 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/Collections.net462.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/Collections.net462.generated.txt @@ -2,12 +2,19 @@ #nullable enable #pragma warning disable CS0612, CS0618 // Suppress warnings about [Obsolete] member usage in generated code. -/// Generated helper providing an AOT and linking compatible implementation for configuration binding. -[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")] -internal static class GeneratedConfigurationBinder +namespace System.Runtime.CompilerServices { - /// Attempts to bind the configuration instance to a new instance of type T. - public static T? Get(this global::Microsoft.Extensions.Configuration.IConfiguration configuration) => (T?)(global::Microsoft.Extensions.Configuration.Binder.SourceGeneration.CoreBindingHelper.GetCore(configuration, typeof(T), configureOptions: null) ?? default(T)); + using System; + using System.CodeDom.Compiler; + + [GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")] + [AttributeUsage(AttributeTargets.Method, AllowMultiple = true)] + file sealed class InterceptsLocationAttribute : Attribute + { + public InterceptsLocationAttribute(string filePath, int line, int column) + { + } + } } namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration @@ -18,11 +25,18 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration using System.Collections.Generic; using System.Globalization; using System.Linq; + using System.Runtime.CompilerServices; - /// Provide core binding logic. [GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")] - file static class CoreBindingHelper + file static class BindingExtensions { + #region IConfiguration extensions. + /// Attempts to bind the configuration instance to a new instance of type T. + [InterceptsLocationAttribute(@"src-0.cs", 12, 17)] + public static T? Get(this IConfiguration configuration) => (T?)(GetCore(configuration, typeof(T), configureOptions: null) ?? default(T)); + #endregion IConfiguration extensions. + + #region Core binding extensions. private readonly static Lazy> s_configKeys_ProgramMyClassWithCustomCollections = new(() => new HashSet(StringComparer.OrdinalIgnoreCase) { "CustomDictionary", "CustomList", "IReadOnlyList", "IReadOnlyDictionary" }); public static object? GetCore(this IConfiguration configuration, Type type, Action? configureOptions) @@ -46,16 +60,11 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration return obj; } - throw new global::System.NotSupportedException($"Unable to bind to type '{type}': generator did not detect the type as input."); + throw new NotSupportedException($"Unable to bind to type '{type}': generator did not detect the type as input."); } public static void BindCore(IConfiguration configuration, ref Program.CustomDictionary obj, BinderOptions? binderOptions) { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - foreach (IConfigurationSection section in configuration.GetChildren()) { if (section.Value is string value) @@ -67,11 +76,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration public static void BindCore(IConfiguration configuration, ref Program.CustomList obj, BinderOptions? binderOptions) { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - foreach (IConfigurationSection section in configuration.GetChildren()) { if (section.Value is string value) @@ -83,11 +87,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration public static void BindCore(IConfiguration configuration, ref List obj, BinderOptions? binderOptions) { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - foreach (IConfigurationSection section in configuration.GetChildren()) { if (section.Value is string value) @@ -99,11 +98,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration public static void BindCore(IConfiguration configuration, ref ICollection obj, BinderOptions? binderOptions) { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - foreach (IConfigurationSection section in configuration.GetChildren()) { if (section.Value is string value) @@ -115,11 +109,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration public static void BindCore(IConfiguration configuration, ref IReadOnlyList obj, BinderOptions? binderOptions) { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - if (obj is not ICollection temp) { return; @@ -136,11 +125,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration public static void BindCore(IConfiguration configuration, ref Dictionary obj, BinderOptions? binderOptions) { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - foreach (IConfigurationSection section in configuration.GetChildren()) { if (section.Value is string value) @@ -152,11 +136,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration public static void BindCore(IConfiguration configuration, ref IDictionary obj, BinderOptions? binderOptions) { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - foreach (IConfigurationSection section in configuration.GetChildren()) { if (section.Value is string value) @@ -168,11 +147,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration public static void BindCore(IConfiguration configuration, ref IReadOnlyDictionary obj, BinderOptions? binderOptions) { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - if (obj is not IDictionary temp) { return; @@ -189,11 +163,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration public static void BindCore(IConfiguration configuration, ref Program.MyClassWithCustomCollections obj, BinderOptions? binderOptions) { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - ValidateConfigurationKeys(typeof(Program.MyClassWithCustomCollections), s_configKeys_ProgramMyClassWithCustomCollections, configuration, binderOptions); if (AsConfigWithChildren(configuration.GetSection("CustomDictionary")) is IConfigurationSection section1) @@ -229,6 +198,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration } } + /// If required by the binder options, validates that there are no unknown keys in the input configuration object. public static void ValidateConfigurationKeys(Type type, Lazy> keys, IConfiguration configuration, BinderOptions? binderOptions) { @@ -281,7 +251,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration if (binderOptions.BindNonPublicProperties) { - throw new global::System.NotSupportedException($"The configuration binding source generator does not support 'BinderOptions.BindNonPublicProperties'."); + throw new NotSupportedException($"The configuration binding source generator does not support 'BinderOptions.BindNonPublicProperties'."); } return binderOptions; @@ -298,5 +268,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration throw new InvalidOperationException($"Failed to convert configuration value at '{getPath()}' to type '{typeof(int)}'.", exception); } } + #endregion Core binding extensions. } } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Bind.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Bind.generated.txt index bc4ab24e91344..d9af7ffbd32a3 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Bind.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Bind.generated.txt @@ -35,6 +35,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration public static void Bind_ProgramMyClass(this IConfiguration configuration, object? obj) { ArgumentNullException.ThrowIfNull(configuration); + ArgumentNullException.ThrowIfNull(obj); var typedObj = (Program.MyClass)obj; @@ -45,15 +46,9 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration [InterceptsLocationAttribute(@"src-0.cs", 14, 24)] public static void Bind_ProgramMyClass(this IConfiguration configuration, object? obj, Action? configureOptions) { - if (configuration is null) - { - throw new ArgumentNullException(nameof(configuration)); - } + ArgumentNullException.ThrowIfNull(configuration); - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } + ArgumentNullException.ThrowIfNull(obj); var typedObj = (Program.MyClass)obj; BindCore(configuration, ref typedObj, GetBinderOptions(configureOptions)); @@ -64,6 +59,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration public static void Bind_ProgramMyClass(this IConfiguration configuration, string key, object? obj) { ArgumentNullException.ThrowIfNull(configuration); + ArgumentNullException.ThrowIfNull(obj); var typedObj = (Program.MyClass)obj; diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Bind.net462.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Bind.net462.generated.txt index 406e8db671677..36ac12fd31f83 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Bind.net462.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Bind.net462.generated.txt @@ -2,18 +2,19 @@ #nullable enable #pragma warning disable CS0612, CS0618 // Suppress warnings about [Obsolete] member usage in generated code. -/// Generated helper providing an AOT and linking compatible implementation for configuration binding. -[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")] -internal static class GeneratedConfigurationBinder +namespace System.Runtime.CompilerServices { - /// Attempts to bind the given object instance to configuration values by matching property names against configuration keys recursively. - public static void Bind(this global::Microsoft.Extensions.Configuration.IConfiguration configuration, global::Program.MyClass obj) => global::Microsoft.Extensions.Configuration.Binder.SourceGeneration.CoreBindingHelper.BindCore(configuration, ref obj, binderOptions: null); - - /// Attempts to bind the given object instance to configuration values by matching property names against configuration keys recursively. - public static void Bind(this global::Microsoft.Extensions.Configuration.IConfiguration configuration, global::Program.MyClass obj, global::System.Action? configureOptions) => global::Microsoft.Extensions.Configuration.Binder.SourceGeneration.CoreBindingHelper.BindCore(configuration, ref obj, global::Microsoft.Extensions.Configuration.Binder.SourceGeneration.CoreBindingHelper.GetBinderOptions(configureOptions)); + using System; + using System.CodeDom.Compiler; - /// Attempts to bind the given object instance to configuration values by matching property names against configuration keys recursively. - public static void Bind(this global::Microsoft.Extensions.Configuration.IConfiguration configuration, string key, global::Program.MyClass obj) => global::Microsoft.Extensions.Configuration.Binder.SourceGeneration.CoreBindingHelper.BindCore(configuration.GetSection(key), ref obj, binderOptions: null); + [GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")] + [AttributeUsage(AttributeTargets.Method, AllowMultiple = true)] + file sealed class InterceptsLocationAttribute : Attribute + { + public InterceptsLocationAttribute(string filePath, int line, int column) + { + } + } } namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration @@ -23,20 +24,72 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration using System.CodeDom.Compiler; using System.Collections.Generic; using System.Globalization; + using System.Runtime.CompilerServices; - /// Provide core binding logic. [GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")] - file static class CoreBindingHelper + file static class BindingExtensions { - private readonly static Lazy> s_configKeys_ProgramMyClass = new(() => new HashSet(StringComparer.OrdinalIgnoreCase) { "MyString", "MyInt", "MyList", "MyDictionary", "MyComplexDictionary" }); + #region IConfiguration extensions. + /// Attempts to bind the given object instance to configuration values by matching property names against configuration keys recursively. + [InterceptsLocationAttribute(@"src-0.cs", 13, 18)] + public static void Bind_ProgramMyClass(this IConfiguration configuration, object? obj) + { + if (configuration is null) + { + throw new ArgumentNullException(nameof(configuration)); + } - public static void BindCore(IConfiguration configuration, ref List obj, BinderOptions? binderOptions) + if (obj is null) + { + throw new ArgumentNullException(nameof(obj)); + } + + var typedObj = (Program.MyClass)obj; + BindCore(configuration, ref typedObj, binderOptions: null); + } + + /// Attempts to bind the given object instance to configuration values by matching property names against configuration keys recursively. + [InterceptsLocationAttribute(@"src-0.cs", 14, 24)] + public static void Bind_ProgramMyClass(this IConfiguration configuration, object? obj, Action? configureOptions) + { + if (configuration is null) + { + throw new ArgumentNullException(nameof(configuration)); + } + + if (obj is null) + { + throw new ArgumentNullException(nameof(obj)); + } + + var typedObj = (Program.MyClass)obj; + BindCore(configuration, ref typedObj, GetBinderOptions(configureOptions)); + } + + /// Attempts to bind the given object instance to configuration values by matching property names against configuration keys recursively. + [InterceptsLocationAttribute(@"src-0.cs", 15, 24)] + public static void Bind_ProgramMyClass(this IConfiguration configuration, string key, object? obj) { + if (configuration is null) + { + throw new ArgumentNullException(nameof(configuration)); + } + if (obj is null) { throw new ArgumentNullException(nameof(obj)); } + var typedObj = (Program.MyClass)obj; + BindCore(configuration.GetSection(key), ref typedObj, binderOptions: null); + } + #endregion IConfiguration extensions. + + #region Core binding extensions. + private readonly static Lazy> s_configKeys_ProgramMyClass = new(() => new HashSet(StringComparer.OrdinalIgnoreCase) { "MyString", "MyInt", "MyList", "MyDictionary", "MyComplexDictionary" }); + + public static void BindCore(IConfiguration configuration, ref List obj, BinderOptions? binderOptions) + { foreach (IConfigurationSection section in configuration.GetChildren()) { if (section.Value is string value) @@ -48,11 +101,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration public static void BindCore(IConfiguration configuration, ref Dictionary obj, BinderOptions? binderOptions) { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - foreach (IConfigurationSection section in configuration.GetChildren()) { if (section.Value is string value) @@ -64,11 +112,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration public static void BindCore(IConfiguration configuration, ref Dictionary obj, BinderOptions? binderOptions) { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - foreach (IConfigurationSection section in configuration.GetChildren()) { if (!(obj.TryGetValue(section.Key, out Program.MyClass2? element) && element is not null)) @@ -81,11 +124,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration public static void BindCore(IConfiguration configuration, ref Program.MyClass obj, BinderOptions? binderOptions) { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - ValidateConfigurationKeys(typeof(Program.MyClass), s_configKeys_ProgramMyClass, configuration, binderOptions); obj.MyString = configuration["MyString"]!; @@ -120,6 +158,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration } } + /// If required by the binder options, validates that there are no unknown keys in the input configuration object. public static void ValidateConfigurationKeys(Type type, Lazy> keys, IConfiguration configuration, BinderOptions? binderOptions) { @@ -163,7 +202,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration if (binderOptions.BindNonPublicProperties) { - throw new global::System.NotSupportedException($"The configuration binding source generator does not support 'BinderOptions.BindNonPublicProperties'."); + throw new NotSupportedException($"The configuration binding source generator does not support 'BinderOptions.BindNonPublicProperties'."); } return binderOptions; @@ -180,5 +219,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration throw new InvalidOperationException($"Failed to convert configuration value at '{getPath()}' to type '{typeof(int)}'.", exception); } } + #endregion Core binding extensions. } } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Bind_Instance.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Bind_Instance.generated.txt index aa3d330fd0ea6..8755ff8c2dfb0 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Bind_Instance.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Bind_Instance.generated.txt @@ -35,6 +35,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration public static void Bind_ProgramMyClass(this IConfiguration configuration, object? obj) { ArgumentNullException.ThrowIfNull(configuration); + ArgumentNullException.ThrowIfNull(obj); var typedObj = (Program.MyClass)obj; diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Bind_Instance.net462.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Bind_Instance.net462.generated.txt index 106e01795369e..02fb06957bb3d 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Bind_Instance.net462.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Bind_Instance.net462.generated.txt @@ -2,12 +2,19 @@ #nullable enable #pragma warning disable CS0612, CS0618 // Suppress warnings about [Obsolete] member usage in generated code. -/// Generated helper providing an AOT and linking compatible implementation for configuration binding. -[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")] -internal static class GeneratedConfigurationBinder +namespace System.Runtime.CompilerServices { - /// Attempts to bind the given object instance to configuration values by matching property names against configuration keys recursively. - public static void Bind(this global::Microsoft.Extensions.Configuration.IConfiguration configuration, global::Program.MyClass obj) => global::Microsoft.Extensions.Configuration.Binder.SourceGeneration.CoreBindingHelper.BindCore(configuration, ref obj, binderOptions: null); + using System; + using System.CodeDom.Compiler; + + [GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")] + [AttributeUsage(AttributeTargets.Method, AllowMultiple = true)] + file sealed class InterceptsLocationAttribute : Attribute + { + public InterceptsLocationAttribute(string filePath, int line, int column) + { + } + } } namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration @@ -17,20 +24,36 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration using System.CodeDom.Compiler; using System.Collections.Generic; using System.Globalization; + using System.Runtime.CompilerServices; - /// Provide core binding logic. [GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")] - file static class CoreBindingHelper + file static class BindingExtensions { - private readonly static Lazy> s_configKeys_ProgramMyClass = new(() => new HashSet(StringComparer.OrdinalIgnoreCase) { "MyString", "MyInt", "MyList", "MyDictionary", "MyComplexDictionary" }); - - public static void BindCore(IConfiguration configuration, ref List obj, BinderOptions? binderOptions) + #region IConfiguration extensions. + /// Attempts to bind the given object instance to configuration values by matching property names against configuration keys recursively. + [InterceptsLocationAttribute(@"src-0.cs", 12, 20)] + public static void Bind_ProgramMyClass(this IConfiguration configuration, object? obj) { + if (configuration is null) + { + throw new ArgumentNullException(nameof(configuration)); + } + if (obj is null) { throw new ArgumentNullException(nameof(obj)); } + var typedObj = (Program.MyClass)obj; + BindCore(configuration, ref typedObj, binderOptions: null); + } + #endregion IConfiguration extensions. + + #region Core binding extensions. + private readonly static Lazy> s_configKeys_ProgramMyClass = new(() => new HashSet(StringComparer.OrdinalIgnoreCase) { "MyString", "MyInt", "MyList", "MyDictionary", "MyComplexDictionary" }); + + public static void BindCore(IConfiguration configuration, ref List obj, BinderOptions? binderOptions) + { foreach (IConfigurationSection section in configuration.GetChildren()) { if (section.Value is string value) @@ -42,11 +65,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration public static void BindCore(IConfiguration configuration, ref Dictionary obj, BinderOptions? binderOptions) { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - foreach (IConfigurationSection section in configuration.GetChildren()) { if (section.Value is string value) @@ -58,11 +76,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration public static void BindCore(IConfiguration configuration, ref Dictionary obj, BinderOptions? binderOptions) { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - foreach (IConfigurationSection section in configuration.GetChildren()) { if (!(obj.TryGetValue(section.Key, out Program.MyClass2? element) && element is not null)) @@ -75,11 +88,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration public static void BindCore(IConfiguration configuration, ref Program.MyClass obj, BinderOptions? binderOptions) { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - ValidateConfigurationKeys(typeof(Program.MyClass), s_configKeys_ProgramMyClass, configuration, binderOptions); obj.MyString = configuration["MyString"]!; @@ -114,6 +122,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration } } + /// If required by the binder options, validates that there are no unknown keys in the input configuration object. public static void ValidateConfigurationKeys(Type type, Lazy> keys, IConfiguration configuration, BinderOptions? binderOptions) { @@ -156,5 +165,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration throw new InvalidOperationException($"Failed to convert configuration value at '{getPath()}' to type '{typeof(int)}'.", exception); } } + #endregion Core binding extensions. } } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Bind_Instance_BinderOptions.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Bind_Instance_BinderOptions.generated.txt index 2cbc192b2867d..a30be1588d2f1 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Bind_Instance_BinderOptions.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Bind_Instance_BinderOptions.generated.txt @@ -35,6 +35,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration public static void Bind_ProgramMyClass(this IConfiguration configuration, object? obj, Action? configureOptions) { ArgumentNullException.ThrowIfNull(configuration); + ArgumentNullException.ThrowIfNull(obj); var typedObj = (Program.MyClass)obj; diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Bind_Instance_BinderOptions.net462.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Bind_Instance_BinderOptions.net462.generated.txt index a1cb7d6b93b5d..4703980996b88 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Bind_Instance_BinderOptions.net462.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Bind_Instance_BinderOptions.net462.generated.txt @@ -2,12 +2,19 @@ #nullable enable #pragma warning disable CS0612, CS0618 // Suppress warnings about [Obsolete] member usage in generated code. -/// Generated helper providing an AOT and linking compatible implementation for configuration binding. -[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")] -internal static class GeneratedConfigurationBinder +namespace System.Runtime.CompilerServices { - /// Attempts to bind the given object instance to configuration values by matching property names against configuration keys recursively. - public static void Bind(this global::Microsoft.Extensions.Configuration.IConfiguration configuration, global::Program.MyClass obj, global::System.Action? configureOptions) => global::Microsoft.Extensions.Configuration.Binder.SourceGeneration.CoreBindingHelper.BindCore(configuration, ref obj, global::Microsoft.Extensions.Configuration.Binder.SourceGeneration.CoreBindingHelper.GetBinderOptions(configureOptions)); + using System; + using System.CodeDom.Compiler; + + [GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")] + [AttributeUsage(AttributeTargets.Method, AllowMultiple = true)] + file sealed class InterceptsLocationAttribute : Attribute + { + public InterceptsLocationAttribute(string filePath, int line, int column) + { + } + } } namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration @@ -17,20 +24,36 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration using System.CodeDom.Compiler; using System.Collections.Generic; using System.Globalization; + using System.Runtime.CompilerServices; - /// Provide core binding logic. [GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")] - file static class CoreBindingHelper + file static class BindingExtensions { - private readonly static Lazy> s_configKeys_ProgramMyClass = new(() => new HashSet(StringComparer.OrdinalIgnoreCase) { "MyString", "MyInt", "MyList", "MyDictionary", "MyComplexDictionary" }); - - public static void BindCore(IConfiguration configuration, ref List obj, BinderOptions? binderOptions) + #region IConfiguration extensions. + /// Attempts to bind the given object instance to configuration values by matching property names against configuration keys recursively. + [InterceptsLocationAttribute(@"src-0.cs", 12, 20)] + public static void Bind_ProgramMyClass(this IConfiguration configuration, object? obj, Action? configureOptions) { + if (configuration is null) + { + throw new ArgumentNullException(nameof(configuration)); + } + if (obj is null) { throw new ArgumentNullException(nameof(obj)); } + var typedObj = (Program.MyClass)obj; + BindCore(configuration, ref typedObj, GetBinderOptions(configureOptions)); + } + #endregion IConfiguration extensions. + + #region Core binding extensions. + private readonly static Lazy> s_configKeys_ProgramMyClass = new(() => new HashSet(StringComparer.OrdinalIgnoreCase) { "MyString", "MyInt", "MyList", "MyDictionary", "MyComplexDictionary" }); + + public static void BindCore(IConfiguration configuration, ref List obj, BinderOptions? binderOptions) + { foreach (IConfigurationSection section in configuration.GetChildren()) { if (section.Value is string value) @@ -42,11 +65,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration public static void BindCore(IConfiguration configuration, ref Dictionary obj, BinderOptions? binderOptions) { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - foreach (IConfigurationSection section in configuration.GetChildren()) { if (section.Value is string value) @@ -58,11 +76,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration public static void BindCore(IConfiguration configuration, ref Dictionary obj, BinderOptions? binderOptions) { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - foreach (IConfigurationSection section in configuration.GetChildren()) { if (!(obj.TryGetValue(section.Key, out Program.MyClass2? element) && element is not null)) @@ -75,11 +88,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration public static void BindCore(IConfiguration configuration, ref Program.MyClass obj, BinderOptions? binderOptions) { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - ValidateConfigurationKeys(typeof(Program.MyClass), s_configKeys_ProgramMyClass, configuration, binderOptions); obj.MyString = configuration["MyString"]!; @@ -114,6 +122,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration } } + /// If required by the binder options, validates that there are no unknown keys in the input configuration object. public static void ValidateConfigurationKeys(Type type, Lazy> keys, IConfiguration configuration, BinderOptions? binderOptions) { @@ -157,7 +166,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration if (binderOptions.BindNonPublicProperties) { - throw new global::System.NotSupportedException($"The configuration binding source generator does not support 'BinderOptions.BindNonPublicProperties'."); + throw new NotSupportedException($"The configuration binding source generator does not support 'BinderOptions.BindNonPublicProperties'."); } return binderOptions; @@ -174,5 +183,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration throw new InvalidOperationException($"Failed to convert configuration value at '{getPath()}' to type '{typeof(int)}'.", exception); } } + #endregion Core binding extensions. } } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Bind_Key_Instance.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Bind_Key_Instance.generated.txt index 48dceb11e053f..c0e00e75e8cf5 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Bind_Key_Instance.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Bind_Key_Instance.generated.txt @@ -35,6 +35,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration public static void Bind_ProgramMyClass(this IConfiguration configuration, string key, object? obj) { ArgumentNullException.ThrowIfNull(configuration); + ArgumentNullException.ThrowIfNull(obj); var typedObj = (Program.MyClass)obj; diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Bind_Key_Instance.net462.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Bind_Key_Instance.net462.generated.txt index f3ee8a9ff4384..9937129699716 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Bind_Key_Instance.net462.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Bind_Key_Instance.net462.generated.txt @@ -2,12 +2,19 @@ #nullable enable #pragma warning disable CS0612, CS0618 // Suppress warnings about [Obsolete] member usage in generated code. -/// Generated helper providing an AOT and linking compatible implementation for configuration binding. -[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")] -internal static class GeneratedConfigurationBinder +namespace System.Runtime.CompilerServices { - /// Attempts to bind the given object instance to configuration values by matching property names against configuration keys recursively. - public static void Bind(this global::Microsoft.Extensions.Configuration.IConfiguration configuration, string key, global::Program.MyClass obj) => global::Microsoft.Extensions.Configuration.Binder.SourceGeneration.CoreBindingHelper.BindCore(configuration.GetSection(key), ref obj, binderOptions: null); + using System; + using System.CodeDom.Compiler; + + [GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")] + [AttributeUsage(AttributeTargets.Method, AllowMultiple = true)] + file sealed class InterceptsLocationAttribute : Attribute + { + public InterceptsLocationAttribute(string filePath, int line, int column) + { + } + } } namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration @@ -17,20 +24,36 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration using System.CodeDom.Compiler; using System.Collections.Generic; using System.Globalization; + using System.Runtime.CompilerServices; - /// Provide core binding logic. [GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")] - file static class CoreBindingHelper + file static class BindingExtensions { - private readonly static Lazy> s_configKeys_ProgramMyClass = new(() => new HashSet(StringComparer.OrdinalIgnoreCase) { "MyString", "MyInt", "MyList", "MyDictionary", "MyComplexDictionary" }); - - public static void BindCore(IConfiguration configuration, ref List obj, BinderOptions? binderOptions) + #region IConfiguration extensions. + /// Attempts to bind the given object instance to configuration values by matching property names against configuration keys recursively. + [InterceptsLocationAttribute(@"src-0.cs", 12, 20)] + public static void Bind_ProgramMyClass(this IConfiguration configuration, string key, object? obj) { + if (configuration is null) + { + throw new ArgumentNullException(nameof(configuration)); + } + if (obj is null) { throw new ArgumentNullException(nameof(obj)); } + var typedObj = (Program.MyClass)obj; + BindCore(configuration.GetSection(key), ref typedObj, binderOptions: null); + } + #endregion IConfiguration extensions. + + #region Core binding extensions. + private readonly static Lazy> s_configKeys_ProgramMyClass = new(() => new HashSet(StringComparer.OrdinalIgnoreCase) { "MyString", "MyInt", "MyList", "MyDictionary", "MyComplexDictionary" }); + + public static void BindCore(IConfiguration configuration, ref List obj, BinderOptions? binderOptions) + { foreach (IConfigurationSection section in configuration.GetChildren()) { if (section.Value is string value) @@ -42,11 +65,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration public static void BindCore(IConfiguration configuration, ref Dictionary obj, BinderOptions? binderOptions) { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - foreach (IConfigurationSection section in configuration.GetChildren()) { if (section.Value is string value) @@ -58,11 +76,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration public static void BindCore(IConfiguration configuration, ref Dictionary obj, BinderOptions? binderOptions) { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - foreach (IConfigurationSection section in configuration.GetChildren()) { if (!(obj.TryGetValue(section.Key, out Program.MyClass2? element) && element is not null)) @@ -75,11 +88,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration public static void BindCore(IConfiguration configuration, ref Program.MyClass obj, BinderOptions? binderOptions) { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - ValidateConfigurationKeys(typeof(Program.MyClass), s_configKeys_ProgramMyClass, configuration, binderOptions); obj.MyString = configuration["MyString"]!; @@ -114,6 +122,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration } } + /// If required by the binder options, validates that there are no unknown keys in the input configuration object. public static void ValidateConfigurationKeys(Type type, Lazy> keys, IConfiguration configuration, BinderOptions? binderOptions) { @@ -156,5 +165,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration throw new InvalidOperationException($"Failed to convert configuration value at '{getPath()}' to type '{typeof(int)}'.", exception); } } + #endregion Core binding extensions. } } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Get.net462.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Get.net462.generated.txt index fb71c70b4dd3b..3e6ce1459b289 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Get.net462.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Get.net462.generated.txt @@ -2,21 +2,19 @@ #nullable enable #pragma warning disable CS0612, CS0618 // Suppress warnings about [Obsolete] member usage in generated code. -/// Generated helper providing an AOT and linking compatible implementation for configuration binding. -[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")] -internal static class GeneratedConfigurationBinder +namespace System.Runtime.CompilerServices { - /// Attempts to bind the configuration instance to a new instance of type T. - public static T? Get(this global::Microsoft.Extensions.Configuration.IConfiguration configuration) => (T?)(global::Microsoft.Extensions.Configuration.Binder.SourceGeneration.CoreBindingHelper.GetCore(configuration, typeof(T), configureOptions: null) ?? default(T)); - - /// Attempts to bind the configuration instance to a new instance of type T. - public static T? Get(this global::Microsoft.Extensions.Configuration.IConfiguration configuration, global::System.Action? configureOptions) => (T?)(global::Microsoft.Extensions.Configuration.Binder.SourceGeneration.CoreBindingHelper.GetCore(configuration, typeof(T), configureOptions) ?? default(T)); - - /// Attempts to bind the configuration instance to a new instance of type T. - public static object? Get(this global::Microsoft.Extensions.Configuration.IConfiguration configuration, global::System.Type type) => global::Microsoft.Extensions.Configuration.Binder.SourceGeneration.CoreBindingHelper.GetCore(configuration, type, configureOptions: null); + using System; + using System.CodeDom.Compiler; - /// Attempts to bind the configuration instance to a new instance of type T. - public static object? Get(this global::Microsoft.Extensions.Configuration.IConfiguration configuration, global::System.Type type, global::System.Action? configureOptions) => global::Microsoft.Extensions.Configuration.Binder.SourceGeneration.CoreBindingHelper.GetCore(configuration, type, configureOptions); + [GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")] + [AttributeUsage(AttributeTargets.Method, AllowMultiple = true)] + file sealed class InterceptsLocationAttribute : Attribute + { + public InterceptsLocationAttribute(string filePath, int line, int column) + { + } + } } namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration @@ -26,11 +24,30 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration using System.CodeDom.Compiler; using System.Collections.Generic; using System.Globalization; + using System.Runtime.CompilerServices; - /// Provide core binding logic. [GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")] - file static class CoreBindingHelper + file static class BindingExtensions { + #region IConfiguration extensions. + /// Attempts to bind the configuration instance to a new instance of type T. + [InterceptsLocationAttribute(@"src-0.cs", 12, 38)] + public static T? Get(this IConfiguration configuration) => (T?)(GetCore(configuration, typeof(T), configureOptions: null) ?? default(T)); + + /// Attempts to bind the configuration instance to a new instance of type T. + [InterceptsLocationAttribute(@"src-0.cs", 14, 36)] + public static T? Get(this IConfiguration configuration, Action? configureOptions) => (T?)(GetCore(configuration, typeof(T), configureOptions) ?? default(T)); + + /// Attempts to bind the configuration instance to a new instance of type T. + [InterceptsLocationAttribute(@"src-0.cs", 13, 36)] + public static object? Get(this IConfiguration configuration, Type type) => GetCore(configuration, type, configureOptions: null); + + /// Attempts to bind the configuration instance to a new instance of type T. + [InterceptsLocationAttribute(@"src-0.cs", 15, 36)] + public static object? Get(this IConfiguration configuration, Type type, Action? configureOptions) => GetCore(configuration, type, configureOptions); + #endregion IConfiguration extensions. + + #region Core binding extensions. private readonly static Lazy> s_configKeys_ProgramMyClass = new(() => new HashSet(StringComparer.OrdinalIgnoreCase) { "MyString", "MyInt", "MyList", "MyArray", "MyDictionary" }); private readonly static Lazy> s_configKeys_ProgramMyClass2 = new(() => new HashSet(StringComparer.OrdinalIgnoreCase) { "MyInt" }); @@ -54,24 +71,18 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration BindCore(configuration, ref obj, binderOptions); return obj; } - - if (type == typeof(Program.MyClass2)) + else if (type == typeof(Program.MyClass2)) { var obj = new Program.MyClass2(); BindCore(configuration, ref obj, binderOptions); return obj; } - throw new global::System.NotSupportedException($"Unable to bind to type '{type}': generator did not detect the type as input."); + throw new NotSupportedException($"Unable to bind to type '{type}': generator did not detect the type as input."); } public static void BindCore(IConfiguration configuration, ref List obj, BinderOptions? binderOptions) { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - foreach (IConfigurationSection section in configuration.GetChildren()) { if (section.Value is string value) @@ -83,11 +94,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration public static void BindCore(IConfiguration configuration, ref int[] obj, BinderOptions? binderOptions) { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - var temp2 = new List(); BindCore(configuration, ref temp2, binderOptions); int originalCount = obj.Length; @@ -97,11 +103,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration public static void BindCore(IConfiguration configuration, ref Dictionary obj, BinderOptions? binderOptions) { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - foreach (IConfigurationSection section in configuration.GetChildren()) { if (section.Value is string value) @@ -113,11 +114,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration public static void BindCore(IConfiguration configuration, ref Program.MyClass obj, BinderOptions? binderOptions) { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - ValidateConfigurationKeys(typeof(Program.MyClass), s_configKeys_ProgramMyClass, configuration, binderOptions); obj.MyString = configuration["MyString"]!; @@ -154,11 +150,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration public static void BindCore(IConfiguration configuration, ref Program.MyClass2 obj, BinderOptions? binderOptions) { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - ValidateConfigurationKeys(typeof(Program.MyClass2), s_configKeys_ProgramMyClass2, configuration, binderOptions); if (configuration["MyInt"] is string value15) @@ -167,6 +158,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration } } + /// If required by the binder options, validates that there are no unknown keys in the input configuration object. public static void ValidateConfigurationKeys(Type type, Lazy> keys, IConfiguration configuration, BinderOptions? binderOptions) { @@ -219,7 +211,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration if (binderOptions.BindNonPublicProperties) { - throw new global::System.NotSupportedException($"The configuration binding source generator does not support 'BinderOptions.BindNonPublicProperties'."); + throw new NotSupportedException($"The configuration binding source generator does not support 'BinderOptions.BindNonPublicProperties'."); } return binderOptions; @@ -236,5 +228,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration throw new InvalidOperationException($"Failed to convert configuration value at '{getPath()}' to type '{typeof(int)}'.", exception); } } + #endregion Core binding extensions. } } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/GetValue.net462.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/GetValue.net462.generated.txt index c9d49faa93724..e4bcaf6a9b7c9 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/GetValue.net462.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/GetValue.net462.generated.txt @@ -2,21 +2,19 @@ #nullable enable #pragma warning disable CS0612, CS0618 // Suppress warnings about [Obsolete] member usage in generated code. -/// Generated helper providing an AOT and linking compatible implementation for configuration binding. -[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")] -internal static class GeneratedConfigurationBinder +namespace System.Runtime.CompilerServices { - /// Extracts the value with the specified key and converts it to the specified type. - public static T? GetValue(this global::Microsoft.Extensions.Configuration.IConfiguration configuration, string key) => (T?)(global::Microsoft.Extensions.Configuration.Binder.SourceGeneration.CoreBindingHelper.GetValueCore(configuration, typeof(T), key) ?? default(T)); - - /// Extracts the value with the specified key and converts it to the specified type. - public static T? GetValue(this global::Microsoft.Extensions.Configuration.IConfiguration configuration, string key, T defaultValue) => (T?)(global::Microsoft.Extensions.Configuration.Binder.SourceGeneration.CoreBindingHelper.GetValueCore(configuration, typeof(T), key) ?? defaultValue); - - /// Extracts the value with the specified key and converts it to the specified type. - public static object? GetValue(this global::Microsoft.Extensions.Configuration.IConfiguration configuration, global::System.Type type, string key) => global::Microsoft.Extensions.Configuration.Binder.SourceGeneration.CoreBindingHelper.GetValueCore(configuration, type, key); + using System; + using System.CodeDom.Compiler; - /// Extracts the value with the specified key and converts it to the specified type. - public static object? GetValue(this global::Microsoft.Extensions.Configuration.IConfiguration configuration, global::System.Type type, string key, object? defaultValue) => global::Microsoft.Extensions.Configuration.Binder.SourceGeneration.CoreBindingHelper.GetValueCore(configuration, type, key) ?? defaultValue; + [GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")] + [AttributeUsage(AttributeTargets.Method, AllowMultiple = true)] + file sealed class InterceptsLocationAttribute : Attribute + { + public InterceptsLocationAttribute(string filePath, int line, int column) + { + } + } } namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration @@ -25,11 +23,30 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration using System; using System.CodeDom.Compiler; using System.Globalization; + using System.Runtime.CompilerServices; - /// Provide core binding logic. [GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")] - file static class CoreBindingHelper + file static class BindingExtensions { + #region IConfiguration extensions. + /// Extracts the value with the specified key and converts it to the specified type. + [InterceptsLocationAttribute(@"src-0.cs", 13, 18)] + public static T? GetValue(this IConfiguration configuration, string key) => (T?)(BindingExtensions.GetValueCore(configuration, typeof(T), key) ?? default(T)); + + /// Extracts the value with the specified key and converts it to the specified type. + [InterceptsLocationAttribute(@"src-0.cs", 16, 24)] + public static T? GetValue(this IConfiguration configuration, string key, T defaultValue) => (T?)(BindingExtensions.GetValueCore(configuration, typeof(T), key) ?? defaultValue); + + /// Extracts the value with the specified key and converts it to the specified type. + [InterceptsLocationAttribute(@"src-0.cs", 14, 24)] + public static object? GetValue(this IConfiguration configuration, Type type, string key) => BindingExtensions.GetValueCore(configuration, type, key); + + /// Extracts the value with the specified key and converts it to the specified type. + [InterceptsLocationAttribute(@"src-0.cs", 17, 24)] + public static object? GetValue(this IConfiguration configuration, Type type, string key, object? defaultValue) => BindingExtensions.GetValueCore(configuration, type, key) ?? defaultValue; + #endregion IConfiguration extensions. + + #region Core binding extensions. public static object? GetValueCore(this IConfiguration configuration, Type type, string key) { if (configuration is null) @@ -48,18 +65,15 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration { return ParseInt(value, () => section.Path); } - - if (type == typeof(bool?)) + else if (type == typeof(bool?)) { return ParseBool(value, () => section.Path); } - - if (type == typeof(byte[])) + else if (type == typeof(byte[])) { return ParseByteArray(value, () => section.Path); } - - if (type == typeof(CultureInfo)) + else if (type == typeof(CultureInfo)) { return ParseCultureInfo(value, () => section.Path); } @@ -114,5 +128,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration throw new InvalidOperationException($"Failed to convert configuration value at '{getPath()}' to type '{typeof(CultureInfo)}'.", exception); } } + #endregion Core binding extensions. } } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/GetValue_T_Key.net462.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/GetValue_T_Key.net462.generated.txt index 17c963bd980a7..2438cf530ca4c 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/GetValue_T_Key.net462.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/GetValue_T_Key.net462.generated.txt @@ -2,12 +2,19 @@ #nullable enable #pragma warning disable CS0612, CS0618 // Suppress warnings about [Obsolete] member usage in generated code. -/// Generated helper providing an AOT and linking compatible implementation for configuration binding. -[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")] -internal static class GeneratedConfigurationBinder +namespace System.Runtime.CompilerServices { - /// Extracts the value with the specified key and converts it to the specified type. - public static T? GetValue(this global::Microsoft.Extensions.Configuration.IConfiguration configuration, string key) => (T?)(global::Microsoft.Extensions.Configuration.Binder.SourceGeneration.CoreBindingHelper.GetValueCore(configuration, typeof(T), key) ?? default(T)); + using System; + using System.CodeDom.Compiler; + + [GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")] + [AttributeUsage(AttributeTargets.Method, AllowMultiple = true)] + file sealed class InterceptsLocationAttribute : Attribute + { + public InterceptsLocationAttribute(string filePath, int line, int column) + { + } + } } namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration @@ -16,11 +23,18 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration using System; using System.CodeDom.Compiler; using System.Globalization; + using System.Runtime.CompilerServices; - /// Provide core binding logic. [GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")] - file static class CoreBindingHelper + file static class BindingExtensions { + #region IConfiguration extensions. + /// Extracts the value with the specified key and converts it to the specified type. + [InterceptsLocationAttribute(@"src-0.cs", 10, 20)] + public static T? GetValue(this IConfiguration configuration, string key) => (T?)(BindingExtensions.GetValueCore(configuration, typeof(T), key) ?? default(T)); + #endregion IConfiguration extensions. + + #region Core binding extensions. public static object? GetValueCore(this IConfiguration configuration, Type type, string key) { if (configuration is null) @@ -54,5 +68,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration throw new InvalidOperationException($"Failed to convert configuration value at '{getPath()}' to type '{typeof(int)}'.", exception); } } + #endregion Core binding extensions. } } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/GetValue_T_Key_DefaultValue.net462.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/GetValue_T_Key_DefaultValue.net462.generated.txt index 1148109b9f5a8..e6db24d522f3c 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/GetValue_T_Key_DefaultValue.net462.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/GetValue_T_Key_DefaultValue.net462.generated.txt @@ -2,12 +2,19 @@ #nullable enable #pragma warning disable CS0612, CS0618 // Suppress warnings about [Obsolete] member usage in generated code. -/// Generated helper providing an AOT and linking compatible implementation for configuration binding. -[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")] -internal static class GeneratedConfigurationBinder +namespace System.Runtime.CompilerServices { - /// Extracts the value with the specified key and converts it to the specified type. - public static T? GetValue(this global::Microsoft.Extensions.Configuration.IConfiguration configuration, string key, T defaultValue) => (T?)(global::Microsoft.Extensions.Configuration.Binder.SourceGeneration.CoreBindingHelper.GetValueCore(configuration, typeof(T), key) ?? defaultValue); + using System; + using System.CodeDom.Compiler; + + [GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")] + [AttributeUsage(AttributeTargets.Method, AllowMultiple = true)] + file sealed class InterceptsLocationAttribute : Attribute + { + public InterceptsLocationAttribute(string filePath, int line, int column) + { + } + } } namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration @@ -16,11 +23,18 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration using System; using System.CodeDom.Compiler; using System.Globalization; + using System.Runtime.CompilerServices; - /// Provide core binding logic. [GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")] - file static class CoreBindingHelper + file static class BindingExtensions { + #region IConfiguration extensions. + /// Extracts the value with the specified key and converts it to the specified type. + [InterceptsLocationAttribute(@"src-0.cs", 12, 20)] + public static T? GetValue(this IConfiguration configuration, string key, T defaultValue) => (T?)(BindingExtensions.GetValueCore(configuration, typeof(T), key) ?? defaultValue); + #endregion IConfiguration extensions. + + #region Core binding extensions. public static object? GetValueCore(this IConfiguration configuration, Type type, string key) { if (configuration is null) @@ -54,5 +68,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration throw new InvalidOperationException($"Failed to convert configuration value at '{getPath()}' to type '{typeof(int)}'.", exception); } } + #endregion Core binding extensions. } } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/GetValue_TypeOf_Key.net462.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/GetValue_TypeOf_Key.net462.generated.txt index c833b20f18dcf..a36f9fafebcff 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/GetValue_TypeOf_Key.net462.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/GetValue_TypeOf_Key.net462.generated.txt @@ -2,12 +2,19 @@ #nullable enable #pragma warning disable CS0612, CS0618 // Suppress warnings about [Obsolete] member usage in generated code. -/// Generated helper providing an AOT and linking compatible implementation for configuration binding. -[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")] -internal static class GeneratedConfigurationBinder +namespace System.Runtime.CompilerServices { - /// Extracts the value with the specified key and converts it to the specified type. - public static object? GetValue(this global::Microsoft.Extensions.Configuration.IConfiguration configuration, global::System.Type type, string key) => global::Microsoft.Extensions.Configuration.Binder.SourceGeneration.CoreBindingHelper.GetValueCore(configuration, type, key); + using System; + using System.CodeDom.Compiler; + + [GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")] + [AttributeUsage(AttributeTargets.Method, AllowMultiple = true)] + file sealed class InterceptsLocationAttribute : Attribute + { + public InterceptsLocationAttribute(string filePath, int line, int column) + { + } + } } namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration @@ -16,11 +23,18 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration using System; using System.CodeDom.Compiler; using System.Globalization; + using System.Runtime.CompilerServices; - /// Provide core binding logic. [GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")] - file static class CoreBindingHelper + file static class BindingExtensions { + #region IConfiguration extensions. + /// Extracts the value with the specified key and converts it to the specified type. + [InterceptsLocationAttribute(@"src-0.cs", 10, 20)] + public static object? GetValue(this IConfiguration configuration, Type type, string key) => BindingExtensions.GetValueCore(configuration, type, key); + #endregion IConfiguration extensions. + + #region Core binding extensions. public static object? GetValueCore(this IConfiguration configuration, Type type, string key) { if (configuration is null) @@ -54,5 +68,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration throw new InvalidOperationException($"Failed to convert configuration value at '{getPath()}' to type '{typeof(bool)}'.", exception); } } + #endregion Core binding extensions. } } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/GetValue_TypeOf_Key_DefaultValue.net462.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/GetValue_TypeOf_Key_DefaultValue.net462.generated.txt index f773f79ce6c2c..356f6bb1a933e 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/GetValue_TypeOf_Key_DefaultValue.net462.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/GetValue_TypeOf_Key_DefaultValue.net462.generated.txt @@ -2,12 +2,19 @@ #nullable enable #pragma warning disable CS0612, CS0618 // Suppress warnings about [Obsolete] member usage in generated code. -/// Generated helper providing an AOT and linking compatible implementation for configuration binding. -[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")] -internal static class GeneratedConfigurationBinder +namespace System.Runtime.CompilerServices { - /// Extracts the value with the specified key and converts it to the specified type. - public static object? GetValue(this global::Microsoft.Extensions.Configuration.IConfiguration configuration, global::System.Type type, string key, object? defaultValue) => global::Microsoft.Extensions.Configuration.Binder.SourceGeneration.CoreBindingHelper.GetValueCore(configuration, type, key) ?? defaultValue; + using System; + using System.CodeDom.Compiler; + + [GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")] + [AttributeUsage(AttributeTargets.Method, AllowMultiple = true)] + file sealed class InterceptsLocationAttribute : Attribute + { + public InterceptsLocationAttribute(string filePath, int line, int column) + { + } + } } namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration @@ -16,11 +23,18 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration using System; using System.CodeDom.Compiler; using System.Globalization; + using System.Runtime.CompilerServices; - /// Provide core binding logic. [GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")] - file static class CoreBindingHelper + file static class BindingExtensions { + #region IConfiguration extensions. + /// Extracts the value with the specified key and converts it to the specified type. + [InterceptsLocationAttribute(@"src-0.cs", 11, 20)] + public static object? GetValue(this IConfiguration configuration, Type type, string key, object? defaultValue) => BindingExtensions.GetValueCore(configuration, type, key) ?? defaultValue; + #endregion IConfiguration extensions. + + #region Core binding extensions. public static object? GetValueCore(this IConfiguration configuration, Type type, string key) { if (configuration is null) @@ -54,5 +68,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration throw new InvalidOperationException($"Failed to convert configuration value at '{getPath()}' to type '{typeof(CultureInfo)}'.", exception); } } + #endregion Core binding extensions. } } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Get_T.net462.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Get_T.net462.generated.txt index de8201fe6fed2..85d0901de3ff6 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Get_T.net462.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Get_T.net462.generated.txt @@ -2,12 +2,19 @@ #nullable enable #pragma warning disable CS0612, CS0618 // Suppress warnings about [Obsolete] member usage in generated code. -/// Generated helper providing an AOT and linking compatible implementation for configuration binding. -[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")] -internal static class GeneratedConfigurationBinder +namespace System.Runtime.CompilerServices { - /// Attempts to bind the configuration instance to a new instance of type T. - public static T? Get(this global::Microsoft.Extensions.Configuration.IConfiguration configuration) => (T?)(global::Microsoft.Extensions.Configuration.Binder.SourceGeneration.CoreBindingHelper.GetCore(configuration, typeof(T), configureOptions: null) ?? default(T)); + using System; + using System.CodeDom.Compiler; + + [GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")] + [AttributeUsage(AttributeTargets.Method, AllowMultiple = true)] + file sealed class InterceptsLocationAttribute : Attribute + { + public InterceptsLocationAttribute(string filePath, int line, int column) + { + } + } } namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration @@ -17,11 +24,18 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration using System.CodeDom.Compiler; using System.Collections.Generic; using System.Globalization; + using System.Runtime.CompilerServices; - /// Provide core binding logic. [GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")] - file static class CoreBindingHelper + file static class BindingExtensions { + #region IConfiguration extensions. + /// Attempts to bind the configuration instance to a new instance of type T. + [InterceptsLocationAttribute(@"src-0.cs", 11, 40)] + public static T? Get(this IConfiguration configuration) => (T?)(GetCore(configuration, typeof(T), configureOptions: null) ?? default(T)); + #endregion IConfiguration extensions. + + #region Core binding extensions. private readonly static Lazy> s_configKeys_ProgramMyClass = new(() => new HashSet(StringComparer.OrdinalIgnoreCase) { "MyString", "MyInt", "MyList", "MyArray", "MyDictionary" }); public static object? GetCore(this IConfiguration configuration, Type type, Action? configureOptions) @@ -45,16 +59,11 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration return obj; } - throw new global::System.NotSupportedException($"Unable to bind to type '{type}': generator did not detect the type as input."); + throw new NotSupportedException($"Unable to bind to type '{type}': generator did not detect the type as input."); } public static void BindCore(IConfiguration configuration, ref List obj, BinderOptions? binderOptions) { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - foreach (IConfigurationSection section in configuration.GetChildren()) { if (section.Value is string value) @@ -66,11 +75,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration public static void BindCore(IConfiguration configuration, ref int[] obj, BinderOptions? binderOptions) { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - var temp1 = new List(); BindCore(configuration, ref temp1, binderOptions); int originalCount = obj.Length; @@ -80,11 +84,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration public static void BindCore(IConfiguration configuration, ref Dictionary obj, BinderOptions? binderOptions) { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - foreach (IConfigurationSection section in configuration.GetChildren()) { if (section.Value is string value) @@ -96,11 +95,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration public static void BindCore(IConfiguration configuration, ref Program.MyClass obj, BinderOptions? binderOptions) { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - ValidateConfigurationKeys(typeof(Program.MyClass), s_configKeys_ProgramMyClass, configuration, binderOptions); obj.MyString = configuration["MyString"]!; @@ -135,6 +129,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration } } + /// If required by the binder options, validates that there are no unknown keys in the input configuration object. public static void ValidateConfigurationKeys(Type type, Lazy> keys, IConfiguration configuration, BinderOptions? binderOptions) { @@ -187,7 +182,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration if (binderOptions.BindNonPublicProperties) { - throw new global::System.NotSupportedException($"The configuration binding source generator does not support 'BinderOptions.BindNonPublicProperties'."); + throw new NotSupportedException($"The configuration binding source generator does not support 'BinderOptions.BindNonPublicProperties'."); } return binderOptions; @@ -204,5 +199,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration throw new InvalidOperationException($"Failed to convert configuration value at '{getPath()}' to type '{typeof(int)}'.", exception); } } + #endregion Core binding extensions. } } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Get_T_BinderOptions.net462.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Get_T_BinderOptions.net462.generated.txt index 34fadacace146..d394cc7b269f7 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Get_T_BinderOptions.net462.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Get_T_BinderOptions.net462.generated.txt @@ -2,12 +2,19 @@ #nullable enable #pragma warning disable CS0612, CS0618 // Suppress warnings about [Obsolete] member usage in generated code. -/// Generated helper providing an AOT and linking compatible implementation for configuration binding. -[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")] -internal static class GeneratedConfigurationBinder +namespace System.Runtime.CompilerServices { - /// Attempts to bind the configuration instance to a new instance of type T. - public static T? Get(this global::Microsoft.Extensions.Configuration.IConfiguration configuration, global::System.Action? configureOptions) => (T?)(global::Microsoft.Extensions.Configuration.Binder.SourceGeneration.CoreBindingHelper.GetCore(configuration, typeof(T), configureOptions) ?? default(T)); + using System; + using System.CodeDom.Compiler; + + [GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")] + [AttributeUsage(AttributeTargets.Method, AllowMultiple = true)] + file sealed class InterceptsLocationAttribute : Attribute + { + public InterceptsLocationAttribute(string filePath, int line, int column) + { + } + } } namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration @@ -17,11 +24,18 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration using System.CodeDom.Compiler; using System.Collections.Generic; using System.Globalization; + using System.Runtime.CompilerServices; - /// Provide core binding logic. [GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")] - file static class CoreBindingHelper + file static class BindingExtensions { + #region IConfiguration extensions. + /// Attempts to bind the configuration instance to a new instance of type T. + [InterceptsLocationAttribute(@"src-0.cs", 11, 40)] + public static T? Get(this IConfiguration configuration, Action? configureOptions) => (T?)(GetCore(configuration, typeof(T), configureOptions) ?? default(T)); + #endregion IConfiguration extensions. + + #region Core binding extensions. private readonly static Lazy> s_configKeys_ProgramMyClass = new(() => new HashSet(StringComparer.OrdinalIgnoreCase) { "MyString", "MyInt", "MyList", "MyArray", "MyDictionary" }); public static object? GetCore(this IConfiguration configuration, Type type, Action? configureOptions) @@ -45,16 +59,11 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration return obj; } - throw new global::System.NotSupportedException($"Unable to bind to type '{type}': generator did not detect the type as input."); + throw new NotSupportedException($"Unable to bind to type '{type}': generator did not detect the type as input."); } public static void BindCore(IConfiguration configuration, ref List obj, BinderOptions? binderOptions) { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - foreach (IConfigurationSection section in configuration.GetChildren()) { if (section.Value is string value) @@ -66,11 +75,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration public static void BindCore(IConfiguration configuration, ref int[] obj, BinderOptions? binderOptions) { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - var temp1 = new List(); BindCore(configuration, ref temp1, binderOptions); int originalCount = obj.Length; @@ -80,11 +84,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration public static void BindCore(IConfiguration configuration, ref Dictionary obj, BinderOptions? binderOptions) { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - foreach (IConfigurationSection section in configuration.GetChildren()) { if (section.Value is string value) @@ -96,11 +95,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration public static void BindCore(IConfiguration configuration, ref Program.MyClass obj, BinderOptions? binderOptions) { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - ValidateConfigurationKeys(typeof(Program.MyClass), s_configKeys_ProgramMyClass, configuration, binderOptions); obj.MyString = configuration["MyString"]!; @@ -135,6 +129,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration } } + /// If required by the binder options, validates that there are no unknown keys in the input configuration object. public static void ValidateConfigurationKeys(Type type, Lazy> keys, IConfiguration configuration, BinderOptions? binderOptions) { @@ -187,7 +182,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration if (binderOptions.BindNonPublicProperties) { - throw new global::System.NotSupportedException($"The configuration binding source generator does not support 'BinderOptions.BindNonPublicProperties'."); + throw new NotSupportedException($"The configuration binding source generator does not support 'BinderOptions.BindNonPublicProperties'."); } return binderOptions; @@ -204,5 +199,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration throw new InvalidOperationException($"Failed to convert configuration value at '{getPath()}' to type '{typeof(int)}'.", exception); } } + #endregion Core binding extensions. } } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Get_TypeOf.net462.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Get_TypeOf.net462.generated.txt index 16a98c931a705..83cd88561310a 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Get_TypeOf.net462.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Get_TypeOf.net462.generated.txt @@ -2,12 +2,19 @@ #nullable enable #pragma warning disable CS0612, CS0618 // Suppress warnings about [Obsolete] member usage in generated code. -/// Generated helper providing an AOT and linking compatible implementation for configuration binding. -[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")] -internal static class GeneratedConfigurationBinder +namespace System.Runtime.CompilerServices { - /// Attempts to bind the configuration instance to a new instance of type T. - public static object? Get(this global::Microsoft.Extensions.Configuration.IConfiguration configuration, global::System.Type type) => global::Microsoft.Extensions.Configuration.Binder.SourceGeneration.CoreBindingHelper.GetCore(configuration, type, configureOptions: null); + using System; + using System.CodeDom.Compiler; + + [GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")] + [AttributeUsage(AttributeTargets.Method, AllowMultiple = true)] + file sealed class InterceptsLocationAttribute : Attribute + { + public InterceptsLocationAttribute(string filePath, int line, int column) + { + } + } } namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration @@ -17,11 +24,18 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration using System.CodeDom.Compiler; using System.Collections.Generic; using System.Globalization; + using System.Runtime.CompilerServices; - /// Provide core binding logic. [GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")] - file static class CoreBindingHelper + file static class BindingExtensions { + #region IConfiguration extensions. + /// Attempts to bind the configuration instance to a new instance of type T. + [InterceptsLocationAttribute(@"src-0.cs", 11, 40)] + public static object? Get(this IConfiguration configuration, Type type) => GetCore(configuration, type, configureOptions: null); + #endregion IConfiguration extensions. + + #region Core binding extensions. private readonly static Lazy> s_configKeys_ProgramMyClass2 = new(() => new HashSet(StringComparer.OrdinalIgnoreCase) { "MyInt" }); public static object? GetCore(this IConfiguration configuration, Type type, Action? configureOptions) @@ -45,16 +59,11 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration return obj; } - throw new global::System.NotSupportedException($"Unable to bind to type '{type}': generator did not detect the type as input."); + throw new NotSupportedException($"Unable to bind to type '{type}': generator did not detect the type as input."); } public static void BindCore(IConfiguration configuration, ref Program.MyClass2 obj, BinderOptions? binderOptions) { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - ValidateConfigurationKeys(typeof(Program.MyClass2), s_configKeys_ProgramMyClass2, configuration, binderOptions); if (configuration["MyInt"] is string value1) @@ -63,6 +72,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration } } + /// If required by the binder options, validates that there are no unknown keys in the input configuration object. public static void ValidateConfigurationKeys(Type type, Lazy> keys, IConfiguration configuration, BinderOptions? binderOptions) { @@ -115,7 +125,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration if (binderOptions.BindNonPublicProperties) { - throw new global::System.NotSupportedException($"The configuration binding source generator does not support 'BinderOptions.BindNonPublicProperties'."); + throw new NotSupportedException($"The configuration binding source generator does not support 'BinderOptions.BindNonPublicProperties'."); } return binderOptions; @@ -132,5 +142,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration throw new InvalidOperationException($"Failed to convert configuration value at '{getPath()}' to type '{typeof(int)}'.", exception); } } + #endregion Core binding extensions. } } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Get_TypeOf_BinderOptions.net462.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Get_TypeOf_BinderOptions.net462.generated.txt index 8d1ee9ed3cd9a..91714c80cd013 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Get_TypeOf_BinderOptions.net462.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Get_TypeOf_BinderOptions.net462.generated.txt @@ -2,12 +2,19 @@ #nullable enable #pragma warning disable CS0612, CS0618 // Suppress warnings about [Obsolete] member usage in generated code. -/// Generated helper providing an AOT and linking compatible implementation for configuration binding. -[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")] -internal static class GeneratedConfigurationBinder +namespace System.Runtime.CompilerServices { - /// Attempts to bind the configuration instance to a new instance of type T. - public static object? Get(this global::Microsoft.Extensions.Configuration.IConfiguration configuration, global::System.Type type, global::System.Action? configureOptions) => global::Microsoft.Extensions.Configuration.Binder.SourceGeneration.CoreBindingHelper.GetCore(configuration, type, configureOptions); + using System; + using System.CodeDom.Compiler; + + [GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")] + [AttributeUsage(AttributeTargets.Method, AllowMultiple = true)] + file sealed class InterceptsLocationAttribute : Attribute + { + public InterceptsLocationAttribute(string filePath, int line, int column) + { + } + } } namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration @@ -17,11 +24,18 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration using System.CodeDom.Compiler; using System.Collections.Generic; using System.Globalization; + using System.Runtime.CompilerServices; - /// Provide core binding logic. [GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")] - file static class CoreBindingHelper + file static class BindingExtensions { + #region IConfiguration extensions. + /// Attempts to bind the configuration instance to a new instance of type T. + [InterceptsLocationAttribute(@"src-0.cs", 11, 20)] + public static object? Get(this IConfiguration configuration, Type type, Action? configureOptions) => GetCore(configuration, type, configureOptions); + #endregion IConfiguration extensions. + + #region Core binding extensions. private readonly static Lazy> s_configKeys_ProgramMyClass2 = new(() => new HashSet(StringComparer.OrdinalIgnoreCase) { "MyInt" }); public static object? GetCore(this IConfiguration configuration, Type type, Action? configureOptions) @@ -45,16 +59,11 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration return obj; } - throw new global::System.NotSupportedException($"Unable to bind to type '{type}': generator did not detect the type as input."); + throw new NotSupportedException($"Unable to bind to type '{type}': generator did not detect the type as input."); } public static void BindCore(IConfiguration configuration, ref Program.MyClass2 obj, BinderOptions? binderOptions) { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - ValidateConfigurationKeys(typeof(Program.MyClass2), s_configKeys_ProgramMyClass2, configuration, binderOptions); if (configuration["MyInt"] is string value1) @@ -63,6 +72,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration } } + /// If required by the binder options, validates that there are no unknown keys in the input configuration object. public static void ValidateConfigurationKeys(Type type, Lazy> keys, IConfiguration configuration, BinderOptions? binderOptions) { @@ -115,7 +125,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration if (binderOptions.BindNonPublicProperties) { - throw new global::System.NotSupportedException($"The configuration binding source generator does not support 'BinderOptions.BindNonPublicProperties'."); + throw new NotSupportedException($"The configuration binding source generator does not support 'BinderOptions.BindNonPublicProperties'."); } return binderOptions; @@ -132,5 +142,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration throw new InvalidOperationException($"Failed to convert configuration value at '{getPath()}' to type '{typeof(int)}'.", exception); } } + #endregion Core binding extensions. } } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/OptionsBuilder/BindConfiguration.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/OptionsBuilder/BindConfiguration.generated.txt index 37fad91482e8e..e0ad6e5305813 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/OptionsBuilder/BindConfiguration.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/OptionsBuilder/BindConfiguration.generated.txt @@ -36,27 +36,15 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration [InterceptsLocationAttribute(@"src-0.cs", 12, 24)] public static OptionsBuilder BindConfiguration(this OptionsBuilder optionsBuilder, string configSectionPath, Action? configureOptions = null) where TOptions : class { - if (optionsBuilder is null) - { - throw new ArgumentNullException(nameof(optionsBuilder)); - } + ArgumentNullException.ThrowIfNull(optionsBuilder); - if (configSectionPath is null) - { - throw new ArgumentNullException(nameof(configSectionPath)); - } + ArgumentNullException.ThrowIfNull(configSectionPath); optionsBuilder.Configure((obj, configuration) => { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } + ArgumentNullException.ThrowIfNull(obj); - if (configuration is null) - { - throw new ArgumentNullException(nameof(configuration)); - } + ArgumentNullException.ThrowIfNull(configuration); IConfiguration section = string.Equals(string.Empty, configSectionPath, StringComparison.OrdinalIgnoreCase) ? configuration : configuration.GetSection(configSectionPath); BindCoreMain(section, obj, typeof(TOptions), configureOptions); @@ -74,10 +62,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration { ArgumentNullException.ThrowIfNull(configuration); - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } + ArgumentNullException.ThrowIfNull(obj); if (!HasValueOrChildren(configuration)) { diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/OptionsBuilder/BindConfiguration.net462.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/OptionsBuilder/BindConfiguration.net462.generated.txt index a74dbfdd04b5b..88b35037c22c3 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/OptionsBuilder/BindConfiguration.net462.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/OptionsBuilder/BindConfiguration.net462.generated.txt @@ -2,31 +2,18 @@ #nullable enable #pragma warning disable CS0612, CS0618 // Suppress warnings about [Obsolete] member usage in generated code. -/// Generated helper providing an AOT and linking compatible implementation for configuration binding. -[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")] -internal static class GeneratedOptionsBuilderBinder +namespace System.Runtime.CompilerServices { - /// Registers the dependency injection container to bind against the obtained from the DI service provider. - public static global::Microsoft.Extensions.Options.OptionsBuilder BindConfiguration(this global::Microsoft.Extensions.Options.OptionsBuilder optionsBuilder, string configSectionPath, global::System.Action? configureOptions = null) where TOptions : class - { - if (optionsBuilder is null) - { - throw new global::System.ArgumentNullException(nameof(optionsBuilder)); - } + using System; + using System.CodeDom.Compiler; - if (configSectionPath is null) + [GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")] + [AttributeUsage(AttributeTargets.Method, AllowMultiple = true)] + file sealed class InterceptsLocationAttribute : Attribute + { + public InterceptsLocationAttribute(string filePath, int line, int column) { - throw new global::System.ArgumentNullException(nameof(configSectionPath)); } - - optionsBuilder.Configure((obj, configuration) => - { - global::Microsoft.Extensions.Configuration.IConfiguration section = string.Equals(string.Empty, configSectionPath, global::System.StringComparison.OrdinalIgnoreCase) ? configuration : configuration.GetSection(configSectionPath); - global::Microsoft.Extensions.Configuration.Binder.SourceGeneration.CoreBindingHelper.BindCoreUntyped(section, obj, typeof(TOptions), configureOptions); - }); - - global::Microsoft.Extensions.DependencyInjection.ServiceCollectionServiceExtensions.AddSingleton, global::Microsoft.Extensions.Options.ConfigurationChangeTokenSource>(optionsBuilder.Services); - return optionsBuilder; } } @@ -34,31 +21,74 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration { using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; + using Microsoft.Extensions.Options; using System; using System.CodeDom.Compiler; using System.Collections.Generic; using System.Globalization; + using System.Runtime.CompilerServices; - /// Provide core binding logic. [GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")] - file static class CoreBindingHelper + file static class BindingExtensions { + #region OptionsBuilder extensions. + /// Registers the dependency injection container to bind against the obtained from the DI service provider. + [InterceptsLocationAttribute(@"src-0.cs", 12, 24)] + public static OptionsBuilder BindConfiguration(this OptionsBuilder optionsBuilder, string configSectionPath, Action? configureOptions = null) where TOptions : class + { + if (optionsBuilder is null) + { + throw new ArgumentNullException(nameof(optionsBuilder)); + } + + if (configSectionPath is null) + { + throw new ArgumentNullException(nameof(configSectionPath)); + } + + optionsBuilder.Configure((obj, configuration) => + { + if (obj is null) + { + throw new ArgumentNullException(nameof(obj)); + } + + if (configuration is null) + { + throw new ArgumentNullException(nameof(configuration)); + } + + IConfiguration section = string.Equals(string.Empty, configSectionPath, StringComparison.OrdinalIgnoreCase) ? configuration : configuration.GetSection(configSectionPath); + BindCoreMain(section, obj, typeof(TOptions), configureOptions); + }); + + optionsBuilder.Services.AddSingleton, ConfigurationChangeTokenSource>(); + return optionsBuilder; + } + #endregion OptionsBuilder extensions. + + #region Core binding extensions. private readonly static Lazy> s_configKeys_ProgramMyClass = new(() => new HashSet(StringComparer.OrdinalIgnoreCase) { "MyString", "MyInt", "MyList" }); - public static void BindCoreUntyped(this IConfiguration configuration, object obj, Type type, Action? configureOptions) + public static void BindCoreMain(IConfiguration configuration, object obj, Type type, Action? configureOptions) { if (configuration is null) { throw new ArgumentNullException(nameof(configuration)); } - BinderOptions? binderOptions = GetBinderOptions(configureOptions); + if (obj is null) + { + throw new ArgumentNullException(nameof(obj)); + } if (!HasValueOrChildren(configuration)) { return; } + BinderOptions? binderOptions = GetBinderOptions(configureOptions); + if (type == typeof(Program.MyClass)) { var temp = (Program.MyClass)obj; @@ -66,16 +96,11 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration return; } - throw new global::System.NotSupportedException($"Unable to bind to type '{type}': generator did not detect the type as input."); + throw new NotSupportedException($"Unable to bind to type '{type}': generator did not detect the type as input."); } public static void BindCore(IConfiguration configuration, ref List obj, BinderOptions? binderOptions) { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - foreach (IConfigurationSection section in configuration.GetChildren()) { if (section.Value is string value) @@ -87,11 +112,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration public static void BindCore(IConfiguration configuration, ref Program.MyClass obj, BinderOptions? binderOptions) { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - ValidateConfigurationKeys(typeof(Program.MyClass), s_configKeys_ProgramMyClass, configuration, binderOptions); obj.MyString = configuration["MyString"]!; @@ -110,6 +130,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration } } + /// If required by the binder options, validates that there are no unknown keys in the input configuration object. public static void ValidateConfigurationKeys(Type type, Lazy> keys, IConfiguration configuration, BinderOptions? binderOptions) { @@ -162,7 +183,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration if (binderOptions.BindNonPublicProperties) { - throw new global::System.NotSupportedException($"The configuration binding source generator does not support 'BinderOptions.BindNonPublicProperties'."); + throw new NotSupportedException($"The configuration binding source generator does not support 'BinderOptions.BindNonPublicProperties'."); } return binderOptions; @@ -179,5 +200,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration throw new InvalidOperationException($"Failed to convert configuration value at '{getPath()}' to type '{typeof(int)}'.", exception); } } + #endregion Core binding extensions. } } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/OptionsBuilder/Bind_T.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/OptionsBuilder/Bind_T.generated.txt index b948dbfd180cb..a1affe087a41b 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/OptionsBuilder/Bind_T.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/OptionsBuilder/Bind_T.generated.txt @@ -54,6 +54,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration public static IServiceCollection Configure(this IServiceCollection services, string? name, IConfiguration configuration, Action? configureOptions) where TOptions : class { ArgumentNullException.ThrowIfNull(services); + ArgumentNullException.ThrowIfNull(configuration); OptionsServiceCollectionExtensions.AddOptions(services); @@ -69,10 +70,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration { ArgumentNullException.ThrowIfNull(configuration); - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } + ArgumentNullException.ThrowIfNull(obj); if (!HasValueOrChildren(configuration)) { diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/OptionsBuilder/Bind_T.net462.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/OptionsBuilder/Bind_T.net462.generated.txt index ac53b58f24da2..633196e7a742d 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/OptionsBuilder/Bind_T.net462.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/OptionsBuilder/Bind_T.net462.generated.txt @@ -2,49 +2,18 @@ #nullable enable #pragma warning disable CS0612, CS0618 // Suppress warnings about [Obsolete] member usage in generated code. -/// Generated helper providing an AOT and linking compatible implementation for configuration binding. -[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")] -internal static class GeneratedOptionsBuilderBinder +namespace System.Runtime.CompilerServices { - /// Registers a configuration instance which will bind against. - public static global::Microsoft.Extensions.Options.OptionsBuilder Bind(this global::Microsoft.Extensions.Options.OptionsBuilder optionsBuilder, global::Microsoft.Extensions.Configuration.IConfiguration configuration) where TOptions : class - { - return global::GeneratedOptionsBuilderBinder.Bind(optionsBuilder, configuration, configureOptions: null); - } - - /// Registers a configuration instance which will bind against. - public static global::Microsoft.Extensions.Options.OptionsBuilder Bind(this global::Microsoft.Extensions.Options.OptionsBuilder optionsBuilder, global::Microsoft.Extensions.Configuration.IConfiguration configuration, global::System.Action? configureOptions) where TOptions : class - { - if (optionsBuilder is null) - { - throw new global::System.ArgumentNullException(nameof(optionsBuilder)); - } - - global::GeneratedServiceCollectionBinder.Configure(optionsBuilder.Services, optionsBuilder.Name, configuration, configureOptions); - return optionsBuilder; - } -} + using System; + using System.CodeDom.Compiler; -/// Generated helper providing an AOT and linking compatible implementation for configuration binding. -[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")] -internal static class GeneratedServiceCollectionBinder -{ - /// Registers a configuration instance which TOptions will bind against. - public static global::Microsoft.Extensions.DependencyInjection.IServiceCollection Configure(this global::Microsoft.Extensions.DependencyInjection.IServiceCollection services, string? name, global::Microsoft.Extensions.Configuration.IConfiguration configuration, global::System.Action? configureOptions) where TOptions : class + [GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")] + [AttributeUsage(AttributeTargets.Method, AllowMultiple = true)] + file sealed class InterceptsLocationAttribute : Attribute { - if (services is null) - { - throw new global::System.ArgumentNullException(nameof(services)); - } - - if (configuration is null) + public InterceptsLocationAttribute(string filePath, int line, int column) { - throw new global::System.ArgumentNullException(nameof(configuration)); } - - global::Microsoft.Extensions.DependencyInjection.OptionsServiceCollectionExtensions.AddOptions(services); - global::Microsoft.Extensions.DependencyInjection.ServiceCollectionServiceExtensions.AddSingleton>(services, new global::Microsoft.Extensions.Options.ConfigurationChangeTokenSource(name, configuration)); - return global::Microsoft.Extensions.DependencyInjection.ServiceCollectionServiceExtensions.AddSingleton>(services, new global::Microsoft.Extensions.Options.ConfigureNamedOptions(name, obj => global::Microsoft.Extensions.Configuration.Binder.SourceGeneration.CoreBindingHelper.BindCoreUntyped(configuration, obj, typeof(TOptions), configureOptions))); } } @@ -52,31 +21,79 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration { using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; + using Microsoft.Extensions.Options; using System; using System.CodeDom.Compiler; using System.Collections.Generic; using System.Globalization; + using System.Runtime.CompilerServices; - /// Provide core binding logic. [GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")] - file static class CoreBindingHelper + file static class BindingExtensions { + #region OptionsBuilder extensions. + /// Registers a configuration instance which will bind against. + [InterceptsLocationAttribute(@"src-0.cs", 15, 24)] + public static OptionsBuilder Bind(this OptionsBuilder optionsBuilder, IConfiguration configuration) where TOptions : class + { + return Bind(optionsBuilder, configuration, configureOptions: null); + } + + /// Registers a configuration instance which will bind against. + public static OptionsBuilder Bind(this OptionsBuilder optionsBuilder, IConfiguration configuration, Action? configureOptions) where TOptions : class + { + if (optionsBuilder is null) + { + throw new ArgumentNullException(nameof(optionsBuilder)); + } + + Configure(optionsBuilder.Services, optionsBuilder.Name, configuration, configureOptions); + return optionsBuilder; + } + #endregion OptionsBuilder extensions. + + #region IServiceCollection extensions. + /// Registers a configuration instance which TOptions will bind against. + public static IServiceCollection Configure(this IServiceCollection services, string? name, IConfiguration configuration, Action? configureOptions) where TOptions : class + { + if (services is null) + { + throw new ArgumentNullException(nameof(services)); + } + + if (configuration is null) + { + throw new ArgumentNullException(nameof(configuration)); + } + + OptionsServiceCollectionExtensions.AddOptions(services); + services.AddSingleton>(new ConfigurationChangeTokenSource(name, configuration)); + return services.AddSingleton>(new Microsoft.Extensions.Options.ConfigureNamedOptions(name, obj => BindCoreMain(configuration, obj, typeof(TOptions)configureOptions))); + } + #endregion IServiceCollection extensions. + + #region Core binding extensions. private readonly static Lazy> s_configKeys_ProgramMyClass = new(() => new HashSet(StringComparer.OrdinalIgnoreCase) { "MyString", "MyInt", "MyList" }); - public static void BindCoreUntyped(this IConfiguration configuration, object obj, Type type, Action? configureOptions) + public static void BindCoreMain(IConfiguration configuration, object obj, Type type, Action? configureOptions) { if (configuration is null) { throw new ArgumentNullException(nameof(configuration)); } - BinderOptions? binderOptions = GetBinderOptions(configureOptions); + if (obj is null) + { + throw new ArgumentNullException(nameof(obj)); + } if (!HasValueOrChildren(configuration)) { return; } + BinderOptions? binderOptions = GetBinderOptions(configureOptions); + if (type == typeof(Program.MyClass)) { var temp = (Program.MyClass)obj; @@ -84,16 +101,11 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration return; } - throw new global::System.NotSupportedException($"Unable to bind to type '{type}': generator did not detect the type as input."); + throw new NotSupportedException($"Unable to bind to type '{type}': generator did not detect the type as input."); } public static void BindCore(IConfiguration configuration, ref List obj, BinderOptions? binderOptions) { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - foreach (IConfigurationSection section in configuration.GetChildren()) { if (section.Value is string value) @@ -105,11 +117,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration public static void BindCore(IConfiguration configuration, ref Program.MyClass obj, BinderOptions? binderOptions) { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - ValidateConfigurationKeys(typeof(Program.MyClass), s_configKeys_ProgramMyClass, configuration, binderOptions); obj.MyString = configuration["MyString"]!; @@ -128,6 +135,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration } } + /// If required by the binder options, validates that there are no unknown keys in the input configuration object. public static void ValidateConfigurationKeys(Type type, Lazy> keys, IConfiguration configuration, BinderOptions? binderOptions) { @@ -180,7 +188,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration if (binderOptions.BindNonPublicProperties) { - throw new global::System.NotSupportedException($"The configuration binding source generator does not support 'BinderOptions.BindNonPublicProperties'."); + throw new NotSupportedException($"The configuration binding source generator does not support 'BinderOptions.BindNonPublicProperties'."); } return binderOptions; @@ -197,5 +205,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration throw new InvalidOperationException($"Failed to convert configuration value at '{getPath()}' to type '{typeof(int)}'.", exception); } } + #endregion Core binding extensions. } } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/OptionsBuilder/Bind_T_BinderOptions.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/OptionsBuilder/Bind_T_BinderOptions.generated.txt index e6ae7533798a3..87ac14b5b79b8 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/OptionsBuilder/Bind_T_BinderOptions.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/OptionsBuilder/Bind_T_BinderOptions.generated.txt @@ -48,6 +48,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration public static IServiceCollection Configure(this IServiceCollection services, string? name, IConfiguration configuration, Action? configureOptions) where TOptions : class { ArgumentNullException.ThrowIfNull(services); + ArgumentNullException.ThrowIfNull(configuration); OptionsServiceCollectionExtensions.AddOptions(services); @@ -63,10 +64,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration { ArgumentNullException.ThrowIfNull(configuration); - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } + ArgumentNullException.ThrowIfNull(obj); if (!HasValueOrChildren(configuration)) { diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/OptionsBuilder/Bind_T_BinderOptions.net462.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/OptionsBuilder/Bind_T_BinderOptions.net462.generated.txt index fd3ec70a8a328..fb5b4b4ad721d 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/OptionsBuilder/Bind_T_BinderOptions.net462.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/OptionsBuilder/Bind_T_BinderOptions.net462.generated.txt @@ -2,43 +2,18 @@ #nullable enable #pragma warning disable CS0612, CS0618 // Suppress warnings about [Obsolete] member usage in generated code. -/// Generated helper providing an AOT and linking compatible implementation for configuration binding. -[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")] -internal static class GeneratedOptionsBuilderBinder +namespace System.Runtime.CompilerServices { - /// Registers a configuration instance which will bind against. - public static global::Microsoft.Extensions.Options.OptionsBuilder Bind(this global::Microsoft.Extensions.Options.OptionsBuilder optionsBuilder, global::Microsoft.Extensions.Configuration.IConfiguration configuration, global::System.Action? configureOptions) where TOptions : class - { - if (optionsBuilder is null) - { - throw new global::System.ArgumentNullException(nameof(optionsBuilder)); - } - - global::GeneratedServiceCollectionBinder.Configure(optionsBuilder.Services, optionsBuilder.Name, configuration, configureOptions); - return optionsBuilder; - } -} + using System; + using System.CodeDom.Compiler; -/// Generated helper providing an AOT and linking compatible implementation for configuration binding. -[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")] -internal static class GeneratedServiceCollectionBinder -{ - /// Registers a configuration instance which TOptions will bind against. - public static global::Microsoft.Extensions.DependencyInjection.IServiceCollection Configure(this global::Microsoft.Extensions.DependencyInjection.IServiceCollection services, string? name, global::Microsoft.Extensions.Configuration.IConfiguration configuration, global::System.Action? configureOptions) where TOptions : class + [GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")] + [AttributeUsage(AttributeTargets.Method, AllowMultiple = true)] + file sealed class InterceptsLocationAttribute : Attribute { - if (services is null) - { - throw new global::System.ArgumentNullException(nameof(services)); - } - - if (configuration is null) + public InterceptsLocationAttribute(string filePath, int line, int column) { - throw new global::System.ArgumentNullException(nameof(configuration)); } - - global::Microsoft.Extensions.DependencyInjection.OptionsServiceCollectionExtensions.AddOptions(services); - global::Microsoft.Extensions.DependencyInjection.ServiceCollectionServiceExtensions.AddSingleton>(services, new global::Microsoft.Extensions.Options.ConfigurationChangeTokenSource(name, configuration)); - return global::Microsoft.Extensions.DependencyInjection.ServiceCollectionServiceExtensions.AddSingleton>(services, new global::Microsoft.Extensions.Options.ConfigureNamedOptions(name, obj => global::Microsoft.Extensions.Configuration.Binder.SourceGeneration.CoreBindingHelper.BindCoreUntyped(configuration, obj, typeof(TOptions), configureOptions))); } } @@ -46,31 +21,73 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration { using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; + using Microsoft.Extensions.Options; using System; using System.CodeDom.Compiler; using System.Collections.Generic; using System.Globalization; + using System.Runtime.CompilerServices; - /// Provide core binding logic. [GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")] - file static class CoreBindingHelper + file static class BindingExtensions { + #region OptionsBuilder extensions. + /// Registers a configuration instance which will bind against. + [InterceptsLocationAttribute(@"src-0.cs", 15, 24)] + public static OptionsBuilder Bind(this OptionsBuilder optionsBuilder, IConfiguration configuration, Action? configureOptions) where TOptions : class + { + if (optionsBuilder is null) + { + throw new ArgumentNullException(nameof(optionsBuilder)); + } + + Configure(optionsBuilder.Services, optionsBuilder.Name, configuration, configureOptions); + return optionsBuilder; + } + #endregion OptionsBuilder extensions. + + #region IServiceCollection extensions. + /// Registers a configuration instance which TOptions will bind against. + public static IServiceCollection Configure(this IServiceCollection services, string? name, IConfiguration configuration, Action? configureOptions) where TOptions : class + { + if (services is null) + { + throw new ArgumentNullException(nameof(services)); + } + + if (configuration is null) + { + throw new ArgumentNullException(nameof(configuration)); + } + + OptionsServiceCollectionExtensions.AddOptions(services); + services.AddSingleton>(new ConfigurationChangeTokenSource(name, configuration)); + return services.AddSingleton>(new Microsoft.Extensions.Options.ConfigureNamedOptions(name, obj => BindCoreMain(configuration, obj, typeof(TOptions)configureOptions))); + } + #endregion IServiceCollection extensions. + + #region Core binding extensions. private readonly static Lazy> s_configKeys_ProgramMyClass = new(() => new HashSet(StringComparer.OrdinalIgnoreCase) { "MyString", "MyInt", "MyList" }); - public static void BindCoreUntyped(this IConfiguration configuration, object obj, Type type, Action? configureOptions) + public static void BindCoreMain(IConfiguration configuration, object obj, Type type, Action? configureOptions) { if (configuration is null) { throw new ArgumentNullException(nameof(configuration)); } - BinderOptions? binderOptions = GetBinderOptions(configureOptions); + if (obj is null) + { + throw new ArgumentNullException(nameof(obj)); + } if (!HasValueOrChildren(configuration)) { return; } + BinderOptions? binderOptions = GetBinderOptions(configureOptions); + if (type == typeof(Program.MyClass)) { var temp = (Program.MyClass)obj; @@ -78,16 +95,11 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration return; } - throw new global::System.NotSupportedException($"Unable to bind to type '{type}': generator did not detect the type as input."); + throw new NotSupportedException($"Unable to bind to type '{type}': generator did not detect the type as input."); } public static void BindCore(IConfiguration configuration, ref List obj, BinderOptions? binderOptions) { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - foreach (IConfigurationSection section in configuration.GetChildren()) { if (section.Value is string value) @@ -99,11 +111,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration public static void BindCore(IConfiguration configuration, ref Program.MyClass obj, BinderOptions? binderOptions) { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - ValidateConfigurationKeys(typeof(Program.MyClass), s_configKeys_ProgramMyClass, configuration, binderOptions); obj.MyString = configuration["MyString"]!; @@ -122,6 +129,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration } } + /// If required by the binder options, validates that there are no unknown keys in the input configuration object. public static void ValidateConfigurationKeys(Type type, Lazy> keys, IConfiguration configuration, BinderOptions? binderOptions) { @@ -174,7 +182,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration if (binderOptions.BindNonPublicProperties) { - throw new global::System.NotSupportedException($"The configuration binding source generator does not support 'BinderOptions.BindNonPublicProperties'."); + throw new NotSupportedException($"The configuration binding source generator does not support 'BinderOptions.BindNonPublicProperties'."); } return binderOptions; @@ -191,5 +199,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration throw new InvalidOperationException($"Failed to convert configuration value at '{getPath()}' to type '{typeof(int)}'.", exception); } } + #endregion Core binding extensions. } } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/Primitives.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/Primitives.generated.txt index 2a5a6e73b2b45..d83a3a7c71aed 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/Primitives.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/Primitives.generated.txt @@ -35,6 +35,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration public static void Bind_ProgramMyClass(this IConfiguration configuration, object? obj) { ArgumentNullException.ThrowIfNull(configuration); + ArgumentNullException.ThrowIfNull(obj); var typedObj = (Program.MyClass)obj; diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/Primitives.net462.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/Primitives.net462.generated.txt index 159afe5f18273..14472df49c479 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/Primitives.net462.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/Primitives.net462.generated.txt @@ -2,12 +2,19 @@ #nullable enable #pragma warning disable CS0612, CS0618 // Suppress warnings about [Obsolete] member usage in generated code. -/// Generated helper providing an AOT and linking compatible implementation for configuration binding. -[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")] -internal static class GeneratedConfigurationBinder +namespace System.Runtime.CompilerServices { - /// Attempts to bind the given object instance to configuration values by matching property names against configuration keys recursively. - public static void Bind(this global::Microsoft.Extensions.Configuration.IConfiguration configuration, global::Program.MyClass obj) => global::Microsoft.Extensions.Configuration.Binder.SourceGeneration.CoreBindingHelper.BindCore(configuration, ref obj, binderOptions: null); + using System; + using System.CodeDom.Compiler; + + [GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")] + [AttributeUsage(AttributeTargets.Method, AllowMultiple = true)] + file sealed class InterceptsLocationAttribute : Attribute + { + public InterceptsLocationAttribute(string filePath, int line, int column) + { + } + } } namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration @@ -17,20 +24,36 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration using System.CodeDom.Compiler; using System.Collections.Generic; using System.Globalization; + using System.Runtime.CompilerServices; - /// Provide core binding logic. [GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")] - file static class CoreBindingHelper + file static class BindingExtensions { - private readonly static Lazy> s_configKeys_ProgramMyClass = new(() => new HashSet(StringComparer.OrdinalIgnoreCase) { "Prop0", "Prop1", "Prop2", "Prop3", "Prop4", "Prop5", "Prop6", "Prop8", "Prop9", "Prop10", "Prop13", "Prop14", "Prop15", "Prop16", "Prop17", "Prop19", "Prop20", "Prop21", "Prop23", "Prop24", "Prop25", "Prop26", "Prop27", "Prop7", "Prop11", "Prop12", "Prop18", "Prop22" }); - - public static void BindCore(IConfiguration configuration, ref Program.MyClass obj, BinderOptions? binderOptions) + #region IConfiguration extensions. + /// Attempts to bind the given object instance to configuration values by matching property names against configuration keys recursively. + [InterceptsLocationAttribute(@"src-0.cs", 13, 16)] + public static void Bind_ProgramMyClass(this IConfiguration configuration, object? obj) { + if (configuration is null) + { + throw new ArgumentNullException(nameof(configuration)); + } + if (obj is null) { throw new ArgumentNullException(nameof(obj)); } + var typedObj = (Program.MyClass)obj; + BindCore(configuration, ref typedObj, binderOptions: null); + } + #endregion IConfiguration extensions. + + #region Core binding extensions. + private readonly static Lazy> s_configKeys_ProgramMyClass = new(() => new HashSet(StringComparer.OrdinalIgnoreCase) { "Prop0", "Prop1", "Prop2", "Prop3", "Prop4", "Prop5", "Prop6", "Prop8", "Prop9", "Prop10", "Prop13", "Prop14", "Prop15", "Prop16", "Prop17", "Prop19", "Prop20", "Prop21", "Prop23", "Prop24", "Prop25", "Prop26", "Prop27", "Prop7", "Prop11", "Prop12", "Prop18", "Prop22" }); + + public static void BindCore(IConfiguration configuration, ref Program.MyClass obj, BinderOptions? binderOptions) + { ValidateConfigurationKeys(typeof(Program.MyClass), s_configKeys_ProgramMyClass, configuration, binderOptions); if (configuration["Prop0"] is string value0) @@ -168,6 +191,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration } } + /// If required by the binder options, validates that there are no unknown keys in the input configuration object. public static void ValidateConfigurationKeys(Type type, Lazy> keys, IConfiguration configuration, BinderOptions? binderOptions) { @@ -513,5 +537,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration throw new InvalidOperationException($"Failed to convert configuration value at '{getPath()}' to type '{typeof(byte[])}'.", exception); } } + #endregion Core binding extensions. } } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ServiceCollection/Configure_T.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ServiceCollection/Configure_T.generated.txt index d2aef5a52551d..d76bec8b028e5 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ServiceCollection/Configure_T.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ServiceCollection/Configure_T.generated.txt @@ -41,15 +41,9 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration /// Registers a configuration instance which TOptions will bind against. public static IServiceCollection Configure(this IServiceCollection services, string? name, IConfiguration configuration, Action? configureOptions) where TOptions : class { - if (services is null) - { - throw new ArgumentNullException(nameof(services)); - } + ArgumentNullException.ThrowIfNull(services); - if (configuration is null) - { - throw new ArgumentNullException(nameof(configuration)); - } + ArgumentNullException.ThrowIfNull(configuration); OptionsServiceCollectionExtensions.AddOptions(services); services.AddSingleton>(new ConfigurationChangeTokenSource(name, configuration)); @@ -65,10 +59,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration { ArgumentNullException.ThrowIfNull(configuration); - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } + ArgumentNullException.ThrowIfNull(obj); if (!HasValueOrChildren(configuration)) { diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ServiceCollection/Configure_T.net462.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ServiceCollection/Configure_T.net462.generated.txt index 461f6050e2fdf..7f626f0e27c52 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ServiceCollection/Configure_T.net462.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ServiceCollection/Configure_T.net462.generated.txt @@ -2,64 +2,84 @@ #nullable enable #pragma warning disable CS0612, CS0618 // Suppress warnings about [Obsolete] member usage in generated code. -/// Generated helper providing an AOT and linking compatible implementation for configuration binding. -[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")] -internal static class GeneratedServiceCollectionBinder +namespace System.Runtime.CompilerServices { - /// Registers a configuration instance which TOptions will bind against. - public static global::Microsoft.Extensions.DependencyInjection.IServiceCollection Configure(this global::Microsoft.Extensions.DependencyInjection.IServiceCollection services, global::Microsoft.Extensions.Configuration.IConfiguration configuration) where TOptions : class - { - return global::GeneratedServiceCollectionBinder.Configure(services, string.Empty, configuration, configureOptions: null); - } + using System; + using System.CodeDom.Compiler; - /// Registers a configuration instance which TOptions will bind against. - public static global::Microsoft.Extensions.DependencyInjection.IServiceCollection Configure(this global::Microsoft.Extensions.DependencyInjection.IServiceCollection services, string? name, global::Microsoft.Extensions.Configuration.IConfiguration configuration, global::System.Action? configureOptions) where TOptions : class + [GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")] + [AttributeUsage(AttributeTargets.Method, AllowMultiple = true)] + file sealed class InterceptsLocationAttribute : Attribute { - if (services is null) - { - throw new global::System.ArgumentNullException(nameof(services)); - } - - if (configuration is null) + public InterceptsLocationAttribute(string filePath, int line, int column) { - throw new global::System.ArgumentNullException(nameof(configuration)); } - - global::Microsoft.Extensions.DependencyInjection.OptionsServiceCollectionExtensions.AddOptions(services); - global::Microsoft.Extensions.DependencyInjection.ServiceCollectionServiceExtensions.AddSingleton>(services, new global::Microsoft.Extensions.Options.ConfigurationChangeTokenSource(name, configuration)); - return global::Microsoft.Extensions.DependencyInjection.ServiceCollectionServiceExtensions.AddSingleton>(services, new global::Microsoft.Extensions.Options.ConfigureNamedOptions(name, obj => global::Microsoft.Extensions.Configuration.Binder.SourceGeneration.CoreBindingHelper.BindCoreUntyped(configuration, obj, typeof(TOptions), configureOptions))); } } namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration { using Microsoft.Extensions.Configuration; + using Microsoft.Extensions.DependencyInjection; using System; using System.CodeDom.Compiler; using System.Collections.Generic; using System.Globalization; + using System.Runtime.CompilerServices; - /// Provide core binding logic. [GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")] - file static class CoreBindingHelper + file static class BindingExtensions { + #region IServiceCollection extensions. + /// Registers a configuration instance which TOptions will bind against. + [InterceptsLocationAttribute(@"src-0.cs", 14, 18)] + public static IServiceCollection Configure(this IServiceCollection services, IConfiguration configuration) where TOptions : class + { + return Configure(services, string.Empty, configuration, configureOptions: null); + } + + /// Registers a configuration instance which TOptions will bind against. + public static IServiceCollection Configure(this IServiceCollection services, string? name, IConfiguration configuration, Action? configureOptions) where TOptions : class + { + if (services is null) + { + throw new ArgumentNullException(nameof(services)); + } + + if (configuration is null) + { + throw new ArgumentNullException(nameof(configuration)); + } + + OptionsServiceCollectionExtensions.AddOptions(services); + services.AddSingleton>(new ConfigurationChangeTokenSource(name, configuration)); + return services.AddSingleton>(new Microsoft.Extensions.Options.ConfigureNamedOptions(name, obj => BindCoreMain(configuration, obj, typeof(TOptions)configureOptions))); + } + #endregion IServiceCollection extensions. + + #region Core binding extensions. private readonly static Lazy> s_configKeys_ProgramMyClass2 = new(() => new HashSet(StringComparer.OrdinalIgnoreCase) { "MyInt" }); private readonly static Lazy> s_configKeys_ProgramMyClass = new(() => new HashSet(StringComparer.OrdinalIgnoreCase) { "MyString", "MyInt", "MyList", "MyList2", "MyDictionary" }); - public static void BindCoreUntyped(this IConfiguration configuration, object obj, Type type, Action? configureOptions) + public static void BindCoreMain(IConfiguration configuration, object obj, Type type, Action? configureOptions) { if (configuration is null) { throw new ArgumentNullException(nameof(configuration)); } - BinderOptions? binderOptions = GetBinderOptions(configureOptions); + if (obj is null) + { + throw new ArgumentNullException(nameof(obj)); + } if (!HasValueOrChildren(configuration)) { return; } + BinderOptions? binderOptions = GetBinderOptions(configureOptions); + if (type == typeof(Program.MyClass)) { var temp = (Program.MyClass)obj; @@ -67,16 +87,11 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration return; } - throw new global::System.NotSupportedException($"Unable to bind to type '{type}': generator did not detect the type as input."); + throw new NotSupportedException($"Unable to bind to type '{type}': generator did not detect the type as input."); } public static void BindCore(IConfiguration configuration, ref List obj, BinderOptions? binderOptions) { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - foreach (IConfigurationSection section in configuration.GetChildren()) { if (section.Value is string value) @@ -88,11 +103,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration public static void BindCore(IConfiguration configuration, ref Program.MyClass2 obj, BinderOptions? binderOptions) { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - ValidateConfigurationKeys(typeof(Program.MyClass2), s_configKeys_ProgramMyClass2, configuration, binderOptions); if (configuration["MyInt"] is string value1) @@ -103,11 +113,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration public static void BindCore(IConfiguration configuration, ref List obj, BinderOptions? binderOptions) { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - foreach (IConfigurationSection section in configuration.GetChildren()) { var value = new Program.MyClass2(); @@ -118,11 +123,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration public static void BindCore(IConfiguration configuration, ref Dictionary obj, BinderOptions? binderOptions) { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - foreach (IConfigurationSection section in configuration.GetChildren()) { if (section.Value is string value) @@ -134,11 +134,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration public static void BindCore(IConfiguration configuration, ref Program.MyClass obj, BinderOptions? binderOptions) { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - ValidateConfigurationKeys(typeof(Program.MyClass), s_configKeys_ProgramMyClass, configuration, binderOptions); obj.MyString = configuration["MyString"]!; @@ -173,6 +168,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration } } + /// If required by the binder options, validates that there are no unknown keys in the input configuration object. public static void ValidateConfigurationKeys(Type type, Lazy> keys, IConfiguration configuration, BinderOptions? binderOptions) { @@ -225,7 +221,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration if (binderOptions.BindNonPublicProperties) { - throw new global::System.NotSupportedException($"The configuration binding source generator does not support 'BinderOptions.BindNonPublicProperties'."); + throw new NotSupportedException($"The configuration binding source generator does not support 'BinderOptions.BindNonPublicProperties'."); } return binderOptions; @@ -242,5 +238,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration throw new InvalidOperationException($"Failed to convert configuration value at '{getPath()}' to type '{typeof(int)}'.", exception); } } + #endregion Core binding extensions. } } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ServiceCollection/Configure_T_BinderOptions.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ServiceCollection/Configure_T_BinderOptions.generated.txt index ee47c7a9f5e67..5db96a8d37734 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ServiceCollection/Configure_T_BinderOptions.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ServiceCollection/Configure_T_BinderOptions.generated.txt @@ -41,15 +41,9 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration /// Registers a configuration instance which TOptions will bind against. public static IServiceCollection Configure(this IServiceCollection services, string? name, IConfiguration configuration, Action? configureOptions) where TOptions : class { - if (services is null) - { - throw new ArgumentNullException(nameof(services)); - } + ArgumentNullException.ThrowIfNull(services); - if (configuration is null) - { - throw new ArgumentNullException(nameof(configuration)); - } + ArgumentNullException.ThrowIfNull(configuration); OptionsServiceCollectionExtensions.AddOptions(services); services.AddSingleton>(new ConfigurationChangeTokenSource(name, configuration)); @@ -65,10 +59,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration { ArgumentNullException.ThrowIfNull(configuration); - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } + ArgumentNullException.ThrowIfNull(obj); if (!HasValueOrChildren(configuration)) { diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ServiceCollection/Configure_T_BinderOptions.net462.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ServiceCollection/Configure_T_BinderOptions.net462.generated.txt index a57f652720bc8..5848c2412f9b7 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ServiceCollection/Configure_T_BinderOptions.net462.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ServiceCollection/Configure_T_BinderOptions.net462.generated.txt @@ -2,64 +2,84 @@ #nullable enable #pragma warning disable CS0612, CS0618 // Suppress warnings about [Obsolete] member usage in generated code. -/// Generated helper providing an AOT and linking compatible implementation for configuration binding. -[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")] -internal static class GeneratedServiceCollectionBinder +namespace System.Runtime.CompilerServices { - /// Registers a configuration instance which TOptions will bind against. - public static global::Microsoft.Extensions.DependencyInjection.IServiceCollection Configure(this global::Microsoft.Extensions.DependencyInjection.IServiceCollection services, global::Microsoft.Extensions.Configuration.IConfiguration configuration, global::System.Action? configureOptions) where TOptions : class - { - return global::GeneratedServiceCollectionBinder.Configure(services, string.Empty, configuration, configureOptions); - } + using System; + using System.CodeDom.Compiler; - /// Registers a configuration instance which TOptions will bind against. - public static global::Microsoft.Extensions.DependencyInjection.IServiceCollection Configure(this global::Microsoft.Extensions.DependencyInjection.IServiceCollection services, string? name, global::Microsoft.Extensions.Configuration.IConfiguration configuration, global::System.Action? configureOptions) where TOptions : class + [GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")] + [AttributeUsage(AttributeTargets.Method, AllowMultiple = true)] + file sealed class InterceptsLocationAttribute : Attribute { - if (services is null) - { - throw new global::System.ArgumentNullException(nameof(services)); - } - - if (configuration is null) + public InterceptsLocationAttribute(string filePath, int line, int column) { - throw new global::System.ArgumentNullException(nameof(configuration)); } - - global::Microsoft.Extensions.DependencyInjection.OptionsServiceCollectionExtensions.AddOptions(services); - global::Microsoft.Extensions.DependencyInjection.ServiceCollectionServiceExtensions.AddSingleton>(services, new global::Microsoft.Extensions.Options.ConfigurationChangeTokenSource(name, configuration)); - return global::Microsoft.Extensions.DependencyInjection.ServiceCollectionServiceExtensions.AddSingleton>(services, new global::Microsoft.Extensions.Options.ConfigureNamedOptions(name, obj => global::Microsoft.Extensions.Configuration.Binder.SourceGeneration.CoreBindingHelper.BindCoreUntyped(configuration, obj, typeof(TOptions), configureOptions))); } } namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration { using Microsoft.Extensions.Configuration; + using Microsoft.Extensions.DependencyInjection; using System; using System.CodeDom.Compiler; using System.Collections.Generic; using System.Globalization; + using System.Runtime.CompilerServices; - /// Provide core binding logic. [GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")] - file static class CoreBindingHelper + file static class BindingExtensions { + #region IServiceCollection extensions. + /// Registers a configuration instance which TOptions will bind against. + [InterceptsLocationAttribute(@"src-0.cs", 14, 18)] + public static IServiceCollection Configure(this IServiceCollection services, IConfiguration configuration, Action? configureOptions) where TOptions : class + { + return Configure(services, string.Empty, configuration, configureOptions); + } + + /// Registers a configuration instance which TOptions will bind against. + public static IServiceCollection Configure(this IServiceCollection services, string? name, IConfiguration configuration, Action? configureOptions) where TOptions : class + { + if (services is null) + { + throw new ArgumentNullException(nameof(services)); + } + + if (configuration is null) + { + throw new ArgumentNullException(nameof(configuration)); + } + + OptionsServiceCollectionExtensions.AddOptions(services); + services.AddSingleton>(new ConfigurationChangeTokenSource(name, configuration)); + return services.AddSingleton>(new Microsoft.Extensions.Options.ConfigureNamedOptions(name, obj => BindCoreMain(configuration, obj, typeof(TOptions)configureOptions))); + } + #endregion IServiceCollection extensions. + + #region Core binding extensions. private readonly static Lazy> s_configKeys_ProgramMyClass2 = new(() => new HashSet(StringComparer.OrdinalIgnoreCase) { "MyInt" }); private readonly static Lazy> s_configKeys_ProgramMyClass = new(() => new HashSet(StringComparer.OrdinalIgnoreCase) { "MyString", "MyInt", "MyList", "MyList2", "MyDictionary" }); - public static void BindCoreUntyped(this IConfiguration configuration, object obj, Type type, Action? configureOptions) + public static void BindCoreMain(IConfiguration configuration, object obj, Type type, Action? configureOptions) { if (configuration is null) { throw new ArgumentNullException(nameof(configuration)); } - BinderOptions? binderOptions = GetBinderOptions(configureOptions); + if (obj is null) + { + throw new ArgumentNullException(nameof(obj)); + } if (!HasValueOrChildren(configuration)) { return; } + BinderOptions? binderOptions = GetBinderOptions(configureOptions); + if (type == typeof(Program.MyClass)) { var temp = (Program.MyClass)obj; @@ -67,16 +87,11 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration return; } - throw new global::System.NotSupportedException($"Unable to bind to type '{type}': generator did not detect the type as input."); + throw new NotSupportedException($"Unable to bind to type '{type}': generator did not detect the type as input."); } public static void BindCore(IConfiguration configuration, ref List obj, BinderOptions? binderOptions) { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - foreach (IConfigurationSection section in configuration.GetChildren()) { if (section.Value is string value) @@ -88,11 +103,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration public static void BindCore(IConfiguration configuration, ref Program.MyClass2 obj, BinderOptions? binderOptions) { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - ValidateConfigurationKeys(typeof(Program.MyClass2), s_configKeys_ProgramMyClass2, configuration, binderOptions); if (configuration["MyInt"] is string value1) @@ -103,11 +113,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration public static void BindCore(IConfiguration configuration, ref List obj, BinderOptions? binderOptions) { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - foreach (IConfigurationSection section in configuration.GetChildren()) { var value = new Program.MyClass2(); @@ -118,11 +123,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration public static void BindCore(IConfiguration configuration, ref Dictionary obj, BinderOptions? binderOptions) { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - foreach (IConfigurationSection section in configuration.GetChildren()) { if (section.Value is string value) @@ -134,11 +134,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration public static void BindCore(IConfiguration configuration, ref Program.MyClass obj, BinderOptions? binderOptions) { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - ValidateConfigurationKeys(typeof(Program.MyClass), s_configKeys_ProgramMyClass, configuration, binderOptions); obj.MyString = configuration["MyString"]!; @@ -173,6 +168,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration } } + /// If required by the binder options, validates that there are no unknown keys in the input configuration object. public static void ValidateConfigurationKeys(Type type, Lazy> keys, IConfiguration configuration, BinderOptions? binderOptions) { @@ -225,7 +221,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration if (binderOptions.BindNonPublicProperties) { - throw new global::System.NotSupportedException($"The configuration binding source generator does not support 'BinderOptions.BindNonPublicProperties'."); + throw new NotSupportedException($"The configuration binding source generator does not support 'BinderOptions.BindNonPublicProperties'."); } return binderOptions; @@ -242,5 +238,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration throw new InvalidOperationException($"Failed to convert configuration value at '{getPath()}' to type '{typeof(int)}'.", exception); } } + #endregion Core binding extensions. } } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ServiceCollection/Configure_T_name.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ServiceCollection/Configure_T_name.generated.txt index 7eb3350dd0825..6fdb013b0899c 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ServiceCollection/Configure_T_name.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ServiceCollection/Configure_T_name.generated.txt @@ -41,15 +41,9 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration /// Registers a configuration instance which TOptions will bind against. public static IServiceCollection Configure(this IServiceCollection services, string? name, IConfiguration configuration, Action? configureOptions) where TOptions : class { - if (services is null) - { - throw new ArgumentNullException(nameof(services)); - } + ArgumentNullException.ThrowIfNull(services); - if (configuration is null) - { - throw new ArgumentNullException(nameof(configuration)); - } + ArgumentNullException.ThrowIfNull(configuration); OptionsServiceCollectionExtensions.AddOptions(services); services.AddSingleton>(new ConfigurationChangeTokenSource(name, configuration)); @@ -65,10 +59,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration { ArgumentNullException.ThrowIfNull(configuration); - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } + ArgumentNullException.ThrowIfNull(obj); if (!HasValueOrChildren(configuration)) { diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ServiceCollection/Configure_T_name.net462.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ServiceCollection/Configure_T_name.net462.generated.txt index 66975c3164d74..91226d730166f 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ServiceCollection/Configure_T_name.net462.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ServiceCollection/Configure_T_name.net462.generated.txt @@ -2,64 +2,84 @@ #nullable enable #pragma warning disable CS0612, CS0618 // Suppress warnings about [Obsolete] member usage in generated code. -/// Generated helper providing an AOT and linking compatible implementation for configuration binding. -[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")] -internal static class GeneratedServiceCollectionBinder +namespace System.Runtime.CompilerServices { - /// Registers a configuration instance which TOptions will bind against. - public static global::Microsoft.Extensions.DependencyInjection.IServiceCollection Configure(this global::Microsoft.Extensions.DependencyInjection.IServiceCollection services, string? name, global::Microsoft.Extensions.Configuration.IConfiguration configuration) where TOptions : class - { - return global::GeneratedServiceCollectionBinder.Configure(services, name, configuration, configureOptions: null); - } + using System; + using System.CodeDom.Compiler; - /// Registers a configuration instance which TOptions will bind against. - public static global::Microsoft.Extensions.DependencyInjection.IServiceCollection Configure(this global::Microsoft.Extensions.DependencyInjection.IServiceCollection services, string? name, global::Microsoft.Extensions.Configuration.IConfiguration configuration, global::System.Action? configureOptions) where TOptions : class + [GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")] + [AttributeUsage(AttributeTargets.Method, AllowMultiple = true)] + file sealed class InterceptsLocationAttribute : Attribute { - if (services is null) - { - throw new global::System.ArgumentNullException(nameof(services)); - } - - if (configuration is null) + public InterceptsLocationAttribute(string filePath, int line, int column) { - throw new global::System.ArgumentNullException(nameof(configuration)); } - - global::Microsoft.Extensions.DependencyInjection.OptionsServiceCollectionExtensions.AddOptions(services); - global::Microsoft.Extensions.DependencyInjection.ServiceCollectionServiceExtensions.AddSingleton>(services, new global::Microsoft.Extensions.Options.ConfigurationChangeTokenSource(name, configuration)); - return global::Microsoft.Extensions.DependencyInjection.ServiceCollectionServiceExtensions.AddSingleton>(services, new global::Microsoft.Extensions.Options.ConfigureNamedOptions(name, obj => global::Microsoft.Extensions.Configuration.Binder.SourceGeneration.CoreBindingHelper.BindCoreUntyped(configuration, obj, typeof(TOptions), configureOptions))); } } namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration { using Microsoft.Extensions.Configuration; + using Microsoft.Extensions.DependencyInjection; using System; using System.CodeDom.Compiler; using System.Collections.Generic; using System.Globalization; + using System.Runtime.CompilerServices; - /// Provide core binding logic. [GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")] - file static class CoreBindingHelper + file static class BindingExtensions { + #region IServiceCollection extensions. + /// Registers a configuration instance which TOptions will bind against. + [InterceptsLocationAttribute(@"src-0.cs", 14, 18)] + public static IServiceCollection Configure(this IServiceCollection services, string? name, IConfiguration configuration) where TOptions : class + { + return Configure(services, name, configuration, configureOptions: null); + } + + /// Registers a configuration instance which TOptions will bind against. + public static IServiceCollection Configure(this IServiceCollection services, string? name, IConfiguration configuration, Action? configureOptions) where TOptions : class + { + if (services is null) + { + throw new ArgumentNullException(nameof(services)); + } + + if (configuration is null) + { + throw new ArgumentNullException(nameof(configuration)); + } + + OptionsServiceCollectionExtensions.AddOptions(services); + services.AddSingleton>(new ConfigurationChangeTokenSource(name, configuration)); + return services.AddSingleton>(new Microsoft.Extensions.Options.ConfigureNamedOptions(name, obj => BindCoreMain(configuration, obj, typeof(TOptions)configureOptions))); + } + #endregion IServiceCollection extensions. + + #region Core binding extensions. private readonly static Lazy> s_configKeys_ProgramMyClass2 = new(() => new HashSet(StringComparer.OrdinalIgnoreCase) { "MyInt" }); private readonly static Lazy> s_configKeys_ProgramMyClass = new(() => new HashSet(StringComparer.OrdinalIgnoreCase) { "MyString", "MyInt", "MyList", "MyList2", "MyDictionary" }); - public static void BindCoreUntyped(this IConfiguration configuration, object obj, Type type, Action? configureOptions) + public static void BindCoreMain(IConfiguration configuration, object obj, Type type, Action? configureOptions) { if (configuration is null) { throw new ArgumentNullException(nameof(configuration)); } - BinderOptions? binderOptions = GetBinderOptions(configureOptions); + if (obj is null) + { + throw new ArgumentNullException(nameof(obj)); + } if (!HasValueOrChildren(configuration)) { return; } + BinderOptions? binderOptions = GetBinderOptions(configureOptions); + if (type == typeof(Program.MyClass)) { var temp = (Program.MyClass)obj; @@ -67,16 +87,11 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration return; } - throw new global::System.NotSupportedException($"Unable to bind to type '{type}': generator did not detect the type as input."); + throw new NotSupportedException($"Unable to bind to type '{type}': generator did not detect the type as input."); } public static void BindCore(IConfiguration configuration, ref List obj, BinderOptions? binderOptions) { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - foreach (IConfigurationSection section in configuration.GetChildren()) { if (section.Value is string value) @@ -88,11 +103,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration public static void BindCore(IConfiguration configuration, ref Program.MyClass2 obj, BinderOptions? binderOptions) { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - ValidateConfigurationKeys(typeof(Program.MyClass2), s_configKeys_ProgramMyClass2, configuration, binderOptions); if (configuration["MyInt"] is string value1) @@ -103,11 +113,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration public static void BindCore(IConfiguration configuration, ref List obj, BinderOptions? binderOptions) { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - foreach (IConfigurationSection section in configuration.GetChildren()) { var value = new Program.MyClass2(); @@ -118,11 +123,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration public static void BindCore(IConfiguration configuration, ref Dictionary obj, BinderOptions? binderOptions) { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - foreach (IConfigurationSection section in configuration.GetChildren()) { if (section.Value is string value) @@ -134,11 +134,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration public static void BindCore(IConfiguration configuration, ref Program.MyClass obj, BinderOptions? binderOptions) { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - ValidateConfigurationKeys(typeof(Program.MyClass), s_configKeys_ProgramMyClass, configuration, binderOptions); obj.MyString = configuration["MyString"]!; @@ -173,6 +168,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration } } + /// If required by the binder options, validates that there are no unknown keys in the input configuration object. public static void ValidateConfigurationKeys(Type type, Lazy> keys, IConfiguration configuration, BinderOptions? binderOptions) { @@ -225,7 +221,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration if (binderOptions.BindNonPublicProperties) { - throw new global::System.NotSupportedException($"The configuration binding source generator does not support 'BinderOptions.BindNonPublicProperties'."); + throw new NotSupportedException($"The configuration binding source generator does not support 'BinderOptions.BindNonPublicProperties'."); } return binderOptions; @@ -242,5 +238,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration throw new InvalidOperationException($"Failed to convert configuration value at '{getPath()}' to type '{typeof(int)}'.", exception); } } + #endregion Core binding extensions. } } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ServiceCollection/Configure_T_name_BinderOptions.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ServiceCollection/Configure_T_name_BinderOptions.generated.txt index 62dd9ff419a56..54700e205e607 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ServiceCollection/Configure_T_name_BinderOptions.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ServiceCollection/Configure_T_name_BinderOptions.generated.txt @@ -35,15 +35,9 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration [InterceptsLocationAttribute(@"src-0.cs", 14, 18)] public static IServiceCollection Configure(this IServiceCollection services, string? name, IConfiguration configuration, Action? configureOptions) where TOptions : class { - if (services is null) - { - throw new ArgumentNullException(nameof(services)); - } + ArgumentNullException.ThrowIfNull(services); - if (configuration is null) - { - throw new ArgumentNullException(nameof(configuration)); - } + ArgumentNullException.ThrowIfNull(configuration); OptionsServiceCollectionExtensions.AddOptions(services); services.AddSingleton>(new ConfigurationChangeTokenSource(name, configuration)); @@ -59,10 +53,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration { ArgumentNullException.ThrowIfNull(configuration); - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } + ArgumentNullException.ThrowIfNull(obj); if (!HasValueOrChildren(configuration)) { diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ServiceCollection/Configure_T_name_BinderOptions.net462.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ServiceCollection/Configure_T_name_BinderOptions.net462.generated.txt index 0263ef1217940..8c9ccaa71a779 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ServiceCollection/Configure_T_name_BinderOptions.net462.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ServiceCollection/Configure_T_name_BinderOptions.net462.generated.txt @@ -2,58 +2,78 @@ #nullable enable #pragma warning disable CS0612, CS0618 // Suppress warnings about [Obsolete] member usage in generated code. -/// Generated helper providing an AOT and linking compatible implementation for configuration binding. -[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")] -internal static class GeneratedServiceCollectionBinder +namespace System.Runtime.CompilerServices { - /// Registers a configuration instance which TOptions will bind against. - public static global::Microsoft.Extensions.DependencyInjection.IServiceCollection Configure(this global::Microsoft.Extensions.DependencyInjection.IServiceCollection services, string? name, global::Microsoft.Extensions.Configuration.IConfiguration configuration, global::System.Action? configureOptions) where TOptions : class - { - if (services is null) - { - throw new global::System.ArgumentNullException(nameof(services)); - } + using System; + using System.CodeDom.Compiler; - if (configuration is null) + [GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")] + [AttributeUsage(AttributeTargets.Method, AllowMultiple = true)] + file sealed class InterceptsLocationAttribute : Attribute + { + public InterceptsLocationAttribute(string filePath, int line, int column) { - throw new global::System.ArgumentNullException(nameof(configuration)); } - - global::Microsoft.Extensions.DependencyInjection.OptionsServiceCollectionExtensions.AddOptions(services); - global::Microsoft.Extensions.DependencyInjection.ServiceCollectionServiceExtensions.AddSingleton>(services, new global::Microsoft.Extensions.Options.ConfigurationChangeTokenSource(name, configuration)); - return global::Microsoft.Extensions.DependencyInjection.ServiceCollectionServiceExtensions.AddSingleton>(services, new global::Microsoft.Extensions.Options.ConfigureNamedOptions(name, obj => global::Microsoft.Extensions.Configuration.Binder.SourceGeneration.CoreBindingHelper.BindCoreUntyped(configuration, obj, typeof(TOptions), configureOptions))); } } namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration { using Microsoft.Extensions.Configuration; + using Microsoft.Extensions.DependencyInjection; using System; using System.CodeDom.Compiler; using System.Collections.Generic; using System.Globalization; + using System.Runtime.CompilerServices; - /// Provide core binding logic. [GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")] - file static class CoreBindingHelper + file static class BindingExtensions { + #region IServiceCollection extensions. + /// Registers a configuration instance which TOptions will bind against. + [InterceptsLocationAttribute(@"src-0.cs", 14, 18)] + public static IServiceCollection Configure(this IServiceCollection services, string? name, IConfiguration configuration, Action? configureOptions) where TOptions : class + { + if (services is null) + { + throw new ArgumentNullException(nameof(services)); + } + + if (configuration is null) + { + throw new ArgumentNullException(nameof(configuration)); + } + + OptionsServiceCollectionExtensions.AddOptions(services); + services.AddSingleton>(new ConfigurationChangeTokenSource(name, configuration)); + return services.AddSingleton>(new Microsoft.Extensions.Options.ConfigureNamedOptions(name, obj => BindCoreMain(configuration, obj, typeof(TOptions)configureOptions))); + } + #endregion IServiceCollection extensions. + + #region Core binding extensions. private readonly static Lazy> s_configKeys_ProgramMyClass2 = new(() => new HashSet(StringComparer.OrdinalIgnoreCase) { "MyInt" }); private readonly static Lazy> s_configKeys_ProgramMyClass = new(() => new HashSet(StringComparer.OrdinalIgnoreCase) { "MyString", "MyInt", "MyList", "MyList2", "MyDictionary" }); - public static void BindCoreUntyped(this IConfiguration configuration, object obj, Type type, Action? configureOptions) + public static void BindCoreMain(IConfiguration configuration, object obj, Type type, Action? configureOptions) { if (configuration is null) { throw new ArgumentNullException(nameof(configuration)); } - BinderOptions? binderOptions = GetBinderOptions(configureOptions); + if (obj is null) + { + throw new ArgumentNullException(nameof(obj)); + } if (!HasValueOrChildren(configuration)) { return; } + BinderOptions? binderOptions = GetBinderOptions(configureOptions); + if (type == typeof(Program.MyClass)) { var temp = (Program.MyClass)obj; @@ -61,16 +81,11 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration return; } - throw new global::System.NotSupportedException($"Unable to bind to type '{type}': generator did not detect the type as input."); + throw new NotSupportedException($"Unable to bind to type '{type}': generator did not detect the type as input."); } public static void BindCore(IConfiguration configuration, ref List obj, BinderOptions? binderOptions) { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - foreach (IConfigurationSection section in configuration.GetChildren()) { if (section.Value is string value) @@ -82,11 +97,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration public static void BindCore(IConfiguration configuration, ref Program.MyClass2 obj, BinderOptions? binderOptions) { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - ValidateConfigurationKeys(typeof(Program.MyClass2), s_configKeys_ProgramMyClass2, configuration, binderOptions); if (configuration["MyInt"] is string value1) @@ -97,11 +107,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration public static void BindCore(IConfiguration configuration, ref List obj, BinderOptions? binderOptions) { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - foreach (IConfigurationSection section in configuration.GetChildren()) { var value = new Program.MyClass2(); @@ -112,11 +117,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration public static void BindCore(IConfiguration configuration, ref Dictionary obj, BinderOptions? binderOptions) { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - foreach (IConfigurationSection section in configuration.GetChildren()) { if (section.Value is string value) @@ -128,11 +128,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration public static void BindCore(IConfiguration configuration, ref Program.MyClass obj, BinderOptions? binderOptions) { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - ValidateConfigurationKeys(typeof(Program.MyClass), s_configKeys_ProgramMyClass, configuration, binderOptions); obj.MyString = configuration["MyString"]!; @@ -167,6 +162,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration } } + /// If required by the binder options, validates that there are no unknown keys in the input configuration object. public static void ValidateConfigurationKeys(Type type, Lazy> keys, IConfiguration configuration, BinderOptions? binderOptions) { @@ -219,7 +215,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration if (binderOptions.BindNonPublicProperties) { - throw new global::System.NotSupportedException($"The configuration binding source generator does not support 'BinderOptions.BindNonPublicProperties'."); + throw new NotSupportedException($"The configuration binding source generator does not support 'BinderOptions.BindNonPublicProperties'."); } return binderOptions; @@ -236,5 +232,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration throw new InvalidOperationException($"Failed to convert configuration value at '{getPath()}' to type '{typeof(int)}'.", exception); } } + #endregion Core binding extensions. } } From f5a2abcfc0dfc5fdb0267c378dd2be745fcda39b Mon Sep 17 00:00:00 2001 From: pedrobsaila Date: Mon, 28 Aug 2023 23:26:45 +0200 Subject: [PATCH 04/17] fix remarks --- .../ConfigurationBindingGenerator.Parser.cs | 2 +- .../gen/Model/KnownTypeSymbols.cs | 4 +- .../Bind.generated.txt} | 0 .../BindConfiguration.generated.txt} | 0 .../Bind_Instance.generated.txt} | 0 ...Bind_Instance_BinderOptions.generated.txt} | 0 .../Bind_Key_Instance.generated.txt} | 0 .../Bind_T.generated.txt} | 0 .../Bind_T_BinderOptions.generated.txt} | 0 .../Collections.generated.txt} | 0 .../Configure_T.generated.txt} | 0 .../Configure_T_BinderOptions.generated.txt} | 0 .../Configure_T_name.generated.txt} | 0 ...figure_T_name_BinderOptions.generated.txt} | 0 .../Get.generated.txt} | 0 .../GetValue.generated.txt} | 0 .../GetValue_T_Key.generated.txt} | 0 ...GetValue_T_Key_DefaultValue.generated.txt} | 0 .../GetValue_TypeOf_Key.generated.txt} | 0 ...lue_TypeOf_Key_DefaultValue.generated.txt} | 0 .../Get_T.generated.txt} | 0 .../Get_T_BinderOptions.generated.txt} | 0 .../Get_TypeOf.generated.txt} | 0 .../Get_TypeOf_BinderOptions.generated.txt} | 0 .../Primitives.generated.txt} | 0 .../Bind.generated.txt | 0 .../BindConfiguration.generated.txt | 0 .../Bind_Instance.generated.txt | 0 .../Bind_Instance_BinderOptions.generated.txt | 0 .../Bind_Key_Instance.generated.txt | 0 .../Bind_T.generated.txt | 0 .../Bind_T_BinderOptions.generated.txt | 0 .../Collections.generated.txt | 0 .../Configure_T.generated.txt | 0 .../Configure_T_BinderOptions.generated.txt | 0 .../Configure_T_name.generated.txt | 0 ...nfigure_T_name_BinderOptions.generated.txt | 0 .../Get.generated.txt | 0 .../GetValue.generated.txt | 0 .../GetValue_T_Key.generated.txt | 0 .../GetValue_T_Key_DefaultValue.generated.txt | 0 .../GetValue_TypeOf_Key.generated.txt | 0 ...alue_TypeOf_Key_DefaultValue.generated.txt | 0 .../Get_T.generated.txt | 0 .../Get_T_BinderOptions.generated.txt | 0 .../Get_TypeOf.generated.txt | 0 .../Get_TypeOf_BinderOptions.generated.txt | 0 .../{ => netcoreapp}/Primitives.generated.txt | 0 .../GeneratorTests.Baselines.Options.cs | 29 +++++---- .../GeneratorTests.Baselines.cs | 65 ++++++++++--------- .../SourceGenerationTests/GeneratorTests.cs | 7 +- ...ation.Binder.SourceGeneration.Tests.csproj | 55 ++++++++++++++-- 52 files changed, 104 insertions(+), 58 deletions(-) rename src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/{ConfigurationBinder/Bind.net462.generated.txt => net462/Bind.generated.txt} (100%) rename src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/{OptionsBuilder/BindConfiguration.net462.generated.txt => net462/BindConfiguration.generated.txt} (100%) rename src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/{ConfigurationBinder/Bind_Instance.net462.generated.txt => net462/Bind_Instance.generated.txt} (100%) rename src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/{ConfigurationBinder/Bind_Instance_BinderOptions.net462.generated.txt => net462/Bind_Instance_BinderOptions.generated.txt} (100%) rename src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/{ConfigurationBinder/Bind_Key_Instance.net462.generated.txt => net462/Bind_Key_Instance.generated.txt} (100%) rename src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/{OptionsBuilder/Bind_T.net462.generated.txt => net462/Bind_T.generated.txt} (100%) rename src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/{OptionsBuilder/Bind_T_BinderOptions.net462.generated.txt => net462/Bind_T_BinderOptions.generated.txt} (100%) rename src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/{Collections.net462.generated.txt => net462/Collections.generated.txt} (100%) rename src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/{ServiceCollection/Configure_T.net462.generated.txt => net462/Configure_T.generated.txt} (100%) rename src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/{ServiceCollection/Configure_T_BinderOptions.net462.generated.txt => net462/Configure_T_BinderOptions.generated.txt} (100%) rename src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/{ServiceCollection/Configure_T_name.net462.generated.txt => net462/Configure_T_name.generated.txt} (100%) rename src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/{ServiceCollection/Configure_T_name_BinderOptions.net462.generated.txt => net462/Configure_T_name_BinderOptions.generated.txt} (100%) rename src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/{ConfigurationBinder/Get.net462.generated.txt => net462/Get.generated.txt} (100%) rename src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/{ConfigurationBinder/GetValue.net462.generated.txt => net462/GetValue.generated.txt} (100%) rename src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/{ConfigurationBinder/GetValue_T_Key.net462.generated.txt => net462/GetValue_T_Key.generated.txt} (100%) rename src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/{ConfigurationBinder/GetValue_T_Key_DefaultValue.net462.generated.txt => net462/GetValue_T_Key_DefaultValue.generated.txt} (100%) rename src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/{ConfigurationBinder/GetValue_TypeOf_Key.net462.generated.txt => net462/GetValue_TypeOf_Key.generated.txt} (100%) rename src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/{ConfigurationBinder/GetValue_TypeOf_Key_DefaultValue.net462.generated.txt => net462/GetValue_TypeOf_Key_DefaultValue.generated.txt} (100%) rename src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/{ConfigurationBinder/Get_T.net462.generated.txt => net462/Get_T.generated.txt} (100%) rename src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/{ConfigurationBinder/Get_T_BinderOptions.net462.generated.txt => net462/Get_T_BinderOptions.generated.txt} (100%) rename src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/{ConfigurationBinder/Get_TypeOf.net462.generated.txt => net462/Get_TypeOf.generated.txt} (100%) rename src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/{ConfigurationBinder/Get_TypeOf_BinderOptions.net462.generated.txt => net462/Get_TypeOf_BinderOptions.generated.txt} (100%) rename src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/{Primitives.net462.generated.txt => net462/Primitives.generated.txt} (100%) rename src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/{ConfigurationBinder => netcoreapp}/Bind.generated.txt (100%) rename src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/{OptionsBuilder => netcoreapp}/BindConfiguration.generated.txt (100%) rename src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/{ConfigurationBinder => netcoreapp}/Bind_Instance.generated.txt (100%) rename src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/{ConfigurationBinder => netcoreapp}/Bind_Instance_BinderOptions.generated.txt (100%) rename src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/{ConfigurationBinder => netcoreapp}/Bind_Key_Instance.generated.txt (100%) rename src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/{OptionsBuilder => netcoreapp}/Bind_T.generated.txt (100%) rename src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/{OptionsBuilder => netcoreapp}/Bind_T_BinderOptions.generated.txt (100%) rename src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/{ => netcoreapp}/Collections.generated.txt (100%) rename src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/{ServiceCollection => netcoreapp}/Configure_T.generated.txt (100%) rename src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/{ServiceCollection => netcoreapp}/Configure_T_BinderOptions.generated.txt (100%) rename src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/{ServiceCollection => netcoreapp}/Configure_T_name.generated.txt (100%) rename src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/{ServiceCollection => netcoreapp}/Configure_T_name_BinderOptions.generated.txt (100%) rename src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/{ConfigurationBinder => netcoreapp}/Get.generated.txt (100%) rename src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/{ConfigurationBinder => netcoreapp}/GetValue.generated.txt (100%) rename src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/{ConfigurationBinder => netcoreapp}/GetValue_T_Key.generated.txt (100%) rename src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/{ConfigurationBinder => netcoreapp}/GetValue_T_Key_DefaultValue.generated.txt (100%) rename src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/{ConfigurationBinder => netcoreapp}/GetValue_TypeOf_Key.generated.txt (100%) rename src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/{ConfigurationBinder => netcoreapp}/GetValue_TypeOf_Key_DefaultValue.generated.txt (100%) rename src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/{ConfigurationBinder => netcoreapp}/Get_T.generated.txt (100%) rename src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/{ConfigurationBinder => netcoreapp}/Get_T_BinderOptions.generated.txt (100%) rename src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/{ConfigurationBinder => netcoreapp}/Get_TypeOf.generated.txt (100%) rename src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/{ConfigurationBinder => netcoreapp}/Get_TypeOf_BinderOptions.generated.txt (100%) rename src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/{ => netcoreapp}/Primitives.generated.txt (100%) diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/ConfigurationBindingGenerator.Parser.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/ConfigurationBindingGenerator.Parser.cs index 891fe3dd1f50b..01ce190c07866 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/ConfigurationBindingGenerator.Parser.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/ConfigurationBindingGenerator.Parser.cs @@ -63,7 +63,7 @@ public Parser(SourceProductionContext context, KnownTypeSymbols typeSymbols, Imm } } - _sourceGenSpec.EmitThrowIfNullMethod = !_typeSymbols.ArgumentNullException.GetMembers("ThrowIfNull").IsEmpty; + _sourceGenSpec.EmitThrowIfNullMethod = _typeSymbols.ArgumentNullException is not null && _typeSymbols.ArgumentNullException.GetMembers("ThrowIfNull").IsEmpty is false; return _sourceGenSpec; } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Model/KnownTypeSymbols.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Model/KnownTypeSymbols.cs index 80b964047cce3..1334fd478fcb3 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Model/KnownTypeSymbols.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Model/KnownTypeSymbols.cs @@ -54,7 +54,7 @@ internal sealed record KnownTypeSymbols public INamedTypeSymbol? ISet_Unbound { get; } public INamedTypeSymbol? ISet { get; } public INamedTypeSymbol? List { get; } - public INamedTypeSymbol? Enum { get; } + public INamedTypeSymbol Enum { get; } public INamedTypeSymbol? ArgumentNullException { get; } public KnownTypeSymbols(CSharpCompilation compilation) @@ -112,7 +112,7 @@ public KnownTypeSymbols(CSharpCompilation compilation) ISet_Unbound = ISet?.ConstructUnboundGenericType(); // needed to be able to know if a member exist inside the compilation unit - Enum = compilation.GetBestTypeByMetadataName(typeof(Enum)); + Enum = compilation.GetSpecialType(SpecialType.System_Enum); ArgumentNullException = compilation.GetBestTypeByMetadataName(typeof(ArgumentNullException)); } } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Bind.net462.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/net462/Bind.generated.txt similarity index 100% rename from src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Bind.net462.generated.txt rename to src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/net462/Bind.generated.txt diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/OptionsBuilder/BindConfiguration.net462.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/net462/BindConfiguration.generated.txt similarity index 100% rename from src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/OptionsBuilder/BindConfiguration.net462.generated.txt rename to src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/net462/BindConfiguration.generated.txt diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Bind_Instance.net462.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/net462/Bind_Instance.generated.txt similarity index 100% rename from src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Bind_Instance.net462.generated.txt rename to src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/net462/Bind_Instance.generated.txt diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Bind_Instance_BinderOptions.net462.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/net462/Bind_Instance_BinderOptions.generated.txt similarity index 100% rename from src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Bind_Instance_BinderOptions.net462.generated.txt rename to src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/net462/Bind_Instance_BinderOptions.generated.txt diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Bind_Key_Instance.net462.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/net462/Bind_Key_Instance.generated.txt similarity index 100% rename from src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Bind_Key_Instance.net462.generated.txt rename to src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/net462/Bind_Key_Instance.generated.txt diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/OptionsBuilder/Bind_T.net462.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/net462/Bind_T.generated.txt similarity index 100% rename from src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/OptionsBuilder/Bind_T.net462.generated.txt rename to src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/net462/Bind_T.generated.txt diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/OptionsBuilder/Bind_T_BinderOptions.net462.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/net462/Bind_T_BinderOptions.generated.txt similarity index 100% rename from src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/OptionsBuilder/Bind_T_BinderOptions.net462.generated.txt rename to src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/net462/Bind_T_BinderOptions.generated.txt diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/Collections.net462.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/net462/Collections.generated.txt similarity index 100% rename from src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/Collections.net462.generated.txt rename to src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/net462/Collections.generated.txt diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ServiceCollection/Configure_T.net462.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/net462/Configure_T.generated.txt similarity index 100% rename from src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ServiceCollection/Configure_T.net462.generated.txt rename to src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/net462/Configure_T.generated.txt diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ServiceCollection/Configure_T_BinderOptions.net462.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/net462/Configure_T_BinderOptions.generated.txt similarity index 100% rename from src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ServiceCollection/Configure_T_BinderOptions.net462.generated.txt rename to src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/net462/Configure_T_BinderOptions.generated.txt diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ServiceCollection/Configure_T_name.net462.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/net462/Configure_T_name.generated.txt similarity index 100% rename from src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ServiceCollection/Configure_T_name.net462.generated.txt rename to src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/net462/Configure_T_name.generated.txt diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ServiceCollection/Configure_T_name_BinderOptions.net462.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/net462/Configure_T_name_BinderOptions.generated.txt similarity index 100% rename from src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ServiceCollection/Configure_T_name_BinderOptions.net462.generated.txt rename to src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/net462/Configure_T_name_BinderOptions.generated.txt diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Get.net462.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/net462/Get.generated.txt similarity index 100% rename from src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Get.net462.generated.txt rename to src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/net462/Get.generated.txt diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/GetValue.net462.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/net462/GetValue.generated.txt similarity index 100% rename from src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/GetValue.net462.generated.txt rename to src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/net462/GetValue.generated.txt diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/GetValue_T_Key.net462.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/net462/GetValue_T_Key.generated.txt similarity index 100% rename from src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/GetValue_T_Key.net462.generated.txt rename to src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/net462/GetValue_T_Key.generated.txt diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/GetValue_T_Key_DefaultValue.net462.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/net462/GetValue_T_Key_DefaultValue.generated.txt similarity index 100% rename from src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/GetValue_T_Key_DefaultValue.net462.generated.txt rename to src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/net462/GetValue_T_Key_DefaultValue.generated.txt diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/GetValue_TypeOf_Key.net462.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/net462/GetValue_TypeOf_Key.generated.txt similarity index 100% rename from src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/GetValue_TypeOf_Key.net462.generated.txt rename to src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/net462/GetValue_TypeOf_Key.generated.txt diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/GetValue_TypeOf_Key_DefaultValue.net462.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/net462/GetValue_TypeOf_Key_DefaultValue.generated.txt similarity index 100% rename from src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/GetValue_TypeOf_Key_DefaultValue.net462.generated.txt rename to src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/net462/GetValue_TypeOf_Key_DefaultValue.generated.txt diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Get_T.net462.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/net462/Get_T.generated.txt similarity index 100% rename from src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Get_T.net462.generated.txt rename to src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/net462/Get_T.generated.txt diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Get_T_BinderOptions.net462.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/net462/Get_T_BinderOptions.generated.txt similarity index 100% rename from src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Get_T_BinderOptions.net462.generated.txt rename to src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/net462/Get_T_BinderOptions.generated.txt diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Get_TypeOf.net462.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/net462/Get_TypeOf.generated.txt similarity index 100% rename from src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Get_TypeOf.net462.generated.txt rename to src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/net462/Get_TypeOf.generated.txt diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Get_TypeOf_BinderOptions.net462.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/net462/Get_TypeOf_BinderOptions.generated.txt similarity index 100% rename from src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Get_TypeOf_BinderOptions.net462.generated.txt rename to src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/net462/Get_TypeOf_BinderOptions.generated.txt diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/Primitives.net462.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/net462/Primitives.generated.txt similarity index 100% rename from src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/Primitives.net462.generated.txt rename to src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/net462/Primitives.generated.txt diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Bind.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/Bind.generated.txt similarity index 100% rename from src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Bind.generated.txt rename to src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/Bind.generated.txt diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/OptionsBuilder/BindConfiguration.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/BindConfiguration.generated.txt similarity index 100% rename from src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/OptionsBuilder/BindConfiguration.generated.txt rename to src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/BindConfiguration.generated.txt diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Bind_Instance.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/Bind_Instance.generated.txt similarity index 100% rename from src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Bind_Instance.generated.txt rename to src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/Bind_Instance.generated.txt diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Bind_Instance_BinderOptions.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/Bind_Instance_BinderOptions.generated.txt similarity index 100% rename from src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Bind_Instance_BinderOptions.generated.txt rename to src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/Bind_Instance_BinderOptions.generated.txt diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Bind_Key_Instance.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/Bind_Key_Instance.generated.txt similarity index 100% rename from src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Bind_Key_Instance.generated.txt rename to src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/Bind_Key_Instance.generated.txt diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/OptionsBuilder/Bind_T.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/Bind_T.generated.txt similarity index 100% rename from src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/OptionsBuilder/Bind_T.generated.txt rename to src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/Bind_T.generated.txt diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/OptionsBuilder/Bind_T_BinderOptions.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/Bind_T_BinderOptions.generated.txt similarity index 100% rename from src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/OptionsBuilder/Bind_T_BinderOptions.generated.txt rename to src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/Bind_T_BinderOptions.generated.txt diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/Collections.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/Collections.generated.txt similarity index 100% rename from src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/Collections.generated.txt rename to src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/Collections.generated.txt diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ServiceCollection/Configure_T.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/Configure_T.generated.txt similarity index 100% rename from src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ServiceCollection/Configure_T.generated.txt rename to src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/Configure_T.generated.txt diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ServiceCollection/Configure_T_BinderOptions.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/Configure_T_BinderOptions.generated.txt similarity index 100% rename from src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ServiceCollection/Configure_T_BinderOptions.generated.txt rename to src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/Configure_T_BinderOptions.generated.txt diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ServiceCollection/Configure_T_name.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/Configure_T_name.generated.txt similarity index 100% rename from src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ServiceCollection/Configure_T_name.generated.txt rename to src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/Configure_T_name.generated.txt diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ServiceCollection/Configure_T_name_BinderOptions.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/Configure_T_name_BinderOptions.generated.txt similarity index 100% rename from src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ServiceCollection/Configure_T_name_BinderOptions.generated.txt rename to src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/Configure_T_name_BinderOptions.generated.txt diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Get.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/Get.generated.txt similarity index 100% rename from src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Get.generated.txt rename to src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/Get.generated.txt diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/GetValue.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/GetValue.generated.txt similarity index 100% rename from src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/GetValue.generated.txt rename to src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/GetValue.generated.txt diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/GetValue_T_Key.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/GetValue_T_Key.generated.txt similarity index 100% rename from src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/GetValue_T_Key.generated.txt rename to src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/GetValue_T_Key.generated.txt diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/GetValue_T_Key_DefaultValue.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/GetValue_T_Key_DefaultValue.generated.txt similarity index 100% rename from src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/GetValue_T_Key_DefaultValue.generated.txt rename to src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/GetValue_T_Key_DefaultValue.generated.txt diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/GetValue_TypeOf_Key.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/GetValue_TypeOf_Key.generated.txt similarity index 100% rename from src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/GetValue_TypeOf_Key.generated.txt rename to src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/GetValue_TypeOf_Key.generated.txt diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/GetValue_TypeOf_Key_DefaultValue.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/GetValue_TypeOf_Key_DefaultValue.generated.txt similarity index 100% rename from src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/GetValue_TypeOf_Key_DefaultValue.generated.txt rename to src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/GetValue_TypeOf_Key_DefaultValue.generated.txt diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Get_T.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/Get_T.generated.txt similarity index 100% rename from src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Get_T.generated.txt rename to src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/Get_T.generated.txt diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Get_T_BinderOptions.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/Get_T_BinderOptions.generated.txt similarity index 100% rename from src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Get_T_BinderOptions.generated.txt rename to src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/Get_T_BinderOptions.generated.txt diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Get_TypeOf.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/Get_TypeOf.generated.txt similarity index 100% rename from src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Get_TypeOf.generated.txt rename to src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/Get_TypeOf.generated.txt diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Get_TypeOf_BinderOptions.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/Get_TypeOf_BinderOptions.generated.txt similarity index 100% rename from src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/ConfigurationBinder/Get_TypeOf_BinderOptions.generated.txt rename to src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/Get_TypeOf_BinderOptions.generated.txt diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/Primitives.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/Primitives.generated.txt similarity index 100% rename from src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/Primitives.generated.txt rename to src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/Primitives.generated.txt diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/GeneratorTests.Baselines.Options.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/GeneratorTests.Baselines.Options.cs index ba2698e367f2e..7874fee6b222d 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/GeneratorTests.Baselines.Options.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/GeneratorTests.Baselines.Options.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. using System; +using System.IO; using System.Threading.Tasks; using Xunit; @@ -47,35 +48,35 @@ public class MyClass2 #region OptionsBuilder extensions. [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNetCore))] public async Task Configure_T() => - await VerifyAgainstBaselineUsingFile("Configure_T.generated.txt", GetConfigureSource("section"), extType: ExtensionClassType.ServiceCollection); + await VerifyAgainstBaselineUsingFile(Path.Combine("netcoreapp", "Configure_T.generated.txt"), GetConfigureSource("section")); [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNetFramework))] public async Task Configure_T_NetFwk() => - await VerifyAgainstBaselineUsingFile("Configure_T.net462.generated.txt", GetConfigureSource("section"), extType: ExtensionClassType.ServiceCollection); + await VerifyAgainstBaselineUsingFile(Path.Combine("net462", "Configure_T.generated.txt"), GetConfigureSource("section")); [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNetCore))] public async Task Configure_T_name() => - await VerifyAgainstBaselineUsingFile("Configure_T_name.generated.txt", GetConfigureSource(@""""", section"), extType: ExtensionClassType.ServiceCollection); + await VerifyAgainstBaselineUsingFile(Path.Combine("netcoreapp", "Configure_T_name.generated.txt"), GetConfigureSource(@""""", section")); [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNetFramework))] public async Task Configure_T_name_NetFwk() => - await VerifyAgainstBaselineUsingFile("Configure_T_name.net462.generated.txt", GetConfigureSource(@""""", section"), extType: ExtensionClassType.ServiceCollection); + await VerifyAgainstBaselineUsingFile(Path.Combine("net462", "Configure_T_name.generated.txt"), GetConfigureSource(@""""", section")); [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNetCore))] public async Task Configure_T_BinderOptions() => - await VerifyAgainstBaselineUsingFile("Configure_T_BinderOptions.generated.txt", GetConfigureSource("section, _ => { }"), extType: ExtensionClassType.ServiceCollection); + await VerifyAgainstBaselineUsingFile(Path.Combine("netcoreapp", "Configure_T_BinderOptions.generated.txt"), GetConfigureSource("section, _ => { }")); [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNetFramework))] public async Task Configure_T_BinderOptions_NetFwk() => - await VerifyAgainstBaselineUsingFile("Configure_T_BinderOptions.net462.generated.txt", GetConfigureSource("section, _ => { }"), extType: ExtensionClassType.ServiceCollection); + await VerifyAgainstBaselineUsingFile(Path.Combine("net462", "Configure_T_BinderOptions.generated.txt"), GetConfigureSource("section, _ => { }")); [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNetCore))] public async Task Configure_T_name_BinderOptions() => - await VerifyAgainstBaselineUsingFile("Configure_T_name_BinderOptions.generated.txt", GetConfigureSource(@""""", section, _ => { }"), extType: ExtensionClassType.ServiceCollection); + await VerifyAgainstBaselineUsingFile(Path.Combine("netcoreapp", "Configure_T_name_BinderOptions.generated.txt"), GetConfigureSource(@""""", section, _ => { }")); [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNetFramework))] public async Task Configure_T_name_BinderOptions_NetFwk() => - await VerifyAgainstBaselineUsingFile("Configure_T_name_BinderOptions.net462.generated.txt", GetConfigureSource(@""""", section, _ => { }"), extType: ExtensionClassType.ServiceCollection); + await VerifyAgainstBaselineUsingFile(Path.Combine("net462", "Configure_T_name_BinderOptions.generated.txt"), GetConfigureSource(@""""", section, _ => { }")); private string GetBindSource(string? configureActions = null) => $$""" using System.Collections.Generic; @@ -107,25 +108,25 @@ public class MyClass [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNetCore))] public async Task Bind_T() { - await VerifyAgainstBaselineUsingFile("Bind_T.generated.txt", GetBindSource(), extType: ExtensionClassType.OptionsBuilder); + await VerifyAgainstBaselineUsingFile(Path.Combine("netcoreapp", "Bind_T.generated.txt"), GetBindSource()); } [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNetFramework))] public async Task Bind_T_NetFwk() { - await VerifyAgainstBaselineUsingFile("Bind_T.net462.generated.txt", GetBindSource(), extType: ExtensionClassType.OptionsBuilder); + await VerifyAgainstBaselineUsingFile(Path.Combine("net462", "Bind_T.generated.txt"), GetBindSource()); } [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNetCore))] public async Task Bind_T_BinderOptions() { - await VerifyAgainstBaselineUsingFile("Bind_T_BinderOptions.generated.txt", GetBindSource(", _ => { }"), extType: ExtensionClassType.OptionsBuilder); + await VerifyAgainstBaselineUsingFile(Path.Combine("netcoreapp", "Bind_T_BinderOptions.generated.txt"), GetBindSource(", _ => { }")); } [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNetFramework))] public async Task Bind_T_BinderOptions_NetFwk() { - await VerifyAgainstBaselineUsingFile("Bind_T_BinderOptions.net462.generated.txt", GetBindSource(", _ => { }"), extType: ExtensionClassType.OptionsBuilder); + await VerifyAgainstBaselineUsingFile(Path.Combine("net462", "Bind_T_BinderOptions.generated.txt"), GetBindSource(", _ => { }")); } [Fact] @@ -155,8 +156,8 @@ public class MyClass } """; - await VerifyAgainstBaselineUsingFile("BindConfiguration.generated.txt", GetSource(), extType: ExtensionClassType.OptionsBuilder); - await VerifyAgainstBaselineUsingFile("BindConfiguration.generated.txt", GetSource(@", _ => { }"), extType: ExtensionClassType.OptionsBuilder); + await VerifyAgainstBaselineUsingFile(Path.Combine("netcoreapp", "BindConfiguration.generated.txt"), GetSource()); + await VerifyAgainstBaselineUsingFile(Path.Combine("netcoreapp", "BindConfiguration.generated.txt"), GetSource(@"), _ => { }")); } #endregion OptionsBuilder extensions. } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/GeneratorTests.Baselines.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/GeneratorTests.Baselines.cs index dafed6787c10d..7fba8168a8de6 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/GeneratorTests.Baselines.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/GeneratorTests.Baselines.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. using System; +using System.IO; using System.Linq; using System.Threading.Tasks; using Microsoft.CodeAnalysis; @@ -44,13 +45,13 @@ public class MyClass2 { } [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsNetCore))] [InlineData(LanguageVersion.Preview)] public async Task Bind(LanguageVersion langVersion) => - await VerifyAgainstBaselineUsingFile("Bind.generated.txt", BindCallSampleCode, langVersion, extType: ExtensionClassType.ConfigurationBinder); + await VerifyAgainstBaselineUsingFile(Path.Combine("netcoreapp", "Bind.generated.txt"), BindCallSampleCode, langVersion); [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsNetFramework))] [InlineData(LanguageVersion.Preview)] [InlineData(LanguageVersion.CSharp11)] public async Task Bind_NetFwk(LanguageVersion langVersion) => - await VerifyAgainstBaselineUsingFile("Bind.net462.generated.txt", BindCallSampleCode, langVersion, extType: ExtensionClassType.ConfigurationBinder); + await VerifyAgainstBaselineUsingFile(Path.Combine("net462", "Bind.generated.txt"), BindCallSampleCode, langVersion); private string Bind_Instance_Sources() { @@ -88,7 +89,7 @@ public async Task Bind_Instance() { string source = Bind_Instance_Sources(); - await VerifyAgainstBaselineUsingFile("Bind_Instance.generated.txt", source, extType: ExtensionClassType.ConfigurationBinder); + await VerifyAgainstBaselineUsingFile(Path.Combine("netcoreapp", "Bind_Instance.generated.txt"), source); } [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNetFramework))] @@ -96,7 +97,7 @@ public async Task Bind_Instance_Fwk() { string source = Bind_Instance_Sources(); - await VerifyAgainstBaselineUsingFile("Bind_Instance.net462.generated.txt", source, extType: ExtensionClassType.ConfigurationBinder); + await VerifyAgainstBaselineUsingFile(Path.Combine("net462", "Bind_Instance.generated.txt"), source); } private string Bind_Instance_BinderOptions_Sources() @@ -135,7 +136,7 @@ public async Task Bind_Instance_BinderOptions() { string source = Bind_Instance_BinderOptions_Sources(); - await VerifyAgainstBaselineUsingFile("Bind_Instance_BinderOptions.generated.txt", source, extType: ExtensionClassType.ConfigurationBinder); + await VerifyAgainstBaselineUsingFile(Path.Combine("netcoreapp", "Bind_Instance_BinderOptions.generated.txt"), source); } [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNetFramework))] @@ -143,7 +144,7 @@ public async Task Bind_Instance_BinderOptions_NetFwk() { string source = Bind_Instance_BinderOptions_Sources(); - await VerifyAgainstBaselineUsingFile("Bind_Instance_BinderOptions.net462.generated.txt", source, extType: ExtensionClassType.ConfigurationBinder); + await VerifyAgainstBaselineUsingFile(Path.Combine("net462", "Bind_Instance_BinderOptions.generated.txt"), source); } private string Bind_Key_Sources() @@ -182,7 +183,7 @@ public async Task Bind_Key_Instance() { string source = Bind_Key_Sources(); - await VerifyAgainstBaselineUsingFile("Bind_Key_Instance.generated.txt", source, extType: ExtensionClassType.ConfigurationBinder); + await VerifyAgainstBaselineUsingFile(Path.Combine("netcoreapp", "Bind_Key_Instance.generated.txt"), source); } [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNetFramework))] @@ -190,7 +191,7 @@ public async Task Bind_Key_Instance_NetFwk() { string source = Bind_Key_Sources(); - await VerifyAgainstBaselineUsingFile("Bind_Key_Instance.net462.generated.txt", source, extType: ExtensionClassType.ConfigurationBinder); + await VerifyAgainstBaselineUsingFile(Path.Combine("net462", "Bind_Key_Instance.generated.txt"), source); } private string GetSources() @@ -243,7 +244,7 @@ public async Task Get() { string source = GetSources(); - await VerifyAgainstBaselineUsingFile("Get.generated.txt", source, extType: ExtensionClassType.ConfigurationBinder); + await VerifyAgainstBaselineUsingFile(Path.Combine("netcoreapp", "Get.generated.txt"), source); } [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNetFramework))] @@ -251,7 +252,7 @@ public async Task Get_NetFwk() { string source = GetSources(); - await VerifyAgainstBaselineUsingFile("Get.net462.generated.txt", source, extType: ExtensionClassType.ConfigurationBinder); + await VerifyAgainstBaselineUsingFile(Path.Combine("net462", "Get.generated.txt"), source); } private string Get_T_Sources() @@ -302,7 +303,7 @@ public async Task Get_T() { string source = Get_T_Sources(); - await VerifyAgainstBaselineUsingFile("Get_T.generated.txt", source, extType: ExtensionClassType.ConfigurationBinder); + await VerifyAgainstBaselineUsingFile(Path.Combine("netcoreapp", "Get_T.generated.txt"), source); } [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNetFramework))] @@ -310,7 +311,7 @@ public async Task Get_T_NetFwk() { string source = Get_T_Sources(); - await VerifyAgainstBaselineUsingFile("Get_T.net462.generated.txt", source, extType: ExtensionClassType.ConfigurationBinder); + await VerifyAgainstBaselineUsingFile(Path.Combine("net462", "Get_T.generated.txt"), source); } private string Get_T_BinderOptions_Sources() @@ -361,7 +362,7 @@ public async Task Get_T_BinderOptions() { string source = Get_T_BinderOptions_Sources(); - await VerifyAgainstBaselineUsingFile("Get_T_BinderOptions.generated.txt", source, extType: ExtensionClassType.ConfigurationBinder); + await VerifyAgainstBaselineUsingFile(Path.Combine("netcoreapp", "Get_T_BinderOptions.generated.txt"), source); } [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNetFramework))] @@ -369,7 +370,7 @@ public async Task Get_T_BinderOptions_NetFwk() { string source = Get_T_BinderOptions_Sources(); - await VerifyAgainstBaselineUsingFile("Get_T_BinderOptions.net462.generated.txt", source, extType: ExtensionClassType.ConfigurationBinder); + await VerifyAgainstBaselineUsingFile(Path.Combine("net462", "Get_T_BinderOptions.generated.txt"), source); } private string Get_TypeOf_Sources() @@ -420,7 +421,7 @@ public async Task Get_TypeOf() { string source = Get_TypeOf_Sources(); - await VerifyAgainstBaselineUsingFile("Get_TypeOf.generated.txt", source, extType: ExtensionClassType.ConfigurationBinder); + await VerifyAgainstBaselineUsingFile(Path.Combine("netcoreapp", "Get_TypeOf.generated.txt"), source); } [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNetFramework))] @@ -428,7 +429,7 @@ public async Task Get_TypeOf_NetFwk() { string source = Get_TypeOf_Sources(); - await VerifyAgainstBaselineUsingFile("Get_TypeOf.net462.generated.txt", source, extType: ExtensionClassType.ConfigurationBinder); + await VerifyAgainstBaselineUsingFile(Path.Combine("net462", "Get_TypeOf.generated.txt"), source); } private string Get_TypeOf_BinderOptions_Sources() @@ -479,7 +480,7 @@ public async Task Get_TypeOf_BinderOptions() { string source = Get_TypeOf_BinderOptions_Sources(); - await VerifyAgainstBaselineUsingFile("Get_TypeOf_BinderOptions.generated.txt", source, extType: ExtensionClassType.ConfigurationBinder); + await VerifyAgainstBaselineUsingFile(Path.Combine("netcoreapp", "Get_TypeOf_BinderOptions.generated.txt"), source); } [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNetFramework))] @@ -487,7 +488,7 @@ public async Task Get_TypeOf_BinderOptions_NetFwk() { string source = Get_TypeOf_BinderOptions_Sources(); - await VerifyAgainstBaselineUsingFile("Get_TypeOf_BinderOptions.net462.generated.txt", source, extType: ExtensionClassType.ConfigurationBinder); + await VerifyAgainstBaselineUsingFile(Path.Combine("net462", "Get_TypeOf_BinderOptions.generated.txt"), source); } private string GetValue_Sources() @@ -527,7 +528,7 @@ public async Task GetValue() { string source = GetValue_Sources(); - await VerifyAgainstBaselineUsingFile("GetValue.generated.txt", source, extType: ExtensionClassType.ConfigurationBinder); + await VerifyAgainstBaselineUsingFile(Path.Combine("netcoreapp", "GetValue.generated.txt"), source); } [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNetFramework))] @@ -535,7 +536,7 @@ public async Task GetValue_NetFwk() { string source = GetValue_Sources(); - await VerifyAgainstBaselineUsingFile("GetValue.net462.generated.txt", source, extType: ExtensionClassType.ConfigurationBinder); + await VerifyAgainstBaselineUsingFile(Path.Combine("net462", "GetValue.generated.txt"), source); } private string GetValue_T_Key_Sources() @@ -561,7 +562,7 @@ public async Task GetValue_T_Key() { string source = GetValue_T_Key_Sources(); - await VerifyAgainstBaselineUsingFile("GetValue_T_Key.generated.txt", source, extType: ExtensionClassType.ConfigurationBinder); + await VerifyAgainstBaselineUsingFile(Path.Combine("netcoreapp", "GetValue_T_Key.generated.txt"), source); } [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNetFramework))] @@ -569,7 +570,7 @@ public async Task GetValue_T_Key_NetFwk() { string source = GetValue_T_Key_Sources(); - await VerifyAgainstBaselineUsingFile("GetValue_T_Key.net462.generated.txt", source, extType: ExtensionClassType.ConfigurationBinder); + await VerifyAgainstBaselineUsingFile(Path.Combine("net462", "GetValue_T_Key.generated.txt"), source); } private string GetValue_T_Key_DefaultValue_Sources() @@ -597,7 +598,7 @@ public async Task GetValue_T_Key_DefaultValue() { string source = GetValue_T_Key_DefaultValue_Sources(); - await VerifyAgainstBaselineUsingFile("GetValue_T_Key_DefaultValue.generated.txt", source, extType: ExtensionClassType.ConfigurationBinder); + await VerifyAgainstBaselineUsingFile(Path.Combine("netcoreapp", "GetValue_T_Key_DefaultValue.generated.txt"), source); } [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNetFramework))] @@ -605,7 +606,7 @@ public async Task GetValue_T_Key_DefaultValue_NetFwk() { string source = GetValue_T_Key_DefaultValue_Sources(); - await VerifyAgainstBaselineUsingFile("GetValue_T_Key_DefaultValue.net462.generated.txt", source, extType: ExtensionClassType.ConfigurationBinder); + await VerifyAgainstBaselineUsingFile(Path.Combine("net462", "GetValue_T_Key_DefaultValue.generated.txt"), source); } private string GetValue_TypeOf_Key_Sources() @@ -631,7 +632,7 @@ public async Task GetValue_TypeOf_Key() { string source = GetValue_TypeOf_Key_Sources(); - await VerifyAgainstBaselineUsingFile("GetValue_TypeOf_Key.generated.txt", source, extType: ExtensionClassType.ConfigurationBinder); + await VerifyAgainstBaselineUsingFile(Path.Combine("netcoreapp", "GetValue_TypeOf_Key.generated.txt"), source); } [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNetFramework))] @@ -639,7 +640,7 @@ public async Task GetValue_TypeOf_Key_NetFwk() { string source = GetValue_TypeOf_Key_Sources(); - await VerifyAgainstBaselineUsingFile("GetValue_TypeOf_Key.net462.generated.txt", source, extType: ExtensionClassType.ConfigurationBinder); + await VerifyAgainstBaselineUsingFile(Path.Combine("net462", "GetValue_TypeOf_Key.generated.txt"), source); } private string GetValue_TypeOf_Key_DefaultValue_Sources() @@ -666,7 +667,7 @@ public async Task GetValue_TypeOf_Key_DefaultValue() { string source = GetValue_TypeOf_Key_DefaultValue_Sources(); - await VerifyAgainstBaselineUsingFile("GetValue_TypeOf_Key_DefaultValue.generated.txt", source, extType: ExtensionClassType.ConfigurationBinder); + await VerifyAgainstBaselineUsingFile(Path.Combine("netcoreapp", "GetValue_TypeOf_Key_DefaultValue.generated.txt"), source); } [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNetFramework))] @@ -674,7 +675,7 @@ public async Task GetValue_TypeOf_Key_DefaultValue_NetFwk() { string source = GetValue_TypeOf_Key_DefaultValue_Sources(); - await VerifyAgainstBaselineUsingFile("GetValue_TypeOf_Key_DefaultValue.net462.generated.txt", source, extType: ExtensionClassType.ConfigurationBinder); + await VerifyAgainstBaselineUsingFile(Path.Combine("net462", "GetValue_TypeOf_Key_DefaultValue.generated.txt"), source); } [Fact] @@ -776,7 +777,7 @@ public class MyClass public async Task Primitives() { string source = GetPrimitivesSource(); - await VerifyAgainstBaselineUsingFile("Primitives.generated.txt", source); + await VerifyAgainstBaselineUsingFile(Path.Combine("netcoreapp", "Primitives.generated.txt"), source); } [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNetFramework))] @@ -784,7 +785,7 @@ public async Task PrimitivesNetFwk() { string source = GetPrimitivesSource(); - await VerifyAgainstBaselineUsingFile($"Primitives.net462.generated.txt", source); + await VerifyAgainstBaselineUsingFile(Path.Combine("net462", "Primitives.generated.txt"), source); } private string GetCollectionsSource() @@ -839,7 +840,7 @@ public async Task Collections() { string source = GetCollectionsSource(); - await VerifyAgainstBaselineUsingFile("Collections.generated.txt", source, assessDiagnostics: (d) => + await VerifyAgainstBaselineUsingFile(Path.Combine("netcoreapp", "Collections.generated.txt"), source, assessDiagnostics: (d) => { Assert.Equal(3, d.Where(diag => diag.Id == Diagnostics.TypeNotSupported.Id).Count()); Assert.Equal(6, d.Where(diag => diag.Id == Diagnostics.PropertyNotSupported.Id).Count()); @@ -851,7 +852,7 @@ public async Task CollectionsFwk() { string source = GetCollectionsSource(); - await VerifyAgainstBaselineUsingFile("Collections.net462.generated.txt", source, assessDiagnostics: (d) => + await VerifyAgainstBaselineUsingFile(Path.Combine("net462", "Collections.generated.txt"), source, assessDiagnostics: (d) => { Console.WriteLine((d.Where(diag => diag.Id == Diagnostics.TypeNotSupported.Id).Count(), d.Where(diag => diag.Id == Diagnostics.PropertyNotSupported.Id).Count())); Assert.Equal(3, d.Where(diag => diag.Id == Diagnostics.TypeNotSupported.Id).Count()); diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/GeneratorTests.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/GeneratorTests.cs index 68f8a66612e67..3c1bdd4fa7951 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/GeneratorTests.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/GeneratorTests.cs @@ -376,12 +376,9 @@ private static async Task VerifyAgainstBaselineUsingFile( string filename, string testSourceCode, LanguageVersion languageVersion = LanguageVersion.Preview, - Action>? assessDiagnostics = null, - ExtensionClassType extType = ExtensionClassType.None) + Action>? assessDiagnostics = null) { - string path = extType is ExtensionClassType.None - ? Path.Combine("Baselines", filename) - : Path.Combine("Baselines", extType.ToString(), filename); + string path = Path.Combine("Baselines", filename); string baseline = LineEndingsHelper.Normalize(await File.ReadAllTextAsync(path).ConfigureAwait(false)); string[] expectedLines = baseline.Replace("%VERSION%", typeof(ConfigurationBindingGenerator).Assembly.GetName().Version?.ToString()) .Split(Environment.NewLine); diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Microsoft.Extensions.Configuration.Binder.SourceGeneration.Tests.csproj b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Microsoft.Extensions.Configuration.Binder.SourceGeneration.Tests.csproj index 94d95564a4735..9b5e69eadb77e 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Microsoft.Extensions.Configuration.Binder.SourceGeneration.Tests.csproj +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Microsoft.Extensions.Configuration.Binder.SourceGeneration.Tests.csproj @@ -31,6 +31,55 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -44,10 +93,8 @@ - + PreserveNewest From 75e001cb9bebe400a4a9a522c971661118154781 Mon Sep 17 00:00:00 2001 From: pedrobsaila Date: Tue, 29 Aug 2023 00:11:31 +0200 Subject: [PATCH 05/17] fix merge issues --- .../gen/Helpers/Emitter/Helpers.cs | 23 +++++-- .../Baselines/netcoreapp/Bind.generated.txt | 59 +++++++++------- .../BindConfiguration.generated.txt | 37 +++++----- .../netcoreapp/Bind_Instance.generated.txt | 41 ++++++------ .../Bind_Instance_BinderOptions.generated.txt | 41 ++++++------ .../Bind_Key_Instance.generated.txt | 41 ++++++------ .../Baselines/netcoreapp/Bind_T.generated.txt | 41 ++++++------ .../Bind_T_BinderOptions.generated.txt | 37 +++++----- .../netcoreapp/Collections.generated.txt | 56 ++++++++-------- .../netcoreapp/Configure_T.generated.txt | 57 ++++++++-------- .../Configure_T_BinderOptions.generated.txt | 57 ++++++++-------- .../netcoreapp/Configure_T_name.generated.txt | 57 ++++++++-------- ...nfigure_T_name_BinderOptions.generated.txt | 53 ++++++++------- .../Baselines/netcoreapp/Get.generated.txt | 50 +++++++------- .../Baselines/netcoreapp/Get_T.generated.txt | 40 +++++------ .../Get_T_BinderOptions.generated.txt | 40 +++++------ .../netcoreapp/Get_TypeOf.generated.txt | 10 +-- .../Get_TypeOf_BinderOptions.generated.txt | 10 +-- .../netcoreapp/Primitives.generated.txt | 67 ++++++++++--------- 19 files changed, 427 insertions(+), 390 deletions(-) diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/Emitter/Helpers.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/Emitter/Helpers.cs index e65b1608be5fb..1b8baef8d597a 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/Emitter/Helpers.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Helpers/Emitter/Helpers.cs @@ -215,17 +215,28 @@ private void EmitBlankLineIfRequired() private void EmitCheckForNullArgument_WithBlankLine(string paramName, bool voidReturn = false) { - string returnExpr = voidReturn - ? "return" - : $"ArgumentNullException.ThrowIfNull({paramName})"; - - _writer.WriteLine($$""" + if (voidReturn) + { + _writer.WriteLine($$""" if ({{paramName}} is null) { - {{returnExpr}}; + return; } """); } + else + { + string throwIfNullExpr = _sourceGenSpec.EmitThrowIfNullMethod + ? $"ArgumentNullException.ThrowIfNull({paramName});" + : $$""" + if ({{paramName}} is null) + { + throw new ArgumentNullException(nameof({{paramName}})); + } + """; + + _writer.WriteLine(throwIfNullExpr); + } _writer.WriteLine(); } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/Bind.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/Bind.generated.txt index d9af7ffbd32a3..078846538f1db 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/Bind.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/Bind.generated.txt @@ -32,37 +32,46 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration #region IConfiguration extensions. /// Attempts to bind the given object instance to configuration values by matching property names against configuration keys recursively. [InterceptsLocationAttribute(@"src-0.cs", 13, 18)] - public static void Bind_ProgramMyClass(this IConfiguration configuration, object? obj) + public static void Bind_ProgramMyClass(this IConfiguration configuration, object? instance) { ArgumentNullException.ThrowIfNull(configuration); - ArgumentNullException.ThrowIfNull(obj); + if (instance is null) + { + return; + } - var typedObj = (Program.MyClass)obj; + var typedObj = (Program.MyClass)instance; BindCore(configuration, ref typedObj, binderOptions: null); } /// Attempts to bind the given object instance to configuration values by matching property names against configuration keys recursively. [InterceptsLocationAttribute(@"src-0.cs", 14, 24)] - public static void Bind_ProgramMyClass(this IConfiguration configuration, object? obj, Action? configureOptions) + public static void Bind_ProgramMyClass(this IConfiguration configuration, object? instance, Action? configureOptions) { ArgumentNullException.ThrowIfNull(configuration); - ArgumentNullException.ThrowIfNull(obj); + if (instance is null) + { + return; + } - var typedObj = (Program.MyClass)obj; + var typedObj = (Program.MyClass)instance; BindCore(configuration, ref typedObj, GetBinderOptions(configureOptions)); } /// Attempts to bind the given object instance to configuration values by matching property names against configuration keys recursively. [InterceptsLocationAttribute(@"src-0.cs", 15, 24)] - public static void Bind_ProgramMyClass(this IConfiguration configuration, string key, object? obj) + public static void Bind_ProgramMyClass(this IConfiguration configuration, string key, object? instance) { ArgumentNullException.ThrowIfNull(configuration); - ArgumentNullException.ThrowIfNull(obj); + if (instance is null) + { + return; + } - var typedObj = (Program.MyClass)obj; + var typedObj = (Program.MyClass)instance; BindCore(configuration.GetSection(key), ref typedObj, binderOptions: null); } #endregion IConfiguration extensions. @@ -70,73 +79,73 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration #region Core binding extensions. private readonly static Lazy> s_configKeys_ProgramMyClass = new(() => new HashSet(StringComparer.OrdinalIgnoreCase) { "MyString", "MyInt", "MyList", "MyDictionary", "MyComplexDictionary" }); - public static void BindCore(IConfiguration configuration, ref List obj, BinderOptions? binderOptions) + public static void BindCore(IConfiguration configuration, ref List instance, BinderOptions? binderOptions) { foreach (IConfigurationSection section in configuration.GetChildren()) { if (section.Value is string value) { - obj.Add(ParseInt(value, () => section.Path)); + instance.Add(ParseInt(value, () => section.Path)); } } } - public static void BindCore(IConfiguration configuration, ref Dictionary obj, BinderOptions? binderOptions) + public static void BindCore(IConfiguration configuration, ref Dictionary instance, BinderOptions? binderOptions) { foreach (IConfigurationSection section in configuration.GetChildren()) { if (section.Value is string value) { - obj[section.Key] = value; + instance[section.Key] = value; } } } - public static void BindCore(IConfiguration configuration, ref Dictionary obj, BinderOptions? binderOptions) + public static void BindCore(IConfiguration configuration, ref Dictionary instance, BinderOptions? binderOptions) { foreach (IConfigurationSection section in configuration.GetChildren()) { - if (!(obj.TryGetValue(section.Key, out Program.MyClass2? element) && element is not null)) + if (!(instance.TryGetValue(section.Key, out Program.MyClass2? element) && element is not null)) { element = new Program.MyClass2(); } - obj[section.Key] = element; + instance[section.Key] = element; } } - public static void BindCore(IConfiguration configuration, ref Program.MyClass obj, BinderOptions? binderOptions) + public static void BindCore(IConfiguration configuration, ref Program.MyClass instance, BinderOptions? binderOptions) { ValidateConfigurationKeys(typeof(Program.MyClass), s_configKeys_ProgramMyClass, configuration, binderOptions); - obj.MyString = configuration["MyString"]!; + instance.MyString = configuration["MyString"]!; if (configuration["MyInt"] is string value1) { - obj.MyInt = ParseInt(value1, () => configuration.GetSection("MyInt").Path); + instance.MyInt = ParseInt(value1, () => configuration.GetSection("MyInt").Path); } if (AsConfigWithChildren(configuration.GetSection("MyList")) is IConfigurationSection section2) { - List? temp4 = obj.MyList; + List? temp4 = instance.MyList; temp4 ??= new List(); BindCore(section2, ref temp4, binderOptions); - obj.MyList = temp4; + instance.MyList = temp4; } if (AsConfigWithChildren(configuration.GetSection("MyDictionary")) is IConfigurationSection section5) { - Dictionary? temp7 = obj.MyDictionary; + Dictionary? temp7 = instance.MyDictionary; temp7 ??= new Dictionary(); BindCore(section5, ref temp7, binderOptions); - obj.MyDictionary = temp7; + instance.MyDictionary = temp7; } if (AsConfigWithChildren(configuration.GetSection("MyComplexDictionary")) is IConfigurationSection section8) { - Dictionary? temp10 = obj.MyComplexDictionary; + Dictionary? temp10 = instance.MyComplexDictionary; temp10 ??= new Dictionary(); BindCore(section8, ref temp10, binderOptions); - obj.MyComplexDictionary = temp10; + instance.MyComplexDictionary = temp10; } } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/BindConfiguration.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/BindConfiguration.generated.txt index e0ad6e5305813..62e6228266d16 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/BindConfiguration.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/BindConfiguration.generated.txt @@ -34,20 +34,18 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration #region OptionsBuilder extensions. /// Registers the dependency injection container to bind against the obtained from the DI service provider. [InterceptsLocationAttribute(@"src-0.cs", 12, 24)] - public static OptionsBuilder BindConfiguration(this OptionsBuilder optionsBuilder, string configSectionPath, Action? configureOptions = null) where TOptions : class + public static OptionsBuilder BindConfiguration(this OptionsBuilder optionsBuilder, string configSectionPath, Action? configureBinder = null) where TOptions : class { ArgumentNullException.ThrowIfNull(optionsBuilder); ArgumentNullException.ThrowIfNull(configSectionPath); - optionsBuilder.Configure((obj, configuration) => + optionsBuilder.Configure((instance, config) => { - ArgumentNullException.ThrowIfNull(obj); + ArgumentNullException.ThrowIfNull(config); - ArgumentNullException.ThrowIfNull(configuration); - - IConfiguration section = string.Equals(string.Empty, configSectionPath, StringComparison.OrdinalIgnoreCase) ? configuration : configuration.GetSection(configSectionPath); - BindCoreMain(section, obj, typeof(TOptions), configureOptions); + IConfiguration section = string.Equals(string.Empty, configSectionPath, StringComparison.OrdinalIgnoreCase) ? config : config.GetSection(configSectionPath); + BindCoreMain(section, instance, typeof(TOptions), configureBinder); }); optionsBuilder.Services.AddSingleton, ConfigurationChangeTokenSource>(); @@ -58,11 +56,12 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration #region Core binding extensions. private readonly static Lazy> s_configKeys_ProgramMyClass = new(() => new HashSet(StringComparer.OrdinalIgnoreCase) { "MyString", "MyInt", "MyList" }); - public static void BindCoreMain(IConfiguration configuration, object obj, Type type, Action? configureOptions) + public static void BindCoreMain(IConfiguration configuration, object instance, Type type, Action? configureOptions) { - ArgumentNullException.ThrowIfNull(configuration); - - ArgumentNullException.ThrowIfNull(obj); + if (instance is null) + { + return; + } if (!HasValueOrChildren(configuration)) { @@ -73,7 +72,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration if (type == typeof(Program.MyClass)) { - var temp = (Program.MyClass)obj; + var temp = (Program.MyClass)instance; BindCore(configuration, ref temp, binderOptions); return; } @@ -81,34 +80,34 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration throw new NotSupportedException($"Unable to bind to type '{type}': generator did not detect the type as input."); } - public static void BindCore(IConfiguration configuration, ref List obj, BinderOptions? binderOptions) + public static void BindCore(IConfiguration configuration, ref List instance, BinderOptions? binderOptions) { foreach (IConfigurationSection section in configuration.GetChildren()) { if (section.Value is string value) { - obj.Add(ParseInt(value, () => section.Path)); + instance.Add(ParseInt(value, () => section.Path)); } } } - public static void BindCore(IConfiguration configuration, ref Program.MyClass obj, BinderOptions? binderOptions) + public static void BindCore(IConfiguration configuration, ref Program.MyClass instance, BinderOptions? binderOptions) { ValidateConfigurationKeys(typeof(Program.MyClass), s_configKeys_ProgramMyClass, configuration, binderOptions); - obj.MyString = configuration["MyString"]!; + instance.MyString = configuration["MyString"]!; if (configuration["MyInt"] is string value2) { - obj.MyInt = ParseInt(value2, () => configuration.GetSection("MyInt").Path); + instance.MyInt = ParseInt(value2, () => configuration.GetSection("MyInt").Path); } if (AsConfigWithChildren(configuration.GetSection("MyList")) is IConfigurationSection section3) { - List? temp5 = obj.MyList; + List? temp5 = instance.MyList; temp5 ??= new List(); BindCore(section3, ref temp5, binderOptions); - obj.MyList = temp5; + instance.MyList = temp5; } } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/Bind_Instance.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/Bind_Instance.generated.txt index 8755ff8c2dfb0..5ee8d25e6b9a5 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/Bind_Instance.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/Bind_Instance.generated.txt @@ -32,13 +32,16 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration #region IConfiguration extensions. /// Attempts to bind the given object instance to configuration values by matching property names against configuration keys recursively. [InterceptsLocationAttribute(@"src-0.cs", 12, 20)] - public static void Bind_ProgramMyClass(this IConfiguration configuration, object? obj) + public static void Bind_ProgramMyClass(this IConfiguration configuration, object? instance) { ArgumentNullException.ThrowIfNull(configuration); - ArgumentNullException.ThrowIfNull(obj); + if (instance is null) + { + return; + } - var typedObj = (Program.MyClass)obj; + var typedObj = (Program.MyClass)instance; BindCore(configuration, ref typedObj, binderOptions: null); } #endregion IConfiguration extensions. @@ -46,73 +49,73 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration #region Core binding extensions. private readonly static Lazy> s_configKeys_ProgramMyClass = new(() => new HashSet(StringComparer.OrdinalIgnoreCase) { "MyString", "MyInt", "MyList", "MyDictionary", "MyComplexDictionary" }); - public static void BindCore(IConfiguration configuration, ref List obj, BinderOptions? binderOptions) + public static void BindCore(IConfiguration configuration, ref List instance, BinderOptions? binderOptions) { foreach (IConfigurationSection section in configuration.GetChildren()) { if (section.Value is string value) { - obj.Add(ParseInt(value, () => section.Path)); + instance.Add(ParseInt(value, () => section.Path)); } } } - public static void BindCore(IConfiguration configuration, ref Dictionary obj, BinderOptions? binderOptions) + public static void BindCore(IConfiguration configuration, ref Dictionary instance, BinderOptions? binderOptions) { foreach (IConfigurationSection section in configuration.GetChildren()) { if (section.Value is string value) { - obj[section.Key] = value; + instance[section.Key] = value; } } } - public static void BindCore(IConfiguration configuration, ref Dictionary obj, BinderOptions? binderOptions) + public static void BindCore(IConfiguration configuration, ref Dictionary instance, BinderOptions? binderOptions) { foreach (IConfigurationSection section in configuration.GetChildren()) { - if (!(obj.TryGetValue(section.Key, out Program.MyClass2? element) && element is not null)) + if (!(instance.TryGetValue(section.Key, out Program.MyClass2? element) && element is not null)) { element = new Program.MyClass2(); } - obj[section.Key] = element; + instance[section.Key] = element; } } - public static void BindCore(IConfiguration configuration, ref Program.MyClass obj, BinderOptions? binderOptions) + public static void BindCore(IConfiguration configuration, ref Program.MyClass instance, BinderOptions? binderOptions) { ValidateConfigurationKeys(typeof(Program.MyClass), s_configKeys_ProgramMyClass, configuration, binderOptions); - obj.MyString = configuration["MyString"]!; + instance.MyString = configuration["MyString"]!; if (configuration["MyInt"] is string value1) { - obj.MyInt = ParseInt(value1, () => configuration.GetSection("MyInt").Path); + instance.MyInt = ParseInt(value1, () => configuration.GetSection("MyInt").Path); } if (AsConfigWithChildren(configuration.GetSection("MyList")) is IConfigurationSection section2) { - List? temp4 = obj.MyList; + List? temp4 = instance.MyList; temp4 ??= new List(); BindCore(section2, ref temp4, binderOptions); - obj.MyList = temp4; + instance.MyList = temp4; } if (AsConfigWithChildren(configuration.GetSection("MyDictionary")) is IConfigurationSection section5) { - Dictionary? temp7 = obj.MyDictionary; + Dictionary? temp7 = instance.MyDictionary; temp7 ??= new Dictionary(); BindCore(section5, ref temp7, binderOptions); - obj.MyDictionary = temp7; + instance.MyDictionary = temp7; } if (AsConfigWithChildren(configuration.GetSection("MyComplexDictionary")) is IConfigurationSection section8) { - Dictionary? temp10 = obj.MyComplexDictionary; + Dictionary? temp10 = instance.MyComplexDictionary; temp10 ??= new Dictionary(); BindCore(section8, ref temp10, binderOptions); - obj.MyComplexDictionary = temp10; + instance.MyComplexDictionary = temp10; } } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/Bind_Instance_BinderOptions.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/Bind_Instance_BinderOptions.generated.txt index a30be1588d2f1..8d030022f5560 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/Bind_Instance_BinderOptions.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/Bind_Instance_BinderOptions.generated.txt @@ -32,13 +32,16 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration #region IConfiguration extensions. /// Attempts to bind the given object instance to configuration values by matching property names against configuration keys recursively. [InterceptsLocationAttribute(@"src-0.cs", 12, 20)] - public static void Bind_ProgramMyClass(this IConfiguration configuration, object? obj, Action? configureOptions) + public static void Bind_ProgramMyClass(this IConfiguration configuration, object? instance, Action? configureOptions) { ArgumentNullException.ThrowIfNull(configuration); - ArgumentNullException.ThrowIfNull(obj); + if (instance is null) + { + return; + } - var typedObj = (Program.MyClass)obj; + var typedObj = (Program.MyClass)instance; BindCore(configuration, ref typedObj, GetBinderOptions(configureOptions)); } #endregion IConfiguration extensions. @@ -46,73 +49,73 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration #region Core binding extensions. private readonly static Lazy> s_configKeys_ProgramMyClass = new(() => new HashSet(StringComparer.OrdinalIgnoreCase) { "MyString", "MyInt", "MyList", "MyDictionary", "MyComplexDictionary" }); - public static void BindCore(IConfiguration configuration, ref List obj, BinderOptions? binderOptions) + public static void BindCore(IConfiguration configuration, ref List instance, BinderOptions? binderOptions) { foreach (IConfigurationSection section in configuration.GetChildren()) { if (section.Value is string value) { - obj.Add(ParseInt(value, () => section.Path)); + instance.Add(ParseInt(value, () => section.Path)); } } } - public static void BindCore(IConfiguration configuration, ref Dictionary obj, BinderOptions? binderOptions) + public static void BindCore(IConfiguration configuration, ref Dictionary instance, BinderOptions? binderOptions) { foreach (IConfigurationSection section in configuration.GetChildren()) { if (section.Value is string value) { - obj[section.Key] = value; + instance[section.Key] = value; } } } - public static void BindCore(IConfiguration configuration, ref Dictionary obj, BinderOptions? binderOptions) + public static void BindCore(IConfiguration configuration, ref Dictionary instance, BinderOptions? binderOptions) { foreach (IConfigurationSection section in configuration.GetChildren()) { - if (!(obj.TryGetValue(section.Key, out Program.MyClass2? element) && element is not null)) + if (!(instance.TryGetValue(section.Key, out Program.MyClass2? element) && element is not null)) { element = new Program.MyClass2(); } - obj[section.Key] = element; + instance[section.Key] = element; } } - public static void BindCore(IConfiguration configuration, ref Program.MyClass obj, BinderOptions? binderOptions) + public static void BindCore(IConfiguration configuration, ref Program.MyClass instance, BinderOptions? binderOptions) { ValidateConfigurationKeys(typeof(Program.MyClass), s_configKeys_ProgramMyClass, configuration, binderOptions); - obj.MyString = configuration["MyString"]!; + instance.MyString = configuration["MyString"]!; if (configuration["MyInt"] is string value1) { - obj.MyInt = ParseInt(value1, () => configuration.GetSection("MyInt").Path); + instance.MyInt = ParseInt(value1, () => configuration.GetSection("MyInt").Path); } if (AsConfigWithChildren(configuration.GetSection("MyList")) is IConfigurationSection section2) { - List? temp4 = obj.MyList; + List? temp4 = instance.MyList; temp4 ??= new List(); BindCore(section2, ref temp4, binderOptions); - obj.MyList = temp4; + instance.MyList = temp4; } if (AsConfigWithChildren(configuration.GetSection("MyDictionary")) is IConfigurationSection section5) { - Dictionary? temp7 = obj.MyDictionary; + Dictionary? temp7 = instance.MyDictionary; temp7 ??= new Dictionary(); BindCore(section5, ref temp7, binderOptions); - obj.MyDictionary = temp7; + instance.MyDictionary = temp7; } if (AsConfigWithChildren(configuration.GetSection("MyComplexDictionary")) is IConfigurationSection section8) { - Dictionary? temp10 = obj.MyComplexDictionary; + Dictionary? temp10 = instance.MyComplexDictionary; temp10 ??= new Dictionary(); BindCore(section8, ref temp10, binderOptions); - obj.MyComplexDictionary = temp10; + instance.MyComplexDictionary = temp10; } } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/Bind_Key_Instance.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/Bind_Key_Instance.generated.txt index c0e00e75e8cf5..53de396b69b8a 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/Bind_Key_Instance.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/Bind_Key_Instance.generated.txt @@ -32,13 +32,16 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration #region IConfiguration extensions. /// Attempts to bind the given object instance to configuration values by matching property names against configuration keys recursively. [InterceptsLocationAttribute(@"src-0.cs", 12, 20)] - public static void Bind_ProgramMyClass(this IConfiguration configuration, string key, object? obj) + public static void Bind_ProgramMyClass(this IConfiguration configuration, string key, object? instance) { ArgumentNullException.ThrowIfNull(configuration); - ArgumentNullException.ThrowIfNull(obj); + if (instance is null) + { + return; + } - var typedObj = (Program.MyClass)obj; + var typedObj = (Program.MyClass)instance; BindCore(configuration.GetSection(key), ref typedObj, binderOptions: null); } #endregion IConfiguration extensions. @@ -46,73 +49,73 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration #region Core binding extensions. private readonly static Lazy> s_configKeys_ProgramMyClass = new(() => new HashSet(StringComparer.OrdinalIgnoreCase) { "MyString", "MyInt", "MyList", "MyDictionary", "MyComplexDictionary" }); - public static void BindCore(IConfiguration configuration, ref List obj, BinderOptions? binderOptions) + public static void BindCore(IConfiguration configuration, ref List instance, BinderOptions? binderOptions) { foreach (IConfigurationSection section in configuration.GetChildren()) { if (section.Value is string value) { - obj.Add(ParseInt(value, () => section.Path)); + instance.Add(ParseInt(value, () => section.Path)); } } } - public static void BindCore(IConfiguration configuration, ref Dictionary obj, BinderOptions? binderOptions) + public static void BindCore(IConfiguration configuration, ref Dictionary instance, BinderOptions? binderOptions) { foreach (IConfigurationSection section in configuration.GetChildren()) { if (section.Value is string value) { - obj[section.Key] = value; + instance[section.Key] = value; } } } - public static void BindCore(IConfiguration configuration, ref Dictionary obj, BinderOptions? binderOptions) + public static void BindCore(IConfiguration configuration, ref Dictionary instance, BinderOptions? binderOptions) { foreach (IConfigurationSection section in configuration.GetChildren()) { - if (!(obj.TryGetValue(section.Key, out Program.MyClass2? element) && element is not null)) + if (!(instance.TryGetValue(section.Key, out Program.MyClass2? element) && element is not null)) { element = new Program.MyClass2(); } - obj[section.Key] = element; + instance[section.Key] = element; } } - public static void BindCore(IConfiguration configuration, ref Program.MyClass obj, BinderOptions? binderOptions) + public static void BindCore(IConfiguration configuration, ref Program.MyClass instance, BinderOptions? binderOptions) { ValidateConfigurationKeys(typeof(Program.MyClass), s_configKeys_ProgramMyClass, configuration, binderOptions); - obj.MyString = configuration["MyString"]!; + instance.MyString = configuration["MyString"]!; if (configuration["MyInt"] is string value1) { - obj.MyInt = ParseInt(value1, () => configuration.GetSection("MyInt").Path); + instance.MyInt = ParseInt(value1, () => configuration.GetSection("MyInt").Path); } if (AsConfigWithChildren(configuration.GetSection("MyList")) is IConfigurationSection section2) { - List? temp4 = obj.MyList; + List? temp4 = instance.MyList; temp4 ??= new List(); BindCore(section2, ref temp4, binderOptions); - obj.MyList = temp4; + instance.MyList = temp4; } if (AsConfigWithChildren(configuration.GetSection("MyDictionary")) is IConfigurationSection section5) { - Dictionary? temp7 = obj.MyDictionary; + Dictionary? temp7 = instance.MyDictionary; temp7 ??= new Dictionary(); BindCore(section5, ref temp7, binderOptions); - obj.MyDictionary = temp7; + instance.MyDictionary = temp7; } if (AsConfigWithChildren(configuration.GetSection("MyComplexDictionary")) is IConfigurationSection section8) { - Dictionary? temp10 = obj.MyComplexDictionary; + Dictionary? temp10 = instance.MyComplexDictionary; temp10 ??= new Dictionary(); BindCore(section8, ref temp10, binderOptions); - obj.MyComplexDictionary = temp10; + instance.MyComplexDictionary = temp10; } } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/Bind_T.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/Bind_T.generated.txt index a1affe087a41b..be3d065da5f06 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/Bind_T.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/Bind_T.generated.txt @@ -34,43 +34,44 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration #region OptionsBuilder extensions. /// Registers a configuration instance which will bind against. [InterceptsLocationAttribute(@"src-0.cs", 15, 24)] - public static OptionsBuilder Bind(this OptionsBuilder optionsBuilder, IConfiguration configuration) where TOptions : class + public static OptionsBuilder Bind(this OptionsBuilder optionsBuilder, IConfiguration config) where TOptions : class { - return Bind(optionsBuilder, configuration, configureOptions: null); + return Bind(optionsBuilder, config, configureBinder: null); } /// Registers a configuration instance which will bind against. - public static OptionsBuilder Bind(this OptionsBuilder optionsBuilder, IConfiguration configuration, Action? configureOptions) where TOptions : class + public static OptionsBuilder Bind(this OptionsBuilder optionsBuilder, IConfiguration config, Action? configureBinder) where TOptions : class { ArgumentNullException.ThrowIfNull(optionsBuilder); - Configure(optionsBuilder.Services, optionsBuilder.Name, configuration, configureOptions); + Configure(optionsBuilder.Services, optionsBuilder.Name, config, configureBinder); return optionsBuilder; } #endregion OptionsBuilder extensions. #region IServiceCollection extensions. /// Registers a configuration instance which TOptions will bind against. - public static IServiceCollection Configure(this IServiceCollection services, string? name, IConfiguration configuration, Action? configureOptions) where TOptions : class + public static IServiceCollection Configure(this IServiceCollection services, string? name, IConfiguration config, Action? configureOptions) where TOptions : class { ArgumentNullException.ThrowIfNull(services); - ArgumentNullException.ThrowIfNull(configuration); + ArgumentNullException.ThrowIfNull(config); OptionsServiceCollectionExtensions.AddOptions(services); - services.AddSingleton>(new ConfigurationChangeTokenSource(name, configuration)); - return services.AddSingleton>(new Microsoft.Extensions.Options.ConfigureNamedOptions(name, obj => BindCoreMain(configuration, obj, typeof(TOptions)configureOptions))); + services.AddSingleton>(new ConfigurationChangeTokenSource(name, config)); + return services.AddSingleton>(new ConfigureNamedOptions(name, instance => BindCoreMain(config, instance, typeof(TOptions), configureOptions))); } #endregion IServiceCollection extensions. #region Core binding extensions. private readonly static Lazy> s_configKeys_ProgramMyClass = new(() => new HashSet(StringComparer.OrdinalIgnoreCase) { "MyString", "MyInt", "MyList" }); - public static void BindCoreMain(IConfiguration configuration, object obj, Type type, Action? configureOptions) + public static void BindCoreMain(IConfiguration configuration, object instance, Type type, Action? configureOptions) { - ArgumentNullException.ThrowIfNull(configuration); - - ArgumentNullException.ThrowIfNull(obj); + if (instance is null) + { + return; + } if (!HasValueOrChildren(configuration)) { @@ -81,7 +82,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration if (type == typeof(Program.MyClass)) { - var temp = (Program.MyClass)obj; + var temp = (Program.MyClass)instance; BindCore(configuration, ref temp, binderOptions); return; } @@ -89,34 +90,34 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration throw new NotSupportedException($"Unable to bind to type '{type}': generator did not detect the type as input."); } - public static void BindCore(IConfiguration configuration, ref List obj, BinderOptions? binderOptions) + public static void BindCore(IConfiguration configuration, ref List instance, BinderOptions? binderOptions) { foreach (IConfigurationSection section in configuration.GetChildren()) { if (section.Value is string value) { - obj.Add(ParseInt(value, () => section.Path)); + instance.Add(ParseInt(value, () => section.Path)); } } } - public static void BindCore(IConfiguration configuration, ref Program.MyClass obj, BinderOptions? binderOptions) + public static void BindCore(IConfiguration configuration, ref Program.MyClass instance, BinderOptions? binderOptions) { ValidateConfigurationKeys(typeof(Program.MyClass), s_configKeys_ProgramMyClass, configuration, binderOptions); - obj.MyString = configuration["MyString"]!; + instance.MyString = configuration["MyString"]!; if (configuration["MyInt"] is string value2) { - obj.MyInt = ParseInt(value2, () => configuration.GetSection("MyInt").Path); + instance.MyInt = ParseInt(value2, () => configuration.GetSection("MyInt").Path); } if (AsConfigWithChildren(configuration.GetSection("MyList")) is IConfigurationSection section3) { - List? temp5 = obj.MyList; + List? temp5 = instance.MyList; temp5 ??= new List(); BindCore(section3, ref temp5, binderOptions); - obj.MyList = temp5; + instance.MyList = temp5; } } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/Bind_T_BinderOptions.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/Bind_T_BinderOptions.generated.txt index 87ac14b5b79b8..905537274c667 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/Bind_T_BinderOptions.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/Bind_T_BinderOptions.generated.txt @@ -34,37 +34,38 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration #region OptionsBuilder extensions. /// Registers a configuration instance which will bind against. [InterceptsLocationAttribute(@"src-0.cs", 15, 24)] - public static OptionsBuilder Bind(this OptionsBuilder optionsBuilder, IConfiguration configuration, Action? configureOptions) where TOptions : class + public static OptionsBuilder Bind(this OptionsBuilder optionsBuilder, IConfiguration config, Action? configureBinder) where TOptions : class { ArgumentNullException.ThrowIfNull(optionsBuilder); - Configure(optionsBuilder.Services, optionsBuilder.Name, configuration, configureOptions); + Configure(optionsBuilder.Services, optionsBuilder.Name, config, configureBinder); return optionsBuilder; } #endregion OptionsBuilder extensions. #region IServiceCollection extensions. /// Registers a configuration instance which TOptions will bind against. - public static IServiceCollection Configure(this IServiceCollection services, string? name, IConfiguration configuration, Action? configureOptions) where TOptions : class + public static IServiceCollection Configure(this IServiceCollection services, string? name, IConfiguration config, Action? configureOptions) where TOptions : class { ArgumentNullException.ThrowIfNull(services); - ArgumentNullException.ThrowIfNull(configuration); + ArgumentNullException.ThrowIfNull(config); OptionsServiceCollectionExtensions.AddOptions(services); - services.AddSingleton>(new ConfigurationChangeTokenSource(name, configuration)); - return services.AddSingleton>(new Microsoft.Extensions.Options.ConfigureNamedOptions(name, obj => BindCoreMain(configuration, obj, typeof(TOptions)configureOptions))); + services.AddSingleton>(new ConfigurationChangeTokenSource(name, config)); + return services.AddSingleton>(new ConfigureNamedOptions(name, instance => BindCoreMain(config, instance, typeof(TOptions), configureOptions))); } #endregion IServiceCollection extensions. #region Core binding extensions. private readonly static Lazy> s_configKeys_ProgramMyClass = new(() => new HashSet(StringComparer.OrdinalIgnoreCase) { "MyString", "MyInt", "MyList" }); - public static void BindCoreMain(IConfiguration configuration, object obj, Type type, Action? configureOptions) + public static void BindCoreMain(IConfiguration configuration, object instance, Type type, Action? configureOptions) { - ArgumentNullException.ThrowIfNull(configuration); - - ArgumentNullException.ThrowIfNull(obj); + if (instance is null) + { + return; + } if (!HasValueOrChildren(configuration)) { @@ -75,7 +76,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration if (type == typeof(Program.MyClass)) { - var temp = (Program.MyClass)obj; + var temp = (Program.MyClass)instance; BindCore(configuration, ref temp, binderOptions); return; } @@ -83,34 +84,34 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration throw new NotSupportedException($"Unable to bind to type '{type}': generator did not detect the type as input."); } - public static void BindCore(IConfiguration configuration, ref List obj, BinderOptions? binderOptions) + public static void BindCore(IConfiguration configuration, ref List instance, BinderOptions? binderOptions) { foreach (IConfigurationSection section in configuration.GetChildren()) { if (section.Value is string value) { - obj.Add(ParseInt(value, () => section.Path)); + instance.Add(ParseInt(value, () => section.Path)); } } } - public static void BindCore(IConfiguration configuration, ref Program.MyClass obj, BinderOptions? binderOptions) + public static void BindCore(IConfiguration configuration, ref Program.MyClass instance, BinderOptions? binderOptions) { ValidateConfigurationKeys(typeof(Program.MyClass), s_configKeys_ProgramMyClass, configuration, binderOptions); - obj.MyString = configuration["MyString"]!; + instance.MyString = configuration["MyString"]!; if (configuration["MyInt"] is string value2) { - obj.MyInt = ParseInt(value2, () => configuration.GetSection("MyInt").Path); + instance.MyInt = ParseInt(value2, () => configuration.GetSection("MyInt").Path); } if (AsConfigWithChildren(configuration.GetSection("MyList")) is IConfigurationSection section3) { - List? temp5 = obj.MyList; + List? temp5 = instance.MyList; temp5 ??= new List(); BindCore(section3, ref temp5, binderOptions); - obj.MyList = temp5; + instance.MyList = temp5; } } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/Collections.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/Collections.generated.txt index cc89078dc8ba7..4e8e9df814c13 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/Collections.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/Collections.generated.txt @@ -52,61 +52,61 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration if (type == typeof(Program.MyClassWithCustomCollections)) { - var obj = new Program.MyClassWithCustomCollections(); - BindCore(configuration, ref obj, binderOptions); - return obj; + var instance = new Program.MyClassWithCustomCollections(); + BindCore(configuration, ref instance, binderOptions); + return instance; } throw new NotSupportedException($"Unable to bind to type '{type}': generator did not detect the type as input."); } - public static void BindCore(IConfiguration configuration, ref Program.CustomDictionary obj, BinderOptions? binderOptions) + public static void BindCore(IConfiguration configuration, ref Program.CustomDictionary instance, BinderOptions? binderOptions) { foreach (IConfigurationSection section in configuration.GetChildren()) { if (section.Value is string value) { - obj[section.Key] = ParseInt(value, () => section.Path); + instance[section.Key] = ParseInt(value, () => section.Path); } } } - public static void BindCore(IConfiguration configuration, ref Program.CustomList obj, BinderOptions? binderOptions) + public static void BindCore(IConfiguration configuration, ref Program.CustomList instance, BinderOptions? binderOptions) { foreach (IConfigurationSection section in configuration.GetChildren()) { if (section.Value is string value) { - obj.Add(value); + instance.Add(value); } } } - public static void BindCore(IConfiguration configuration, ref List obj, BinderOptions? binderOptions) + public static void BindCore(IConfiguration configuration, ref List instance, BinderOptions? binderOptions) { foreach (IConfigurationSection section in configuration.GetChildren()) { if (section.Value is string value) { - obj.Add(ParseInt(value, () => section.Path)); + instance.Add(ParseInt(value, () => section.Path)); } } } - public static void BindCore(IConfiguration configuration, ref ICollection obj, BinderOptions? binderOptions) + public static void BindCore(IConfiguration configuration, ref ICollection instance, BinderOptions? binderOptions) { foreach (IConfigurationSection section in configuration.GetChildren()) { if (section.Value is string value) { - obj.Add(ParseInt(value, () => section.Path)); + instance.Add(ParseInt(value, () => section.Path)); } } } - public static void BindCore(IConfiguration configuration, ref IReadOnlyList obj, BinderOptions? binderOptions) + public static void BindCore(IConfiguration configuration, ref IReadOnlyList instance, BinderOptions? binderOptions) { - if (obj is not ICollection temp) + if (instance is not ICollection temp) { return; } @@ -120,31 +120,31 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration } } - public static void BindCore(IConfiguration configuration, ref Dictionary obj, BinderOptions? binderOptions) + public static void BindCore(IConfiguration configuration, ref Dictionary instance, BinderOptions? binderOptions) { foreach (IConfigurationSection section in configuration.GetChildren()) { if (section.Value is string value) { - obj[section.Key] = ParseInt(value, () => section.Path); + instance[section.Key] = ParseInt(value, () => section.Path); } } } - public static void BindCore(IConfiguration configuration, ref IDictionary obj, BinderOptions? binderOptions) + public static void BindCore(IConfiguration configuration, ref IDictionary instance, BinderOptions? binderOptions) { foreach (IConfigurationSection section in configuration.GetChildren()) { if (section.Value is string value) { - obj[section.Key] = ParseInt(value, () => section.Path); + instance[section.Key] = ParseInt(value, () => section.Path); } } } - public static void BindCore(IConfiguration configuration, ref IReadOnlyDictionary obj, BinderOptions? binderOptions) + public static void BindCore(IConfiguration configuration, ref IReadOnlyDictionary instance, BinderOptions? binderOptions) { - if (obj is not IDictionary temp) + if (instance is not IDictionary temp) { return; } @@ -158,40 +158,40 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration } } - public static void BindCore(IConfiguration configuration, ref Program.MyClassWithCustomCollections obj, BinderOptions? binderOptions) + public static void BindCore(IConfiguration configuration, ref Program.MyClassWithCustomCollections instance, BinderOptions? binderOptions) { ValidateConfigurationKeys(typeof(Program.MyClassWithCustomCollections), s_configKeys_ProgramMyClassWithCustomCollections, configuration, binderOptions); if (AsConfigWithChildren(configuration.GetSection("CustomDictionary")) is IConfigurationSection section1) { - Program.CustomDictionary? temp3 = obj.CustomDictionary; + Program.CustomDictionary? temp3 = instance.CustomDictionary; temp3 ??= new Program.CustomDictionary(); BindCore(section1, ref temp3, binderOptions); - obj.CustomDictionary = temp3; + instance.CustomDictionary = temp3; } if (AsConfigWithChildren(configuration.GetSection("CustomList")) is IConfigurationSection section4) { - Program.CustomList? temp6 = obj.CustomList; + Program.CustomList? temp6 = instance.CustomList; temp6 ??= new Program.CustomList(); BindCore(section4, ref temp6, binderOptions); - obj.CustomList = temp6; + instance.CustomList = temp6; } if (AsConfigWithChildren(configuration.GetSection("IReadOnlyList")) is IConfigurationSection section7) { - IReadOnlyList? temp9 = obj.IReadOnlyList; + IReadOnlyList? temp9 = instance.IReadOnlyList; temp9 = temp9 is null ? new List() : new List(temp9); BindCore(section7, ref temp9, binderOptions); - obj.IReadOnlyList = temp9; + instance.IReadOnlyList = temp9; } if (AsConfigWithChildren(configuration.GetSection("IReadOnlyDictionary")) is IConfigurationSection section10) { - IReadOnlyDictionary? temp12 = obj.IReadOnlyDictionary; + IReadOnlyDictionary? temp12 = instance.IReadOnlyDictionary; temp12 = temp12 is null ? new Dictionary() : temp12.ToDictionary(pair => pair.Key, pair => pair.Value); BindCore(section10, ref temp12, binderOptions); - obj.IReadOnlyDictionary = temp12; + instance.IReadOnlyDictionary = temp12; } } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/Configure_T.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/Configure_T.generated.txt index d76bec8b028e5..60da6ae0b0b45 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/Configure_T.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/Configure_T.generated.txt @@ -33,21 +33,21 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration #region IServiceCollection extensions. /// Registers a configuration instance which TOptions will bind against. [InterceptsLocationAttribute(@"src-0.cs", 14, 18)] - public static IServiceCollection Configure(this IServiceCollection services, IConfiguration configuration) where TOptions : class + public static IServiceCollection Configure(this IServiceCollection services, IConfiguration config) where TOptions : class { - return Configure(services, string.Empty, configuration, configureOptions: null); + return Configure(services, string.Empty, config, configureOptions: null); } /// Registers a configuration instance which TOptions will bind against. - public static IServiceCollection Configure(this IServiceCollection services, string? name, IConfiguration configuration, Action? configureOptions) where TOptions : class + public static IServiceCollection Configure(this IServiceCollection services, string? name, IConfiguration config, Action? configureOptions) where TOptions : class { ArgumentNullException.ThrowIfNull(services); - ArgumentNullException.ThrowIfNull(configuration); + ArgumentNullException.ThrowIfNull(config); OptionsServiceCollectionExtensions.AddOptions(services); - services.AddSingleton>(new ConfigurationChangeTokenSource(name, configuration)); - return services.AddSingleton>(new Microsoft.Extensions.Options.ConfigureNamedOptions(name, obj => BindCoreMain(configuration, obj, typeof(TOptions)configureOptions))); + services.AddSingleton>(new ConfigurationChangeTokenSource(name, config)); + return services.AddSingleton>(new ConfigureNamedOptions(name, instance => BindCoreMain(config, instance, typeof(TOptions), configureOptions))); } #endregion IServiceCollection extensions. @@ -55,11 +55,12 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration private readonly static Lazy> s_configKeys_ProgramMyClass2 = new(() => new HashSet(StringComparer.OrdinalIgnoreCase) { "MyInt" }); private readonly static Lazy> s_configKeys_ProgramMyClass = new(() => new HashSet(StringComparer.OrdinalIgnoreCase) { "MyString", "MyInt", "MyList", "MyList2", "MyDictionary" }); - public static void BindCoreMain(IConfiguration configuration, object obj, Type type, Action? configureOptions) + public static void BindCoreMain(IConfiguration configuration, object instance, Type type, Action? configureOptions) { - ArgumentNullException.ThrowIfNull(configuration); - - ArgumentNullException.ThrowIfNull(obj); + if (instance is null) + { + return; + } if (!HasValueOrChildren(configuration)) { @@ -70,7 +71,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration if (type == typeof(Program.MyClass)) { - var temp = (Program.MyClass)obj; + var temp = (Program.MyClass)instance; BindCore(configuration, ref temp, binderOptions); return; } @@ -78,81 +79,81 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration throw new NotSupportedException($"Unable to bind to type '{type}': generator did not detect the type as input."); } - public static void BindCore(IConfiguration configuration, ref List obj, BinderOptions? binderOptions) + public static void BindCore(IConfiguration configuration, ref List instance, BinderOptions? binderOptions) { foreach (IConfigurationSection section in configuration.GetChildren()) { if (section.Value is string value) { - obj.Add(ParseInt(value, () => section.Path)); + instance.Add(ParseInt(value, () => section.Path)); } } } - public static void BindCore(IConfiguration configuration, ref Program.MyClass2 obj, BinderOptions? binderOptions) + public static void BindCore(IConfiguration configuration, ref Program.MyClass2 instance, BinderOptions? binderOptions) { ValidateConfigurationKeys(typeof(Program.MyClass2), s_configKeys_ProgramMyClass2, configuration, binderOptions); if (configuration["MyInt"] is string value1) { - obj.MyInt = ParseInt(value1, () => configuration.GetSection("MyInt").Path); + instance.MyInt = ParseInt(value1, () => configuration.GetSection("MyInt").Path); } } - public static void BindCore(IConfiguration configuration, ref List obj, BinderOptions? binderOptions) + public static void BindCore(IConfiguration configuration, ref List instance, BinderOptions? binderOptions) { foreach (IConfigurationSection section in configuration.GetChildren()) { var value = new Program.MyClass2(); BindCore(section, ref value, binderOptions); - obj.Add(value); + instance.Add(value); } } - public static void BindCore(IConfiguration configuration, ref Dictionary obj, BinderOptions? binderOptions) + public static void BindCore(IConfiguration configuration, ref Dictionary instance, BinderOptions? binderOptions) { foreach (IConfigurationSection section in configuration.GetChildren()) { if (section.Value is string value) { - obj[section.Key] = value; + instance[section.Key] = value; } } } - public static void BindCore(IConfiguration configuration, ref Program.MyClass obj, BinderOptions? binderOptions) + public static void BindCore(IConfiguration configuration, ref Program.MyClass instance, BinderOptions? binderOptions) { ValidateConfigurationKeys(typeof(Program.MyClass), s_configKeys_ProgramMyClass, configuration, binderOptions); - obj.MyString = configuration["MyString"]!; + instance.MyString = configuration["MyString"]!; if (configuration["MyInt"] is string value4) { - obj.MyInt = ParseInt(value4, () => configuration.GetSection("MyInt").Path); + instance.MyInt = ParseInt(value4, () => configuration.GetSection("MyInt").Path); } if (AsConfigWithChildren(configuration.GetSection("MyList")) is IConfigurationSection section5) { - List? temp7 = obj.MyList; + List? temp7 = instance.MyList; temp7 ??= new List(); BindCore(section5, ref temp7, binderOptions); - obj.MyList = temp7; + instance.MyList = temp7; } if (AsConfigWithChildren(configuration.GetSection("MyList2")) is IConfigurationSection section8) { - List? temp10 = obj.MyList2; + List? temp10 = instance.MyList2; temp10 ??= new List(); BindCore(section8, ref temp10, binderOptions); - obj.MyList2 = temp10; + instance.MyList2 = temp10; } if (AsConfigWithChildren(configuration.GetSection("MyDictionary")) is IConfigurationSection section11) { - Dictionary? temp13 = obj.MyDictionary; + Dictionary? temp13 = instance.MyDictionary; temp13 ??= new Dictionary(); BindCore(section11, ref temp13, binderOptions); - obj.MyDictionary = temp13; + instance.MyDictionary = temp13; } } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/Configure_T_BinderOptions.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/Configure_T_BinderOptions.generated.txt index 5db96a8d37734..682131e6f2e97 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/Configure_T_BinderOptions.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/Configure_T_BinderOptions.generated.txt @@ -33,21 +33,21 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration #region IServiceCollection extensions. /// Registers a configuration instance which TOptions will bind against. [InterceptsLocationAttribute(@"src-0.cs", 14, 18)] - public static IServiceCollection Configure(this IServiceCollection services, IConfiguration configuration, Action? configureOptions) where TOptions : class + public static IServiceCollection Configure(this IServiceCollection services, IConfiguration config, Action? configureOptions) where TOptions : class { - return Configure(services, string.Empty, configuration, configureOptions); + return Configure(services, string.Empty, config, configureOptions); } /// Registers a configuration instance which TOptions will bind against. - public static IServiceCollection Configure(this IServiceCollection services, string? name, IConfiguration configuration, Action? configureOptions) where TOptions : class + public static IServiceCollection Configure(this IServiceCollection services, string? name, IConfiguration config, Action? configureOptions) where TOptions : class { ArgumentNullException.ThrowIfNull(services); - ArgumentNullException.ThrowIfNull(configuration); + ArgumentNullException.ThrowIfNull(config); OptionsServiceCollectionExtensions.AddOptions(services); - services.AddSingleton>(new ConfigurationChangeTokenSource(name, configuration)); - return services.AddSingleton>(new Microsoft.Extensions.Options.ConfigureNamedOptions(name, obj => BindCoreMain(configuration, obj, typeof(TOptions)configureOptions))); + services.AddSingleton>(new ConfigurationChangeTokenSource(name, config)); + return services.AddSingleton>(new ConfigureNamedOptions(name, instance => BindCoreMain(config, instance, typeof(TOptions), configureOptions))); } #endregion IServiceCollection extensions. @@ -55,11 +55,12 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration private readonly static Lazy> s_configKeys_ProgramMyClass2 = new(() => new HashSet(StringComparer.OrdinalIgnoreCase) { "MyInt" }); private readonly static Lazy> s_configKeys_ProgramMyClass = new(() => new HashSet(StringComparer.OrdinalIgnoreCase) { "MyString", "MyInt", "MyList", "MyList2", "MyDictionary" }); - public static void BindCoreMain(IConfiguration configuration, object obj, Type type, Action? configureOptions) + public static void BindCoreMain(IConfiguration configuration, object instance, Type type, Action? configureOptions) { - ArgumentNullException.ThrowIfNull(configuration); - - ArgumentNullException.ThrowIfNull(obj); + if (instance is null) + { + return; + } if (!HasValueOrChildren(configuration)) { @@ -70,7 +71,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration if (type == typeof(Program.MyClass)) { - var temp = (Program.MyClass)obj; + var temp = (Program.MyClass)instance; BindCore(configuration, ref temp, binderOptions); return; } @@ -78,81 +79,81 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration throw new NotSupportedException($"Unable to bind to type '{type}': generator did not detect the type as input."); } - public static void BindCore(IConfiguration configuration, ref List obj, BinderOptions? binderOptions) + public static void BindCore(IConfiguration configuration, ref List instance, BinderOptions? binderOptions) { foreach (IConfigurationSection section in configuration.GetChildren()) { if (section.Value is string value) { - obj.Add(ParseInt(value, () => section.Path)); + instance.Add(ParseInt(value, () => section.Path)); } } } - public static void BindCore(IConfiguration configuration, ref Program.MyClass2 obj, BinderOptions? binderOptions) + public static void BindCore(IConfiguration configuration, ref Program.MyClass2 instance, BinderOptions? binderOptions) { ValidateConfigurationKeys(typeof(Program.MyClass2), s_configKeys_ProgramMyClass2, configuration, binderOptions); if (configuration["MyInt"] is string value1) { - obj.MyInt = ParseInt(value1, () => configuration.GetSection("MyInt").Path); + instance.MyInt = ParseInt(value1, () => configuration.GetSection("MyInt").Path); } } - public static void BindCore(IConfiguration configuration, ref List obj, BinderOptions? binderOptions) + public static void BindCore(IConfiguration configuration, ref List instance, BinderOptions? binderOptions) { foreach (IConfigurationSection section in configuration.GetChildren()) { var value = new Program.MyClass2(); BindCore(section, ref value, binderOptions); - obj.Add(value); + instance.Add(value); } } - public static void BindCore(IConfiguration configuration, ref Dictionary obj, BinderOptions? binderOptions) + public static void BindCore(IConfiguration configuration, ref Dictionary instance, BinderOptions? binderOptions) { foreach (IConfigurationSection section in configuration.GetChildren()) { if (section.Value is string value) { - obj[section.Key] = value; + instance[section.Key] = value; } } } - public static void BindCore(IConfiguration configuration, ref Program.MyClass obj, BinderOptions? binderOptions) + public static void BindCore(IConfiguration configuration, ref Program.MyClass instance, BinderOptions? binderOptions) { ValidateConfigurationKeys(typeof(Program.MyClass), s_configKeys_ProgramMyClass, configuration, binderOptions); - obj.MyString = configuration["MyString"]!; + instance.MyString = configuration["MyString"]!; if (configuration["MyInt"] is string value4) { - obj.MyInt = ParseInt(value4, () => configuration.GetSection("MyInt").Path); + instance.MyInt = ParseInt(value4, () => configuration.GetSection("MyInt").Path); } if (AsConfigWithChildren(configuration.GetSection("MyList")) is IConfigurationSection section5) { - List? temp7 = obj.MyList; + List? temp7 = instance.MyList; temp7 ??= new List(); BindCore(section5, ref temp7, binderOptions); - obj.MyList = temp7; + instance.MyList = temp7; } if (AsConfigWithChildren(configuration.GetSection("MyList2")) is IConfigurationSection section8) { - List? temp10 = obj.MyList2; + List? temp10 = instance.MyList2; temp10 ??= new List(); BindCore(section8, ref temp10, binderOptions); - obj.MyList2 = temp10; + instance.MyList2 = temp10; } if (AsConfigWithChildren(configuration.GetSection("MyDictionary")) is IConfigurationSection section11) { - Dictionary? temp13 = obj.MyDictionary; + Dictionary? temp13 = instance.MyDictionary; temp13 ??= new Dictionary(); BindCore(section11, ref temp13, binderOptions); - obj.MyDictionary = temp13; + instance.MyDictionary = temp13; } } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/Configure_T_name.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/Configure_T_name.generated.txt index 6fdb013b0899c..417c7a8dfb9ad 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/Configure_T_name.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/Configure_T_name.generated.txt @@ -33,21 +33,21 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration #region IServiceCollection extensions. /// Registers a configuration instance which TOptions will bind against. [InterceptsLocationAttribute(@"src-0.cs", 14, 18)] - public static IServiceCollection Configure(this IServiceCollection services, string? name, IConfiguration configuration) where TOptions : class + public static IServiceCollection Configure(this IServiceCollection services, string? name, IConfiguration config) where TOptions : class { - return Configure(services, name, configuration, configureOptions: null); + return Configure(services, name, config, configureOptions: null); } /// Registers a configuration instance which TOptions will bind against. - public static IServiceCollection Configure(this IServiceCollection services, string? name, IConfiguration configuration, Action? configureOptions) where TOptions : class + public static IServiceCollection Configure(this IServiceCollection services, string? name, IConfiguration config, Action? configureOptions) where TOptions : class { ArgumentNullException.ThrowIfNull(services); - ArgumentNullException.ThrowIfNull(configuration); + ArgumentNullException.ThrowIfNull(config); OptionsServiceCollectionExtensions.AddOptions(services); - services.AddSingleton>(new ConfigurationChangeTokenSource(name, configuration)); - return services.AddSingleton>(new Microsoft.Extensions.Options.ConfigureNamedOptions(name, obj => BindCoreMain(configuration, obj, typeof(TOptions)configureOptions))); + services.AddSingleton>(new ConfigurationChangeTokenSource(name, config)); + return services.AddSingleton>(new ConfigureNamedOptions(name, instance => BindCoreMain(config, instance, typeof(TOptions), configureOptions))); } #endregion IServiceCollection extensions. @@ -55,11 +55,12 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration private readonly static Lazy> s_configKeys_ProgramMyClass2 = new(() => new HashSet(StringComparer.OrdinalIgnoreCase) { "MyInt" }); private readonly static Lazy> s_configKeys_ProgramMyClass = new(() => new HashSet(StringComparer.OrdinalIgnoreCase) { "MyString", "MyInt", "MyList", "MyList2", "MyDictionary" }); - public static void BindCoreMain(IConfiguration configuration, object obj, Type type, Action? configureOptions) + public static void BindCoreMain(IConfiguration configuration, object instance, Type type, Action? configureOptions) { - ArgumentNullException.ThrowIfNull(configuration); - - ArgumentNullException.ThrowIfNull(obj); + if (instance is null) + { + return; + } if (!HasValueOrChildren(configuration)) { @@ -70,7 +71,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration if (type == typeof(Program.MyClass)) { - var temp = (Program.MyClass)obj; + var temp = (Program.MyClass)instance; BindCore(configuration, ref temp, binderOptions); return; } @@ -78,81 +79,81 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration throw new NotSupportedException($"Unable to bind to type '{type}': generator did not detect the type as input."); } - public static void BindCore(IConfiguration configuration, ref List obj, BinderOptions? binderOptions) + public static void BindCore(IConfiguration configuration, ref List instance, BinderOptions? binderOptions) { foreach (IConfigurationSection section in configuration.GetChildren()) { if (section.Value is string value) { - obj.Add(ParseInt(value, () => section.Path)); + instance.Add(ParseInt(value, () => section.Path)); } } } - public static void BindCore(IConfiguration configuration, ref Program.MyClass2 obj, BinderOptions? binderOptions) + public static void BindCore(IConfiguration configuration, ref Program.MyClass2 instance, BinderOptions? binderOptions) { ValidateConfigurationKeys(typeof(Program.MyClass2), s_configKeys_ProgramMyClass2, configuration, binderOptions); if (configuration["MyInt"] is string value1) { - obj.MyInt = ParseInt(value1, () => configuration.GetSection("MyInt").Path); + instance.MyInt = ParseInt(value1, () => configuration.GetSection("MyInt").Path); } } - public static void BindCore(IConfiguration configuration, ref List obj, BinderOptions? binderOptions) + public static void BindCore(IConfiguration configuration, ref List instance, BinderOptions? binderOptions) { foreach (IConfigurationSection section in configuration.GetChildren()) { var value = new Program.MyClass2(); BindCore(section, ref value, binderOptions); - obj.Add(value); + instance.Add(value); } } - public static void BindCore(IConfiguration configuration, ref Dictionary obj, BinderOptions? binderOptions) + public static void BindCore(IConfiguration configuration, ref Dictionary instance, BinderOptions? binderOptions) { foreach (IConfigurationSection section in configuration.GetChildren()) { if (section.Value is string value) { - obj[section.Key] = value; + instance[section.Key] = value; } } } - public static void BindCore(IConfiguration configuration, ref Program.MyClass obj, BinderOptions? binderOptions) + public static void BindCore(IConfiguration configuration, ref Program.MyClass instance, BinderOptions? binderOptions) { ValidateConfigurationKeys(typeof(Program.MyClass), s_configKeys_ProgramMyClass, configuration, binderOptions); - obj.MyString = configuration["MyString"]!; + instance.MyString = configuration["MyString"]!; if (configuration["MyInt"] is string value4) { - obj.MyInt = ParseInt(value4, () => configuration.GetSection("MyInt").Path); + instance.MyInt = ParseInt(value4, () => configuration.GetSection("MyInt").Path); } if (AsConfigWithChildren(configuration.GetSection("MyList")) is IConfigurationSection section5) { - List? temp7 = obj.MyList; + List? temp7 = instance.MyList; temp7 ??= new List(); BindCore(section5, ref temp7, binderOptions); - obj.MyList = temp7; + instance.MyList = temp7; } if (AsConfigWithChildren(configuration.GetSection("MyList2")) is IConfigurationSection section8) { - List? temp10 = obj.MyList2; + List? temp10 = instance.MyList2; temp10 ??= new List(); BindCore(section8, ref temp10, binderOptions); - obj.MyList2 = temp10; + instance.MyList2 = temp10; } if (AsConfigWithChildren(configuration.GetSection("MyDictionary")) is IConfigurationSection section11) { - Dictionary? temp13 = obj.MyDictionary; + Dictionary? temp13 = instance.MyDictionary; temp13 ??= new Dictionary(); BindCore(section11, ref temp13, binderOptions); - obj.MyDictionary = temp13; + instance.MyDictionary = temp13; } } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/Configure_T_name_BinderOptions.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/Configure_T_name_BinderOptions.generated.txt index 54700e205e607..60927f977deb1 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/Configure_T_name_BinderOptions.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/Configure_T_name_BinderOptions.generated.txt @@ -33,15 +33,15 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration #region IServiceCollection extensions. /// Registers a configuration instance which TOptions will bind against. [InterceptsLocationAttribute(@"src-0.cs", 14, 18)] - public static IServiceCollection Configure(this IServiceCollection services, string? name, IConfiguration configuration, Action? configureOptions) where TOptions : class + public static IServiceCollection Configure(this IServiceCollection services, string? name, IConfiguration config, Action? configureOptions) where TOptions : class { ArgumentNullException.ThrowIfNull(services); - ArgumentNullException.ThrowIfNull(configuration); + ArgumentNullException.ThrowIfNull(config); OptionsServiceCollectionExtensions.AddOptions(services); - services.AddSingleton>(new ConfigurationChangeTokenSource(name, configuration)); - return services.AddSingleton>(new Microsoft.Extensions.Options.ConfigureNamedOptions(name, obj => BindCoreMain(configuration, obj, typeof(TOptions)configureOptions))); + services.AddSingleton>(new ConfigurationChangeTokenSource(name, config)); + return services.AddSingleton>(new ConfigureNamedOptions(name, instance => BindCoreMain(config, instance, typeof(TOptions), configureOptions))); } #endregion IServiceCollection extensions. @@ -49,11 +49,12 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration private readonly static Lazy> s_configKeys_ProgramMyClass2 = new(() => new HashSet(StringComparer.OrdinalIgnoreCase) { "MyInt" }); private readonly static Lazy> s_configKeys_ProgramMyClass = new(() => new HashSet(StringComparer.OrdinalIgnoreCase) { "MyString", "MyInt", "MyList", "MyList2", "MyDictionary" }); - public static void BindCoreMain(IConfiguration configuration, object obj, Type type, Action? configureOptions) + public static void BindCoreMain(IConfiguration configuration, object instance, Type type, Action? configureOptions) { - ArgumentNullException.ThrowIfNull(configuration); - - ArgumentNullException.ThrowIfNull(obj); + if (instance is null) + { + return; + } if (!HasValueOrChildren(configuration)) { @@ -64,7 +65,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration if (type == typeof(Program.MyClass)) { - var temp = (Program.MyClass)obj; + var temp = (Program.MyClass)instance; BindCore(configuration, ref temp, binderOptions); return; } @@ -72,81 +73,81 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration throw new NotSupportedException($"Unable to bind to type '{type}': generator did not detect the type as input."); } - public static void BindCore(IConfiguration configuration, ref List obj, BinderOptions? binderOptions) + public static void BindCore(IConfiguration configuration, ref List instance, BinderOptions? binderOptions) { foreach (IConfigurationSection section in configuration.GetChildren()) { if (section.Value is string value) { - obj.Add(ParseInt(value, () => section.Path)); + instance.Add(ParseInt(value, () => section.Path)); } } } - public static void BindCore(IConfiguration configuration, ref Program.MyClass2 obj, BinderOptions? binderOptions) + public static void BindCore(IConfiguration configuration, ref Program.MyClass2 instance, BinderOptions? binderOptions) { ValidateConfigurationKeys(typeof(Program.MyClass2), s_configKeys_ProgramMyClass2, configuration, binderOptions); if (configuration["MyInt"] is string value1) { - obj.MyInt = ParseInt(value1, () => configuration.GetSection("MyInt").Path); + instance.MyInt = ParseInt(value1, () => configuration.GetSection("MyInt").Path); } } - public static void BindCore(IConfiguration configuration, ref List obj, BinderOptions? binderOptions) + public static void BindCore(IConfiguration configuration, ref List instance, BinderOptions? binderOptions) { foreach (IConfigurationSection section in configuration.GetChildren()) { var value = new Program.MyClass2(); BindCore(section, ref value, binderOptions); - obj.Add(value); + instance.Add(value); } } - public static void BindCore(IConfiguration configuration, ref Dictionary obj, BinderOptions? binderOptions) + public static void BindCore(IConfiguration configuration, ref Dictionary instance, BinderOptions? binderOptions) { foreach (IConfigurationSection section in configuration.GetChildren()) { if (section.Value is string value) { - obj[section.Key] = value; + instance[section.Key] = value; } } } - public static void BindCore(IConfiguration configuration, ref Program.MyClass obj, BinderOptions? binderOptions) + public static void BindCore(IConfiguration configuration, ref Program.MyClass instance, BinderOptions? binderOptions) { ValidateConfigurationKeys(typeof(Program.MyClass), s_configKeys_ProgramMyClass, configuration, binderOptions); - obj.MyString = configuration["MyString"]!; + instance.MyString = configuration["MyString"]!; if (configuration["MyInt"] is string value4) { - obj.MyInt = ParseInt(value4, () => configuration.GetSection("MyInt").Path); + instance.MyInt = ParseInt(value4, () => configuration.GetSection("MyInt").Path); } if (AsConfigWithChildren(configuration.GetSection("MyList")) is IConfigurationSection section5) { - List? temp7 = obj.MyList; + List? temp7 = instance.MyList; temp7 ??= new List(); BindCore(section5, ref temp7, binderOptions); - obj.MyList = temp7; + instance.MyList = temp7; } if (AsConfigWithChildren(configuration.GetSection("MyList2")) is IConfigurationSection section8) { - List? temp10 = obj.MyList2; + List? temp10 = instance.MyList2; temp10 ??= new List(); BindCore(section8, ref temp10, binderOptions); - obj.MyList2 = temp10; + instance.MyList2 = temp10; } if (AsConfigWithChildren(configuration.GetSection("MyDictionary")) is IConfigurationSection section11) { - Dictionary? temp13 = obj.MyDictionary; + Dictionary? temp13 = instance.MyDictionary; temp13 ??= new Dictionary(); BindCore(section11, ref temp13, binderOptions); - obj.MyDictionary = temp13; + instance.MyDictionary = temp13; } } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/Get.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/Get.generated.txt index 086b53ffb5d02..eb07147617d7a 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/Get.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/Get.generated.txt @@ -64,94 +64,94 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration if (type == typeof(Program.MyClass)) { - var obj = new Program.MyClass(); - BindCore(configuration, ref obj, binderOptions); - return obj; + var instance = new Program.MyClass(); + BindCore(configuration, ref instance, binderOptions); + return instance; } else if (type == typeof(Program.MyClass2)) { - var obj = new Program.MyClass2(); - BindCore(configuration, ref obj, binderOptions); - return obj; + var instance = new Program.MyClass2(); + BindCore(configuration, ref instance, binderOptions); + return instance; } throw new NotSupportedException($"Unable to bind to type '{type}': generator did not detect the type as input."); } - public static void BindCore(IConfiguration configuration, ref List obj, BinderOptions? binderOptions) + public static void BindCore(IConfiguration configuration, ref List instance, BinderOptions? binderOptions) { foreach (IConfigurationSection section in configuration.GetChildren()) { if (section.Value is string value) { - obj.Add(ParseInt(value, () => section.Path)); + instance.Add(ParseInt(value, () => section.Path)); } } } - public static void BindCore(IConfiguration configuration, ref int[] obj, BinderOptions? binderOptions) + public static void BindCore(IConfiguration configuration, ref int[] instance, BinderOptions? binderOptions) { var temp2 = new List(); BindCore(configuration, ref temp2, binderOptions); - int originalCount = obj.Length; - Array.Resize(ref obj, originalCount + temp2.Count); - temp2.CopyTo(obj, originalCount); + int originalCount = instance.Length; + Array.Resize(ref instance, originalCount + temp2.Count); + temp2.CopyTo(instance, originalCount); } - public static void BindCore(IConfiguration configuration, ref Dictionary obj, BinderOptions? binderOptions) + public static void BindCore(IConfiguration configuration, ref Dictionary instance, BinderOptions? binderOptions) { foreach (IConfigurationSection section in configuration.GetChildren()) { if (section.Value is string value) { - obj[section.Key] = value; + instance[section.Key] = value; } } } - public static void BindCore(IConfiguration configuration, ref Program.MyClass obj, BinderOptions? binderOptions) + public static void BindCore(IConfiguration configuration, ref Program.MyClass instance, BinderOptions? binderOptions) { ValidateConfigurationKeys(typeof(Program.MyClass), s_configKeys_ProgramMyClass, configuration, binderOptions); - obj.MyString = configuration["MyString"]!; + instance.MyString = configuration["MyString"]!; if (configuration["MyInt"] is string value5) { - obj.MyInt = ParseInt(value5, () => configuration.GetSection("MyInt").Path); + instance.MyInt = ParseInt(value5, () => configuration.GetSection("MyInt").Path); } if (AsConfigWithChildren(configuration.GetSection("MyList")) is IConfigurationSection section6) { - List? temp8 = obj.MyList; + List? temp8 = instance.MyList; temp8 ??= new List(); BindCore(section6, ref temp8, binderOptions); - obj.MyList = temp8; + instance.MyList = temp8; } if (AsConfigWithChildren(configuration.GetSection("MyArray")) is IConfigurationSection section9) { - int[]? temp11 = obj.MyArray; + int[]? temp11 = instance.MyArray; temp11 ??= new int[0]; BindCore(section9, ref temp11, binderOptions); - obj.MyArray = temp11; + instance.MyArray = temp11; } if (AsConfigWithChildren(configuration.GetSection("MyDictionary")) is IConfigurationSection section12) { - Dictionary? temp14 = obj.MyDictionary; + Dictionary? temp14 = instance.MyDictionary; temp14 ??= new Dictionary(); BindCore(section12, ref temp14, binderOptions); - obj.MyDictionary = temp14; + instance.MyDictionary = temp14; } } - public static void BindCore(IConfiguration configuration, ref Program.MyClass2 obj, BinderOptions? binderOptions) + public static void BindCore(IConfiguration configuration, ref Program.MyClass2 instance, BinderOptions? binderOptions) { ValidateConfigurationKeys(typeof(Program.MyClass2), s_configKeys_ProgramMyClass2, configuration, binderOptions); if (configuration["MyInt"] is string value15) { - obj.MyInt = ParseInt(value15, () => configuration.GetSection("MyInt").Path); + instance.MyInt = ParseInt(value15, () => configuration.GetSection("MyInt").Path); } } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/Get_T.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/Get_T.generated.txt index 7f0927705f914..f7fa75a30e791 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/Get_T.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/Get_T.generated.txt @@ -51,78 +51,78 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration if (type == typeof(Program.MyClass)) { - var obj = new Program.MyClass(); - BindCore(configuration, ref obj, binderOptions); - return obj; + var instance = new Program.MyClass(); + BindCore(configuration, ref instance, binderOptions); + return instance; } throw new NotSupportedException($"Unable to bind to type '{type}': generator did not detect the type as input."); } - public static void BindCore(IConfiguration configuration, ref List obj, BinderOptions? binderOptions) + public static void BindCore(IConfiguration configuration, ref List instance, BinderOptions? binderOptions) { foreach (IConfigurationSection section in configuration.GetChildren()) { if (section.Value is string value) { - obj.Add(ParseInt(value, () => section.Path)); + instance.Add(ParseInt(value, () => section.Path)); } } } - public static void BindCore(IConfiguration configuration, ref int[] obj, BinderOptions? binderOptions) + public static void BindCore(IConfiguration configuration, ref int[] instance, BinderOptions? binderOptions) { var temp1 = new List(); BindCore(configuration, ref temp1, binderOptions); - int originalCount = obj.Length; - Array.Resize(ref obj, originalCount + temp1.Count); - temp1.CopyTo(obj, originalCount); + int originalCount = instance.Length; + Array.Resize(ref instance, originalCount + temp1.Count); + temp1.CopyTo(instance, originalCount); } - public static void BindCore(IConfiguration configuration, ref Dictionary obj, BinderOptions? binderOptions) + public static void BindCore(IConfiguration configuration, ref Dictionary instance, BinderOptions? binderOptions) { foreach (IConfigurationSection section in configuration.GetChildren()) { if (section.Value is string value) { - obj[section.Key] = value; + instance[section.Key] = value; } } } - public static void BindCore(IConfiguration configuration, ref Program.MyClass obj, BinderOptions? binderOptions) + public static void BindCore(IConfiguration configuration, ref Program.MyClass instance, BinderOptions? binderOptions) { ValidateConfigurationKeys(typeof(Program.MyClass), s_configKeys_ProgramMyClass, configuration, binderOptions); - obj.MyString = configuration["MyString"]!; + instance.MyString = configuration["MyString"]!; if (configuration["MyInt"] is string value4) { - obj.MyInt = ParseInt(value4, () => configuration.GetSection("MyInt").Path); + instance.MyInt = ParseInt(value4, () => configuration.GetSection("MyInt").Path); } if (AsConfigWithChildren(configuration.GetSection("MyList")) is IConfigurationSection section5) { - List? temp7 = obj.MyList; + List? temp7 = instance.MyList; temp7 ??= new List(); BindCore(section5, ref temp7, binderOptions); - obj.MyList = temp7; + instance.MyList = temp7; } if (AsConfigWithChildren(configuration.GetSection("MyArray")) is IConfigurationSection section8) { - int[]? temp10 = obj.MyArray; + int[]? temp10 = instance.MyArray; temp10 ??= new int[0]; BindCore(section8, ref temp10, binderOptions); - obj.MyArray = temp10; + instance.MyArray = temp10; } if (AsConfigWithChildren(configuration.GetSection("MyDictionary")) is IConfigurationSection section11) { - Dictionary? temp13 = obj.MyDictionary; + Dictionary? temp13 = instance.MyDictionary; temp13 ??= new Dictionary(); BindCore(section11, ref temp13, binderOptions); - obj.MyDictionary = temp13; + instance.MyDictionary = temp13; } } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/Get_T_BinderOptions.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/Get_T_BinderOptions.generated.txt index 911a6d894a4ac..21475909d4447 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/Get_T_BinderOptions.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/Get_T_BinderOptions.generated.txt @@ -51,78 +51,78 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration if (type == typeof(Program.MyClass)) { - var obj = new Program.MyClass(); - BindCore(configuration, ref obj, binderOptions); - return obj; + var instance = new Program.MyClass(); + BindCore(configuration, ref instance, binderOptions); + return instance; } throw new NotSupportedException($"Unable to bind to type '{type}': generator did not detect the type as input."); } - public static void BindCore(IConfiguration configuration, ref List obj, BinderOptions? binderOptions) + public static void BindCore(IConfiguration configuration, ref List instance, BinderOptions? binderOptions) { foreach (IConfigurationSection section in configuration.GetChildren()) { if (section.Value is string value) { - obj.Add(ParseInt(value, () => section.Path)); + instance.Add(ParseInt(value, () => section.Path)); } } } - public static void BindCore(IConfiguration configuration, ref int[] obj, BinderOptions? binderOptions) + public static void BindCore(IConfiguration configuration, ref int[] instance, BinderOptions? binderOptions) { var temp1 = new List(); BindCore(configuration, ref temp1, binderOptions); - int originalCount = obj.Length; - Array.Resize(ref obj, originalCount + temp1.Count); - temp1.CopyTo(obj, originalCount); + int originalCount = instance.Length; + Array.Resize(ref instance, originalCount + temp1.Count); + temp1.CopyTo(instance, originalCount); } - public static void BindCore(IConfiguration configuration, ref Dictionary obj, BinderOptions? binderOptions) + public static void BindCore(IConfiguration configuration, ref Dictionary instance, BinderOptions? binderOptions) { foreach (IConfigurationSection section in configuration.GetChildren()) { if (section.Value is string value) { - obj[section.Key] = value; + instance[section.Key] = value; } } } - public static void BindCore(IConfiguration configuration, ref Program.MyClass obj, BinderOptions? binderOptions) + public static void BindCore(IConfiguration configuration, ref Program.MyClass instance, BinderOptions? binderOptions) { ValidateConfigurationKeys(typeof(Program.MyClass), s_configKeys_ProgramMyClass, configuration, binderOptions); - obj.MyString = configuration["MyString"]!; + instance.MyString = configuration["MyString"]!; if (configuration["MyInt"] is string value4) { - obj.MyInt = ParseInt(value4, () => configuration.GetSection("MyInt").Path); + instance.MyInt = ParseInt(value4, () => configuration.GetSection("MyInt").Path); } if (AsConfigWithChildren(configuration.GetSection("MyList")) is IConfigurationSection section5) { - List? temp7 = obj.MyList; + List? temp7 = instance.MyList; temp7 ??= new List(); BindCore(section5, ref temp7, binderOptions); - obj.MyList = temp7; + instance.MyList = temp7; } if (AsConfigWithChildren(configuration.GetSection("MyArray")) is IConfigurationSection section8) { - int[]? temp10 = obj.MyArray; + int[]? temp10 = instance.MyArray; temp10 ??= new int[0]; BindCore(section8, ref temp10, binderOptions); - obj.MyArray = temp10; + instance.MyArray = temp10; } if (AsConfigWithChildren(configuration.GetSection("MyDictionary")) is IConfigurationSection section11) { - Dictionary? temp13 = obj.MyDictionary; + Dictionary? temp13 = instance.MyDictionary; temp13 ??= new Dictionary(); BindCore(section11, ref temp13, binderOptions); - obj.MyDictionary = temp13; + instance.MyDictionary = temp13; } } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/Get_TypeOf.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/Get_TypeOf.generated.txt index ccf8e72babcc9..590a745175280 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/Get_TypeOf.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/Get_TypeOf.generated.txt @@ -51,21 +51,21 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration if (type == typeof(Program.MyClass2)) { - var obj = new Program.MyClass2(); - BindCore(configuration, ref obj, binderOptions); - return obj; + var instance = new Program.MyClass2(); + BindCore(configuration, ref instance, binderOptions); + return instance; } throw new NotSupportedException($"Unable to bind to type '{type}': generator did not detect the type as input."); } - public static void BindCore(IConfiguration configuration, ref Program.MyClass2 obj, BinderOptions? binderOptions) + public static void BindCore(IConfiguration configuration, ref Program.MyClass2 instance, BinderOptions? binderOptions) { ValidateConfigurationKeys(typeof(Program.MyClass2), s_configKeys_ProgramMyClass2, configuration, binderOptions); if (configuration["MyInt"] is string value1) { - obj.MyInt = ParseInt(value1, () => configuration.GetSection("MyInt").Path); + instance.MyInt = ParseInt(value1, () => configuration.GetSection("MyInt").Path); } } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/Get_TypeOf_BinderOptions.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/Get_TypeOf_BinderOptions.generated.txt index 76cbc01b77eee..322d7c2eb5ee0 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/Get_TypeOf_BinderOptions.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/Get_TypeOf_BinderOptions.generated.txt @@ -51,21 +51,21 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration if (type == typeof(Program.MyClass2)) { - var obj = new Program.MyClass2(); - BindCore(configuration, ref obj, binderOptions); - return obj; + var instance = new Program.MyClass2(); + BindCore(configuration, ref instance, binderOptions); + return instance; } throw new NotSupportedException($"Unable to bind to type '{type}': generator did not detect the type as input."); } - public static void BindCore(IConfiguration configuration, ref Program.MyClass2 obj, BinderOptions? binderOptions) + public static void BindCore(IConfiguration configuration, ref Program.MyClass2 instance, BinderOptions? binderOptions) { ValidateConfigurationKeys(typeof(Program.MyClass2), s_configKeys_ProgramMyClass2, configuration, binderOptions); if (configuration["MyInt"] is string value1) { - obj.MyInt = ParseInt(value1, () => configuration.GetSection("MyInt").Path); + instance.MyInt = ParseInt(value1, () => configuration.GetSection("MyInt").Path); } } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/Primitives.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/Primitives.generated.txt index d83a3a7c71aed..fbb91189030e6 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/Primitives.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/Primitives.generated.txt @@ -32,13 +32,16 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration #region IConfiguration extensions. /// Attempts to bind the given object instance to configuration values by matching property names against configuration keys recursively. [InterceptsLocationAttribute(@"src-0.cs", 13, 16)] - public static void Bind_ProgramMyClass(this IConfiguration configuration, object? obj) + public static void Bind_ProgramMyClass(this IConfiguration configuration, object? instance) { ArgumentNullException.ThrowIfNull(configuration); - ArgumentNullException.ThrowIfNull(obj); + if (instance is null) + { + return; + } - var typedObj = (Program.MyClass)obj; + var typedObj = (Program.MyClass)instance; BindCore(configuration, ref typedObj, binderOptions: null); } #endregion IConfiguration extensions. @@ -46,142 +49,142 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration #region Core binding extensions. private readonly static Lazy> s_configKeys_ProgramMyClass = new(() => new HashSet(StringComparer.OrdinalIgnoreCase) { "Prop0", "Prop1", "Prop2", "Prop3", "Prop4", "Prop5", "Prop6", "Prop8", "Prop9", "Prop10", "Prop13", "Prop14", "Prop15", "Prop16", "Prop17", "Prop19", "Prop20", "Prop21", "Prop23", "Prop24", "Prop25", "Prop26", "Prop27", "Prop7", "Prop11", "Prop12", "Prop18", "Prop22" }); - public static void BindCore(IConfiguration configuration, ref Program.MyClass obj, BinderOptions? binderOptions) + public static void BindCore(IConfiguration configuration, ref Program.MyClass instance, BinderOptions? binderOptions) { ValidateConfigurationKeys(typeof(Program.MyClass), s_configKeys_ProgramMyClass, configuration, binderOptions); if (configuration["Prop0"] is string value0) { - obj.Prop0 = ParseBool(value0, () => configuration.GetSection("Prop0").Path); + instance.Prop0 = ParseBool(value0, () => configuration.GetSection("Prop0").Path); } if (configuration["Prop1"] is string value1) { - obj.Prop1 = ParseByte(value1, () => configuration.GetSection("Prop1").Path); + instance.Prop1 = ParseByte(value1, () => configuration.GetSection("Prop1").Path); } if (configuration["Prop2"] is string value2) { - obj.Prop2 = ParseSbyte(value2, () => configuration.GetSection("Prop2").Path); + instance.Prop2 = ParseSbyte(value2, () => configuration.GetSection("Prop2").Path); } if (configuration["Prop3"] is string value3) { - obj.Prop3 = ParseChar(value3, () => configuration.GetSection("Prop3").Path); + instance.Prop3 = ParseChar(value3, () => configuration.GetSection("Prop3").Path); } if (configuration["Prop4"] is string value4) { - obj.Prop4 = ParseDouble(value4, () => configuration.GetSection("Prop4").Path); + instance.Prop4 = ParseDouble(value4, () => configuration.GetSection("Prop4").Path); } - obj.Prop5 = configuration["Prop5"]!; + instance.Prop5 = configuration["Prop5"]!; if (configuration["Prop6"] is string value6) { - obj.Prop6 = ParseInt(value6, () => configuration.GetSection("Prop6").Path); + instance.Prop6 = ParseInt(value6, () => configuration.GetSection("Prop6").Path); } if (configuration["Prop8"] is string value7) { - obj.Prop8 = ParseShort(value7, () => configuration.GetSection("Prop8").Path); + instance.Prop8 = ParseShort(value7, () => configuration.GetSection("Prop8").Path); } if (configuration["Prop9"] is string value8) { - obj.Prop9 = ParseLong(value8, () => configuration.GetSection("Prop9").Path); + instance.Prop9 = ParseLong(value8, () => configuration.GetSection("Prop9").Path); } if (configuration["Prop10"] is string value9) { - obj.Prop10 = ParseFloat(value9, () => configuration.GetSection("Prop10").Path); + instance.Prop10 = ParseFloat(value9, () => configuration.GetSection("Prop10").Path); } if (configuration["Prop13"] is string value10) { - obj.Prop13 = ParseUshort(value10, () => configuration.GetSection("Prop13").Path); + instance.Prop13 = ParseUshort(value10, () => configuration.GetSection("Prop13").Path); } if (configuration["Prop14"] is string value11) { - obj.Prop14 = ParseUint(value11, () => configuration.GetSection("Prop14").Path); + instance.Prop14 = ParseUint(value11, () => configuration.GetSection("Prop14").Path); } if (configuration["Prop15"] is string value12) { - obj.Prop15 = ParseUlong(value12, () => configuration.GetSection("Prop15").Path); + instance.Prop15 = ParseUlong(value12, () => configuration.GetSection("Prop15").Path); } - obj.Prop16 = configuration["Prop16"]!; + instance.Prop16 = configuration["Prop16"]!; if (configuration["Prop17"] is string value14) { - obj.Prop17 = ParseCultureInfo(value14, () => configuration.GetSection("Prop17").Path); + instance.Prop17 = ParseCultureInfo(value14, () => configuration.GetSection("Prop17").Path); } if (configuration["Prop19"] is string value15) { - obj.Prop19 = ParseDateTime(value15, () => configuration.GetSection("Prop19").Path); + instance.Prop19 = ParseDateTime(value15, () => configuration.GetSection("Prop19").Path); } if (configuration["Prop20"] is string value16) { - obj.Prop20 = ParseDateTimeOffset(value16, () => configuration.GetSection("Prop20").Path); + instance.Prop20 = ParseDateTimeOffset(value16, () => configuration.GetSection("Prop20").Path); } if (configuration["Prop21"] is string value17) { - obj.Prop21 = ParseDecimal(value17, () => configuration.GetSection("Prop21").Path); + instance.Prop21 = ParseDecimal(value17, () => configuration.GetSection("Prop21").Path); } if (configuration["Prop23"] is string value18) { - obj.Prop23 = ParseInt(value18, () => configuration.GetSection("Prop23").Path); + instance.Prop23 = ParseInt(value18, () => configuration.GetSection("Prop23").Path); } if (configuration["Prop24"] is string value19) { - obj.Prop24 = ParseDateTime(value19, () => configuration.GetSection("Prop24").Path); + instance.Prop24 = ParseDateTime(value19, () => configuration.GetSection("Prop24").Path); } if (configuration["Prop25"] is string value20) { - obj.Prop25 = ParseUri(value20, () => configuration.GetSection("Prop25").Path); + instance.Prop25 = ParseUri(value20, () => configuration.GetSection("Prop25").Path); } if (configuration["Prop26"] is string value21) { - obj.Prop26 = ParseVersion(value21, () => configuration.GetSection("Prop26").Path); + instance.Prop26 = ParseVersion(value21, () => configuration.GetSection("Prop26").Path); } if (configuration["Prop27"] is string value22) { - obj.Prop27 = ParseEnum(value22, () => configuration.GetSection("Prop27").Path); + instance.Prop27 = ParseEnum(value22, () => configuration.GetSection("Prop27").Path); } if (configuration["Prop7"] is string value23) { - obj.Prop7 = ParseInt128(value23, () => configuration.GetSection("Prop7").Path); + instance.Prop7 = ParseInt128(value23, () => configuration.GetSection("Prop7").Path); } if (configuration["Prop11"] is string value24) { - obj.Prop11 = ParseHalf(value24, () => configuration.GetSection("Prop11").Path); + instance.Prop11 = ParseHalf(value24, () => configuration.GetSection("Prop11").Path); } if (configuration["Prop12"] is string value25) { - obj.Prop12 = ParseUInt128(value25, () => configuration.GetSection("Prop12").Path); + instance.Prop12 = ParseUInt128(value25, () => configuration.GetSection("Prop12").Path); } if (configuration["Prop18"] is string value26) { - obj.Prop18 = ParseDateOnly(value26, () => configuration.GetSection("Prop18").Path); + instance.Prop18 = ParseDateOnly(value26, () => configuration.GetSection("Prop18").Path); } if (configuration["Prop22"] is string value27) { - obj.Prop22 = ParseByteArray(value27, () => configuration.GetSection("Prop22").Path); + instance.Prop22 = ParseByteArray(value27, () => configuration.GetSection("Prop22").Path); } } From 497a90035fd3c22ef6c4272f64baefae16a54048 Mon Sep 17 00:00:00 2001 From: pedrobsaila Date: Tue, 29 Aug 2023 00:15:01 +0200 Subject: [PATCH 06/17] delete useless references --- ...ation.Binder.SourceGeneration.Tests.csproj | 49 ------------------- 1 file changed, 49 deletions(-) diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Microsoft.Extensions.Configuration.Binder.SourceGeneration.Tests.csproj b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Microsoft.Extensions.Configuration.Binder.SourceGeneration.Tests.csproj index 9b5e69eadb77e..97d0be59688c9 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Microsoft.Extensions.Configuration.Binder.SourceGeneration.Tests.csproj +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Microsoft.Extensions.Configuration.Binder.SourceGeneration.Tests.csproj @@ -31,55 +31,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - From 1ce13feca3fe5980dfa6da5d6e11e380ccf0128d Mon Sep 17 00:00:00 2001 From: pedrobsaila Date: Tue, 29 Aug 2023 16:04:14 +0200 Subject: [PATCH 07/17] run tests for net462 --- .../Baselines/net462/Primitives.generated.txt | 86 +------------------ .../GeneratorTests.Baselines.Options.cs | 19 ++-- .../GeneratorTests.Baselines.cs | 60 ++++++++++--- .../SourceGenerationTests/GeneratorTests.cs | 8 +- ...ation.Binder.SourceGeneration.Tests.csproj | 2 +- 5 files changed, 71 insertions(+), 104 deletions(-) diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/net462/Primitives.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/net462/Primitives.generated.txt index a7ebce4cba1d7..5128831e45f49 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/net462/Primitives.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/net462/Primitives.generated.txt @@ -50,7 +50,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration #endregion IConfiguration extensions. #region Core binding extensions. - private readonly static Lazy> s_configKeys_ProgramMyClass = new(() => new HashSet(StringComparer.OrdinalIgnoreCase) { "Prop0", "Prop1", "Prop2", "Prop3", "Prop4", "Prop5", "Prop6", "Prop8", "Prop9", "Prop10", "Prop13", "Prop14", "Prop15", "Prop16", "Prop17", "Prop19", "Prop20", "Prop21", "Prop23", "Prop24", "Prop25", "Prop26", "Prop27", "Prop7", "Prop11", "Prop12", "Prop18", "Prop22" }); + private readonly static Lazy> s_configKeys_ProgramMyClass = new(() => new HashSet(StringComparer.OrdinalIgnoreCase) { "Prop0", "Prop1", "Prop2", "Prop3", "Prop4", "Prop5", "Prop6", "Prop8", "Prop9", "Prop10", "Prop13", "Prop14", "Prop15", "Prop16", "Prop17", "Prop19", "Prop20", "Prop21", "Prop23", "Prop24", "Prop25", "Prop26", "Prop27", "Prop22" }); public static void BindCore(IConfiguration configuration, ref Program.MyClass instance, BinderOptions? binderOptions) { @@ -165,29 +165,9 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration instance.Prop27 = ParseEnum(value22, () => configuration.GetSection("Prop27").Path); } - if (configuration["Prop7"] is string value23) + if (configuration["Prop22"] is string value23) { - instance.Prop7 = ParseInt128(value23, () => configuration.GetSection("Prop7").Path); - } - - if (configuration["Prop11"] is string value24) - { - instance.Prop11 = ParseHalf(value24, () => configuration.GetSection("Prop11").Path); - } - - if (configuration["Prop12"] is string value25) - { - instance.Prop12 = ParseUInt128(value25, () => configuration.GetSection("Prop12").Path); - } - - if (configuration["Prop18"] is string value26) - { - instance.Prop18 = ParseDateOnly(value26, () => configuration.GetSection("Prop18").Path); - } - - if (configuration["Prop22"] is string value27) - { - instance.Prop22 = ParseByteArray(value27, () => configuration.GetSection("Prop22").Path); + instance.Prop22 = ParseByteArray(value23, () => configuration.GetSection("Prop22").Path); } } @@ -466,66 +446,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration } } - public static Int128 ParseInt128(string value, Func getPath) - { - try - { - return Int128.Parse(value, CultureInfo.InvariantCulture); - } - catch (Exception exception) - { - throw new InvalidOperationException($"Failed to convert configuration value at '{getPath()}' to type '{typeof(Int128)}'.", exception); - } - } - - public static Half ParseHalf(string value, Func getPath) - { - try - { - return Half.Parse(value, CultureInfo.InvariantCulture); - } - catch (Exception exception) - { - throw new InvalidOperationException($"Failed to convert configuration value at '{getPath()}' to type '{typeof(Half)}'.", exception); - } - } - - public static UInt128 ParseUInt128(string value, Func getPath) - { - try - { - return UInt128.Parse(value, CultureInfo.InvariantCulture); - } - catch (Exception exception) - { - throw new InvalidOperationException($"Failed to convert configuration value at '{getPath()}' to type '{typeof(UInt128)}'.", exception); - } - } - - public static DateOnly ParseDateOnly(string value, Func getPath) - { - try - { - return DateOnly.Parse(value, CultureInfo.InvariantCulture); - } - catch (Exception exception) - { - throw new InvalidOperationException($"Failed to convert configuration value at '{getPath()}' to type '{typeof(DateOnly)}'.", exception); - } - } - - public static TimeOnly ParseTimeOnly(string value, Func getPath) - { - try - { - return TimeOnly.Parse(value, CultureInfo.InvariantCulture); - } - catch (Exception exception) - { - throw new InvalidOperationException($"Failed to convert configuration value at '{getPath()}' to type '{typeof(TimeOnly)}'.", exception); - } - } - public static byte[] ParseByteArray(string value, Func getPath) { try diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/GeneratorTests.Baselines.Options.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/GeneratorTests.Baselines.Options.cs index 7874fee6b222d..011daa476525b 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/GeneratorTests.Baselines.Options.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/GeneratorTests.Baselines.Options.cs @@ -129,10 +129,7 @@ public async Task Bind_T_BinderOptions_NetFwk() await VerifyAgainstBaselineUsingFile(Path.Combine("net462", "Bind_T_BinderOptions.generated.txt"), GetBindSource(", _ => { }")); } - [Fact] - public async Task BindConfiguration() - { - string GetSource(string? configureActions = null) => $$""" + string GetBindConfigurationSource(string? configureActions = null) => $$""" using System.Collections.Generic; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; @@ -156,8 +153,18 @@ public class MyClass } """; - await VerifyAgainstBaselineUsingFile(Path.Combine("netcoreapp", "BindConfiguration.generated.txt"), GetSource()); - await VerifyAgainstBaselineUsingFile(Path.Combine("netcoreapp", "BindConfiguration.generated.txt"), GetSource(@"), _ => { }")); + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNetCore))] + public async Task BindConfiguration() + { + await VerifyAgainstBaselineUsingFile(Path.Combine("netcoreapp", "BindConfiguration.generated.txt"), GetBindConfigurationSource()); + await VerifyAgainstBaselineUsingFile(Path.Combine("netcoreapp", "BindConfiguration.generated.txt"), GetBindConfigurationSource(@", _ => { }")); + } + + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNetFramework))] + public async Task BindConfigurationNetFwk() + { + await VerifyAgainstBaselineUsingFile(Path.Combine("net462", "BindConfiguration.generated.txt"), GetBindConfigurationSource()); + await VerifyAgainstBaselineUsingFile(Path.Combine("net462", "BindConfiguration.generated.txt"), GetBindConfigurationSource(@", _ => { }")); } #endregion OptionsBuilder extensions. } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/GeneratorTests.Baselines.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/GeneratorTests.Baselines.cs index 7fba8168a8de6..bba7f1a35a8ee 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/GeneratorTests.Baselines.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/GeneratorTests.Baselines.cs @@ -49,7 +49,6 @@ public async Task Bind(LanguageVersion langVersion) => [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsNetFramework))] [InlineData(LanguageVersion.Preview)] - [InlineData(LanguageVersion.CSharp11)] public async Task Bind_NetFwk(LanguageVersion langVersion) => await VerifyAgainstBaselineUsingFile(Path.Combine("net462", "Bind.generated.txt"), BindCallSampleCode, langVersion); @@ -717,9 +716,10 @@ public class MyClass2 Assert.Empty(d); } - private string GetPrimitivesSource() + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNetCore))] + public async Task Primitives() { - return """ + string source = """ using System; using System.Globalization; using Microsoft.Extensions.Configuration; @@ -771,19 +771,59 @@ public class MyClass } } """; - } - - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNetCore))] - public async Task Primitives() - { - string source = GetPrimitivesSource(); await VerifyAgainstBaselineUsingFile(Path.Combine("netcoreapp", "Primitives.generated.txt"), source); } [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNetFramework))] public async Task PrimitivesNetFwk() { - string source = GetPrimitivesSource(); + string source = """ + using System; + using System.Globalization; + using Microsoft.Extensions.Configuration; + + public class Program + { + public static void Main() + { + ConfigurationBuilder configurationBuilder = new(); + IConfigurationRoot config = configurationBuilder.Build(); + + MyClass obj = new(); + config.Bind(obj); + } + + public class MyClass + { + public bool Prop0 { get; set; } + public byte Prop1 { get; set; } + public sbyte Prop2 { get; set; } + public char Prop3 { get; set; } + public double Prop4 { get; set; } + public string Prop5 { get; set; } + public int Prop6 { get; set; } + public short Prop8 { get; set; } + public long Prop9 { get; set; } + public float Prop10 { get; set; } + public ushort Prop13 { get; set; } + public uint Prop14 { get; set; } + public ulong Prop15 { get; set; } + public object Prop16 { get; set; } + public CultureInfo Prop17 { get; set; } + public DateTime Prop19 { get; set; } + public DateTimeOffset Prop20 { get; set; } + public decimal Prop21 { get; set; } + public TimeSpan Prop23 { get; set; } + public Guid Prop24 { get; set; } + public Uri Prop25 { get; set; } + public Version Prop26 { get; set; } + public DayOfWeek Prop27 { get; set; } + public byte[] Prop22 { get; set; } + public int Prop23 { get; set; } + public DateTime Prop24 { get; set; } + } + } + """; await VerifyAgainstBaselineUsingFile(Path.Combine("net462", "Primitives.generated.txt"), source); } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/GeneratorTests.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/GeneratorTests.cs index d8bd65eeec8e3..32b9ba6525161 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/GeneratorTests.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/GeneratorTests.cs @@ -67,7 +67,7 @@ public async Task LangVersionMustBeCharp12OrHigher(LanguageVersion langVersion) Assert.Equal(DiagnosticSeverity.Error, diagnostic.Severity); } - [Fact] + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNetCore))] public async Task ValueTypesAreInvalidAsBindInputs() { string source = """ @@ -252,7 +252,7 @@ public class MyClass2 { } var (d, r) = await RunGenerator(source); Assert.Single(r); - string generatedSource = string.Join('\n', r[0].SourceText.Lines.Select(x => x.ToString())); + string generatedSource = string.Join("\n", r[0].SourceText.Lines.Select(x => x.ToString())); Assert.Contains("public static void Bind_ProgramMyClass0(this IConfiguration configuration, object? instance)", generatedSource); Assert.Contains("public static void Bind_ProgramMyClass1(this IConfiguration configuration, object? instance, Action? configureOptions)", generatedSource); Assert.Contains("public static void Bind_ProgramMyClass2(this IConfiguration configuration, string key, object? instance)", generatedSource); @@ -379,9 +379,9 @@ private static async Task VerifyAgainstBaselineUsingFile( Action>? assessDiagnostics = null) { string path = Path.Combine("Baselines", filename); - string baseline = LineEndingsHelper.Normalize(await File.ReadAllTextAsync(path).ConfigureAwait(false)); + string baseline = LineEndingsHelper.Normalize(File.ReadAllText(path)); string[] expectedLines = baseline.Replace("%VERSION%", typeof(ConfigurationBindingGenerator).Assembly.GetName().Version?.ToString()) - .Split(Environment.NewLine); + .Split(new string[] { Environment.NewLine }, StringSplitOptions.None); var (d, r) = await RunGenerator(testSourceCode, languageVersion); bool success = RoslynTestUtils.CompareLines(expectedLines, r[0].SourceText, out string errorMessage); diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Microsoft.Extensions.Configuration.Binder.SourceGeneration.Tests.csproj b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Microsoft.Extensions.Configuration.Binder.SourceGeneration.Tests.csproj index 97d0be59688c9..aa1880f7e0973 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Microsoft.Extensions.Configuration.Binder.SourceGeneration.Tests.csproj +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Microsoft.Extensions.Configuration.Binder.SourceGeneration.Tests.csproj @@ -43,7 +43,7 @@ - + PreserveNewest From 4e18e33fa67eb729cac50f4adde01b0cdac08276 Mon Sep 17 00:00:00 2001 From: pedrobsaila Date: Fri, 15 Sep 2023 19:47:41 +0200 Subject: [PATCH 08/17] revert --- .../Bind.generated.txt | 0 .../Bind_Instance.generated.txt | 0 .../Bind_Instance_BinderOptions.generated.txt | 0 .../Bind_Key_Instance.generated.txt | 0 .../Get.generated.txt | 0 .../GetValue.generated.txt | 0 .../GetValue_T_Key.generated.txt | 0 .../GetValue_T_Key_DefaultValue.generated.txt | 0 .../GetValue_TypeOf_Key.generated.txt | 0 ...alue_TypeOf_Key_DefaultValue.generated.txt | 0 .../Get_T.generated.txt | 0 .../Get_T_BinderOptions.generated.txt | 0 .../Get_TypeOf.generated.txt | 0 .../Get_TypeOf_BinderOptions.generated.txt | 0 .../BindConfiguration.generated.txt | 0 .../{ => OptionsBuilder}/Bind_T.generated.txt | 0 .../Bind_T_BinderOptions.generated.txt | 0 .../Configure_T.generated.txt | 0 .../Configure_T_BinderOptions.generated.txt | 0 .../Configure_T_name.generated.txt | 0 ...nfigure_T_name_BinderOptions.generated.txt | 0 .../Bind.generated.txt | 0 .../Bind_Instance.generated.txt | 0 .../Bind_Instance_BinderOptions.generated.txt | 0 .../Bind_Key_Instance.generated.txt | 0 .../Get.generated.txt | 0 .../GetValue.generated.txt | 0 .../GetValue_T_Key.generated.txt | 0 .../GetValue_T_Key_DefaultValue.generated.txt | 0 .../GetValue_TypeOf_Key.generated.txt | 0 ...alue_TypeOf_Key_DefaultValue.generated.txt | 0 .../Get_T.generated.txt | 0 .../Get_T_BinderOptions.generated.txt | 0 .../Get_TypeOf.generated.txt | 0 .../Get_TypeOf_BinderOptions.generated.txt | 0 .../BindConfiguration.generated.txt | 0 .../{ => OptionsBuilder}/Bind_T.generated.txt | 0 .../Bind_T_BinderOptions.generated.txt | 0 .../Configure_T.generated.txt | 0 .../Configure_T_BinderOptions.generated.txt | 0 .../Configure_T_name.generated.txt | 0 ...nfigure_T_name_BinderOptions.generated.txt | 0 .../GeneratorTests.Baselines.Options.cs | 88 +++-- .../GeneratorTests.Baselines.cs | 314 ++++-------------- .../SourceGenerationTests/GeneratorTests.cs | 15 +- ...ation.Binder.SourceGeneration.Tests.csproj | 53 ++- 46 files changed, 165 insertions(+), 305 deletions(-) rename src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/net462/{ => ConfigurationBinder}/Bind.generated.txt (100%) rename src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/net462/{ => ConfigurationBinder}/Bind_Instance.generated.txt (100%) rename src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/net462/{ => ConfigurationBinder}/Bind_Instance_BinderOptions.generated.txt (100%) rename src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/net462/{ => ConfigurationBinder}/Bind_Key_Instance.generated.txt (100%) rename src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/net462/{ => ConfigurationBinder}/Get.generated.txt (100%) rename src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/net462/{ => ConfigurationBinder}/GetValue.generated.txt (100%) rename src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/net462/{ => ConfigurationBinder}/GetValue_T_Key.generated.txt (100%) rename src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/net462/{ => ConfigurationBinder}/GetValue_T_Key_DefaultValue.generated.txt (100%) rename src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/net462/{ => ConfigurationBinder}/GetValue_TypeOf_Key.generated.txt (100%) rename src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/net462/{ => ConfigurationBinder}/GetValue_TypeOf_Key_DefaultValue.generated.txt (100%) rename src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/net462/{ => ConfigurationBinder}/Get_T.generated.txt (100%) rename src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/net462/{ => ConfigurationBinder}/Get_T_BinderOptions.generated.txt (100%) rename src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/net462/{ => ConfigurationBinder}/Get_TypeOf.generated.txt (100%) rename src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/net462/{ => ConfigurationBinder}/Get_TypeOf_BinderOptions.generated.txt (100%) rename src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/net462/{ => OptionsBuilder}/BindConfiguration.generated.txt (100%) rename src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/net462/{ => OptionsBuilder}/Bind_T.generated.txt (100%) rename src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/net462/{ => OptionsBuilder}/Bind_T_BinderOptions.generated.txt (100%) rename src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/net462/{ => ServiceCollection}/Configure_T.generated.txt (100%) rename src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/net462/{ => ServiceCollection}/Configure_T_BinderOptions.generated.txt (100%) rename src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/net462/{ => ServiceCollection}/Configure_T_name.generated.txt (100%) rename src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/net462/{ => ServiceCollection}/Configure_T_name_BinderOptions.generated.txt (100%) rename src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/{ => ConfigurationBinder}/Bind.generated.txt (100%) rename src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/{ => ConfigurationBinder}/Bind_Instance.generated.txt (100%) rename src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/{ => ConfigurationBinder}/Bind_Instance_BinderOptions.generated.txt (100%) rename src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/{ => ConfigurationBinder}/Bind_Key_Instance.generated.txt (100%) rename src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/{ => ConfigurationBinder}/Get.generated.txt (100%) rename src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/{ => ConfigurationBinder}/GetValue.generated.txt (100%) rename src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/{ => ConfigurationBinder}/GetValue_T_Key.generated.txt (100%) rename src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/{ => ConfigurationBinder}/GetValue_T_Key_DefaultValue.generated.txt (100%) rename src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/{ => ConfigurationBinder}/GetValue_TypeOf_Key.generated.txt (100%) rename src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/{ => ConfigurationBinder}/GetValue_TypeOf_Key_DefaultValue.generated.txt (100%) rename src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/{ => ConfigurationBinder}/Get_T.generated.txt (100%) rename src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/{ => ConfigurationBinder}/Get_T_BinderOptions.generated.txt (100%) rename src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/{ => ConfigurationBinder}/Get_TypeOf.generated.txt (100%) rename src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/{ => ConfigurationBinder}/Get_TypeOf_BinderOptions.generated.txt (100%) rename src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/{ => OptionsBuilder}/BindConfiguration.generated.txt (100%) rename src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/{ => OptionsBuilder}/Bind_T.generated.txt (100%) rename src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/{ => OptionsBuilder}/Bind_T_BinderOptions.generated.txt (100%) rename src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/{ => ServiceCollection}/Configure_T.generated.txt (100%) rename src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/{ => ServiceCollection}/Configure_T_BinderOptions.generated.txt (100%) rename src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/{ => ServiceCollection}/Configure_T_name.generated.txt (100%) rename src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/{ => ServiceCollection}/Configure_T_name_BinderOptions.generated.txt (100%) diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/net462/Bind.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/net462/ConfigurationBinder/Bind.generated.txt similarity index 100% rename from src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/net462/Bind.generated.txt rename to src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/net462/ConfigurationBinder/Bind.generated.txt diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/net462/Bind_Instance.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/net462/ConfigurationBinder/Bind_Instance.generated.txt similarity index 100% rename from src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/net462/Bind_Instance.generated.txt rename to src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/net462/ConfigurationBinder/Bind_Instance.generated.txt diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/net462/Bind_Instance_BinderOptions.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/net462/ConfigurationBinder/Bind_Instance_BinderOptions.generated.txt similarity index 100% rename from src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/net462/Bind_Instance_BinderOptions.generated.txt rename to src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/net462/ConfigurationBinder/Bind_Instance_BinderOptions.generated.txt diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/net462/Bind_Key_Instance.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/net462/ConfigurationBinder/Bind_Key_Instance.generated.txt similarity index 100% rename from src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/net462/Bind_Key_Instance.generated.txt rename to src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/net462/ConfigurationBinder/Bind_Key_Instance.generated.txt diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/net462/Get.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/net462/ConfigurationBinder/Get.generated.txt similarity index 100% rename from src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/net462/Get.generated.txt rename to src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/net462/ConfigurationBinder/Get.generated.txt diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/net462/GetValue.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/net462/ConfigurationBinder/GetValue.generated.txt similarity index 100% rename from src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/net462/GetValue.generated.txt rename to src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/net462/ConfigurationBinder/GetValue.generated.txt diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/net462/GetValue_T_Key.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/net462/ConfigurationBinder/GetValue_T_Key.generated.txt similarity index 100% rename from src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/net462/GetValue_T_Key.generated.txt rename to src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/net462/ConfigurationBinder/GetValue_T_Key.generated.txt diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/net462/GetValue_T_Key_DefaultValue.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/net462/ConfigurationBinder/GetValue_T_Key_DefaultValue.generated.txt similarity index 100% rename from src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/net462/GetValue_T_Key_DefaultValue.generated.txt rename to src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/net462/ConfigurationBinder/GetValue_T_Key_DefaultValue.generated.txt diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/net462/GetValue_TypeOf_Key.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/net462/ConfigurationBinder/GetValue_TypeOf_Key.generated.txt similarity index 100% rename from src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/net462/GetValue_TypeOf_Key.generated.txt rename to src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/net462/ConfigurationBinder/GetValue_TypeOf_Key.generated.txt diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/net462/GetValue_TypeOf_Key_DefaultValue.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/net462/ConfigurationBinder/GetValue_TypeOf_Key_DefaultValue.generated.txt similarity index 100% rename from src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/net462/GetValue_TypeOf_Key_DefaultValue.generated.txt rename to src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/net462/ConfigurationBinder/GetValue_TypeOf_Key_DefaultValue.generated.txt diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/net462/Get_T.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/net462/ConfigurationBinder/Get_T.generated.txt similarity index 100% rename from src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/net462/Get_T.generated.txt rename to src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/net462/ConfigurationBinder/Get_T.generated.txt diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/net462/Get_T_BinderOptions.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/net462/ConfigurationBinder/Get_T_BinderOptions.generated.txt similarity index 100% rename from src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/net462/Get_T_BinderOptions.generated.txt rename to src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/net462/ConfigurationBinder/Get_T_BinderOptions.generated.txt diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/net462/Get_TypeOf.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/net462/ConfigurationBinder/Get_TypeOf.generated.txt similarity index 100% rename from src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/net462/Get_TypeOf.generated.txt rename to src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/net462/ConfigurationBinder/Get_TypeOf.generated.txt diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/net462/Get_TypeOf_BinderOptions.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/net462/ConfigurationBinder/Get_TypeOf_BinderOptions.generated.txt similarity index 100% rename from src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/net462/Get_TypeOf_BinderOptions.generated.txt rename to src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/net462/ConfigurationBinder/Get_TypeOf_BinderOptions.generated.txt diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/net462/BindConfiguration.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/net462/OptionsBuilder/BindConfiguration.generated.txt similarity index 100% rename from src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/net462/BindConfiguration.generated.txt rename to src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/net462/OptionsBuilder/BindConfiguration.generated.txt diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/net462/Bind_T.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/net462/OptionsBuilder/Bind_T.generated.txt similarity index 100% rename from src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/net462/Bind_T.generated.txt rename to src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/net462/OptionsBuilder/Bind_T.generated.txt diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/net462/Bind_T_BinderOptions.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/net462/OptionsBuilder/Bind_T_BinderOptions.generated.txt similarity index 100% rename from src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/net462/Bind_T_BinderOptions.generated.txt rename to src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/net462/OptionsBuilder/Bind_T_BinderOptions.generated.txt diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/net462/Configure_T.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/net462/ServiceCollection/Configure_T.generated.txt similarity index 100% rename from src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/net462/Configure_T.generated.txt rename to src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/net462/ServiceCollection/Configure_T.generated.txt diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/net462/Configure_T_BinderOptions.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/net462/ServiceCollection/Configure_T_BinderOptions.generated.txt similarity index 100% rename from src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/net462/Configure_T_BinderOptions.generated.txt rename to src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/net462/ServiceCollection/Configure_T_BinderOptions.generated.txt diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/net462/Configure_T_name.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/net462/ServiceCollection/Configure_T_name.generated.txt similarity index 100% rename from src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/net462/Configure_T_name.generated.txt rename to src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/net462/ServiceCollection/Configure_T_name.generated.txt diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/net462/Configure_T_name_BinderOptions.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/net462/ServiceCollection/Configure_T_name_BinderOptions.generated.txt similarity index 100% rename from src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/net462/Configure_T_name_BinderOptions.generated.txt rename to src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/net462/ServiceCollection/Configure_T_name_BinderOptions.generated.txt diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/Bind.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/ConfigurationBinder/Bind.generated.txt similarity index 100% rename from src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/Bind.generated.txt rename to src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/ConfigurationBinder/Bind.generated.txt diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/Bind_Instance.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/ConfigurationBinder/Bind_Instance.generated.txt similarity index 100% rename from src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/Bind_Instance.generated.txt rename to src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/ConfigurationBinder/Bind_Instance.generated.txt diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/Bind_Instance_BinderOptions.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/ConfigurationBinder/Bind_Instance_BinderOptions.generated.txt similarity index 100% rename from src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/Bind_Instance_BinderOptions.generated.txt rename to src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/ConfigurationBinder/Bind_Instance_BinderOptions.generated.txt diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/Bind_Key_Instance.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/ConfigurationBinder/Bind_Key_Instance.generated.txt similarity index 100% rename from src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/Bind_Key_Instance.generated.txt rename to src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/ConfigurationBinder/Bind_Key_Instance.generated.txt diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/Get.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/ConfigurationBinder/Get.generated.txt similarity index 100% rename from src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/Get.generated.txt rename to src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/ConfigurationBinder/Get.generated.txt diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/GetValue.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/ConfigurationBinder/GetValue.generated.txt similarity index 100% rename from src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/GetValue.generated.txt rename to src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/ConfigurationBinder/GetValue.generated.txt diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/GetValue_T_Key.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/ConfigurationBinder/GetValue_T_Key.generated.txt similarity index 100% rename from src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/GetValue_T_Key.generated.txt rename to src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/ConfigurationBinder/GetValue_T_Key.generated.txt diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/GetValue_T_Key_DefaultValue.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/ConfigurationBinder/GetValue_T_Key_DefaultValue.generated.txt similarity index 100% rename from src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/GetValue_T_Key_DefaultValue.generated.txt rename to src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/ConfigurationBinder/GetValue_T_Key_DefaultValue.generated.txt diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/GetValue_TypeOf_Key.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/ConfigurationBinder/GetValue_TypeOf_Key.generated.txt similarity index 100% rename from src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/GetValue_TypeOf_Key.generated.txt rename to src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/ConfigurationBinder/GetValue_TypeOf_Key.generated.txt diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/GetValue_TypeOf_Key_DefaultValue.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/ConfigurationBinder/GetValue_TypeOf_Key_DefaultValue.generated.txt similarity index 100% rename from src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/GetValue_TypeOf_Key_DefaultValue.generated.txt rename to src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/ConfigurationBinder/GetValue_TypeOf_Key_DefaultValue.generated.txt diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/Get_T.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/ConfigurationBinder/Get_T.generated.txt similarity index 100% rename from src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/Get_T.generated.txt rename to src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/ConfigurationBinder/Get_T.generated.txt diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/Get_T_BinderOptions.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/ConfigurationBinder/Get_T_BinderOptions.generated.txt similarity index 100% rename from src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/Get_T_BinderOptions.generated.txt rename to src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/ConfigurationBinder/Get_T_BinderOptions.generated.txt diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/Get_TypeOf.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/ConfigurationBinder/Get_TypeOf.generated.txt similarity index 100% rename from src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/Get_TypeOf.generated.txt rename to src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/ConfigurationBinder/Get_TypeOf.generated.txt diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/Get_TypeOf_BinderOptions.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/ConfigurationBinder/Get_TypeOf_BinderOptions.generated.txt similarity index 100% rename from src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/Get_TypeOf_BinderOptions.generated.txt rename to src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/ConfigurationBinder/Get_TypeOf_BinderOptions.generated.txt diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/BindConfiguration.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/OptionsBuilder/BindConfiguration.generated.txt similarity index 100% rename from src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/BindConfiguration.generated.txt rename to src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/OptionsBuilder/BindConfiguration.generated.txt diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/Bind_T.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/OptionsBuilder/Bind_T.generated.txt similarity index 100% rename from src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/Bind_T.generated.txt rename to src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/OptionsBuilder/Bind_T.generated.txt diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/Bind_T_BinderOptions.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/OptionsBuilder/Bind_T_BinderOptions.generated.txt similarity index 100% rename from src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/Bind_T_BinderOptions.generated.txt rename to src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/OptionsBuilder/Bind_T_BinderOptions.generated.txt diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/Configure_T.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/ServiceCollection/Configure_T.generated.txt similarity index 100% rename from src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/Configure_T.generated.txt rename to src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/ServiceCollection/Configure_T.generated.txt diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/Configure_T_BinderOptions.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/ServiceCollection/Configure_T_BinderOptions.generated.txt similarity index 100% rename from src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/Configure_T_BinderOptions.generated.txt rename to src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/ServiceCollection/Configure_T_BinderOptions.generated.txt diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/Configure_T_name.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/ServiceCollection/Configure_T_name.generated.txt similarity index 100% rename from src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/Configure_T_name.generated.txt rename to src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/ServiceCollection/Configure_T_name.generated.txt diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/Configure_T_name_BinderOptions.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/ServiceCollection/Configure_T_name_BinderOptions.generated.txt similarity index 100% rename from src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/Configure_T_name_BinderOptions.generated.txt rename to src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/ServiceCollection/Configure_T_name_BinderOptions.generated.txt diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/GeneratorTests.Baselines.Options.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/GeneratorTests.Baselines.Options.cs index 011daa476525b..01ceb22835297 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/GeneratorTests.Baselines.Options.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/GeneratorTests.Baselines.Options.cs @@ -46,37 +46,22 @@ public class MyClass2 #endregion IServiceCollection extensions. #region OptionsBuilder extensions. - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNetCore))] - public async Task Configure_T() => - await VerifyAgainstBaselineUsingFile(Path.Combine("netcoreapp", "Configure_T.generated.txt"), GetConfigureSource("section")); - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNetFramework))] - public async Task Configure_T_NetFwk() => - await VerifyAgainstBaselineUsingFile(Path.Combine("net462", "Configure_T.generated.txt"), GetConfigureSource("section")); + [Fact] + public async Task Configure_T() => + await VerifyAgainstBaselineUsingFile("Configure_T.generated.txt", GetConfigureSource("section"), extType: ExtensionClassType.ServiceCollection); - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNetCore))] + [Fact] public async Task Configure_T_name() => - await VerifyAgainstBaselineUsingFile(Path.Combine("netcoreapp", "Configure_T_name.generated.txt"), GetConfigureSource(@""""", section")); - - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNetFramework))] - public async Task Configure_T_name_NetFwk() => - await VerifyAgainstBaselineUsingFile(Path.Combine("net462", "Configure_T_name.generated.txt"), GetConfigureSource(@""""", section")); + await VerifyAgainstBaselineUsingFile("Configure_T_name.generated.txt", GetConfigureSource(@""""", section"), extType: ExtensionClassType.ServiceCollection); - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNetCore))] + [Fact] public async Task Configure_T_BinderOptions() => - await VerifyAgainstBaselineUsingFile(Path.Combine("netcoreapp", "Configure_T_BinderOptions.generated.txt"), GetConfigureSource("section, _ => { }")); + await VerifyAgainstBaselineUsingFile("Configure_T_BinderOptions.generated.txt", GetConfigureSource("section, _ => { }"), extType: ExtensionClassType.ServiceCollection); - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNetFramework))] - public async Task Configure_T_BinderOptions_NetFwk() => - await VerifyAgainstBaselineUsingFile(Path.Combine("net462", "Configure_T_BinderOptions.generated.txt"), GetConfigureSource("section, _ => { }")); - - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNetCore))] + [Fact] public async Task Configure_T_name_BinderOptions() => - await VerifyAgainstBaselineUsingFile(Path.Combine("netcoreapp", "Configure_T_name_BinderOptions.generated.txt"), GetConfigureSource(@""""", section, _ => { }")); - - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNetFramework))] - public async Task Configure_T_name_BinderOptions_NetFwk() => - await VerifyAgainstBaselineUsingFile(Path.Combine("net462", "Configure_T_name_BinderOptions.generated.txt"), GetConfigureSource(@""""", section, _ => { }")); + await VerifyAgainstBaselineUsingFile("Configure_T_name_BinderOptions.generated.txt", GetConfigureSource(@""""", section, _ => { }"), extType: ExtensionClassType.ServiceCollection); private string GetBindSource(string? configureActions = null) => $$""" using System.Collections.Generic; @@ -105,28 +90,16 @@ public class MyClass } """; - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNetCore))] + [Fact] public async Task Bind_T() { - await VerifyAgainstBaselineUsingFile(Path.Combine("netcoreapp", "Bind_T.generated.txt"), GetBindSource()); + await VerifyAgainstBaselineUsingFile("Bind_T.generated.txt", GetBindSource(), extType: ExtensionClassType.OptionsBuilder); } - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNetFramework))] - public async Task Bind_T_NetFwk() - { - await VerifyAgainstBaselineUsingFile(Path.Combine("net462", "Bind_T.generated.txt"), GetBindSource()); - } - - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNetCore))] + [Fact] public async Task Bind_T_BinderOptions() { - await VerifyAgainstBaselineUsingFile(Path.Combine("netcoreapp", "Bind_T_BinderOptions.generated.txt"), GetBindSource(", _ => { }")); - } - - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNetFramework))] - public async Task Bind_T_BinderOptions_NetFwk() - { - await VerifyAgainstBaselineUsingFile(Path.Combine("net462", "Bind_T_BinderOptions.generated.txt"), GetBindSource(", _ => { }")); + await VerifyAgainstBaselineUsingFile("Bind_T_BinderOptions.generated.txt", GetBindSource(", _ => { }"), extType: ExtensionClassType.OptionsBuilder); } string GetBindConfigurationSource(string? configureActions = null) => $$""" @@ -153,18 +126,35 @@ public class MyClass } """; - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNetCore))] + [Fact] public async Task BindConfiguration() { - await VerifyAgainstBaselineUsingFile(Path.Combine("netcoreapp", "BindConfiguration.generated.txt"), GetBindConfigurationSource()); - await VerifyAgainstBaselineUsingFile(Path.Combine("netcoreapp", "BindConfiguration.generated.txt"), GetBindConfigurationSource(@", _ => { }")); - } + string GetSource(string? configureActions = null) => $$""" + using System.Collections.Generic; + using Microsoft.Extensions.Configuration; + using Microsoft.Extensions.DependencyInjection; + using Microsoft.Extensions.Options; - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNetFramework))] - public async Task BindConfigurationNetFwk() - { - await VerifyAgainstBaselineUsingFile(Path.Combine("net462", "BindConfiguration.generated.txt"), GetBindConfigurationSource()); - await VerifyAgainstBaselineUsingFile(Path.Combine("net462", "BindConfiguration.generated.txt"), GetBindConfigurationSource(@", _ => { }")); + public class Program + { + public static void Main() + { + var services = new ServiceCollection(); + OptionsBuilder optionsBuilder = new(services, Options.DefaultName); + optionsBuilder.BindConfiguration(""{{configureActions}}); + } + + public class MyClass + { + public string MyString { get; set; } + public int MyInt { get; set; } + public List MyList { get; set; } + } + } + """; + + await VerifyAgainstBaselineUsingFile("BindConfiguration.generated.txt", GetSource(), extType: ExtensionClassType.OptionsBuilder); + await VerifyAgainstBaselineUsingFile("BindConfiguration.generated.txt", GetSource(@", _ => { }"), extType: ExtensionClassType.OptionsBuilder); } #endregion OptionsBuilder extensions. } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/GeneratorTests.Baselines.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/GeneratorTests.Baselines.cs index bba7f1a35a8ee..367de2b974c50 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/GeneratorTests.Baselines.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/GeneratorTests.Baselines.cs @@ -42,19 +42,15 @@ public class MyClass public class MyClass2 { } }"; - [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsNetCore))] + [Theory] [InlineData(LanguageVersion.Preview)] public async Task Bind(LanguageVersion langVersion) => - await VerifyAgainstBaselineUsingFile(Path.Combine("netcoreapp", "Bind.generated.txt"), BindCallSampleCode, langVersion); + await VerifyAgainstBaselineUsingFile("Bind.generated.txt", BindCallSampleCode, langVersion, extType: ExtensionClassType.ConfigurationBinder); - [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsNetFramework))] - [InlineData(LanguageVersion.Preview)] - public async Task Bind_NetFwk(LanguageVersion langVersion) => - await VerifyAgainstBaselineUsingFile(Path.Combine("net462", "Bind.generated.txt"), BindCallSampleCode, langVersion); - - private string Bind_Instance_Sources() + [Fact] + public async Task Bind_Instance() { - return """ + string source = """ using System.Collections.Generic; using Microsoft.Extensions.Configuration; @@ -81,27 +77,14 @@ public class MyClass public class MyClass2 { } } """; - } - - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNetCore))] - public async Task Bind_Instance() - { - string source = Bind_Instance_Sources(); - - await VerifyAgainstBaselineUsingFile(Path.Combine("netcoreapp", "Bind_Instance.generated.txt"), source); - } - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNetFramework))] - public async Task Bind_Instance_Fwk() - { - string source = Bind_Instance_Sources(); - - await VerifyAgainstBaselineUsingFile(Path.Combine("net462", "Bind_Instance.generated.txt"), source); + await VerifyAgainstBaselineUsingFile("Bind_Instance.generated.txt", source, extType: ExtensionClassType.ConfigurationBinder); } - private string Bind_Instance_BinderOptions_Sources() + [Fact] + public async Task Bind_Instance_BinderOptions() { - return """ + string source = """ using System.Collections.Generic; using Microsoft.Extensions.Configuration; @@ -128,27 +111,14 @@ public class MyClass public class MyClass2 { } } """; - } - - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNetCore))] - public async Task Bind_Instance_BinderOptions() - { - string source = Bind_Instance_BinderOptions_Sources(); - - await VerifyAgainstBaselineUsingFile(Path.Combine("netcoreapp", "Bind_Instance_BinderOptions.generated.txt"), source); - } - - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNetFramework))] - public async Task Bind_Instance_BinderOptions_NetFwk() - { - string source = Bind_Instance_BinderOptions_Sources(); - await VerifyAgainstBaselineUsingFile(Path.Combine("net462", "Bind_Instance_BinderOptions.generated.txt"), source); + await VerifyAgainstBaselineUsingFile("Bind_Instance_BinderOptions.generated.txt", source, extType: ExtensionClassType.ConfigurationBinder); } - private string Bind_Key_Sources() + [Fact] + public async Task Bind_Key_Instance() { - return """ + string source = """ using System.Collections.Generic; using Microsoft.Extensions.Configuration; @@ -175,27 +145,14 @@ public class MyClass public class MyClass2 { } } """; - } - - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNetCore))] - public async Task Bind_Key_Instance() - { - string source = Bind_Key_Sources(); - await VerifyAgainstBaselineUsingFile(Path.Combine("netcoreapp", "Bind_Key_Instance.generated.txt"), source); + await VerifyAgainstBaselineUsingFile("Bind_Key_Instance.generated.txt", source, extType: ExtensionClassType.ConfigurationBinder); } - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNetFramework))] - public async Task Bind_Key_Instance_NetFwk() - { - string source = Bind_Key_Sources(); - - await VerifyAgainstBaselineUsingFile(Path.Combine("net462", "Bind_Key_Instance.generated.txt"), source); - } - - private string GetSources() + [Fact] + public async Task Get() { - return @" + string source = @" using System.Collections.Generic; using Microsoft.Extensions.Configuration; @@ -235,28 +192,15 @@ public class MyClass4 { public int MyInt { get; set; } } - }"; - } + }"; ; - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNetCore))] - public async Task Get() - { - string source = GetSources(); - - await VerifyAgainstBaselineUsingFile(Path.Combine("netcoreapp", "Get.generated.txt"), source); - } - - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNetFramework))] - public async Task Get_NetFwk() - { - string source = GetSources(); - - await VerifyAgainstBaselineUsingFile(Path.Combine("net462", "Get.generated.txt"), source); + await VerifyAgainstBaselineUsingFile("Get.generated.txt", source, extType: ExtensionClassType.ConfigurationBinder); } - private string Get_T_Sources() + [Fact] + public async Task Get_T() { - return """ + string source = """ using System.Collections.Generic; using Microsoft.Extensions.Configuration; @@ -295,27 +239,14 @@ public class MyClass4 } } """; - } - - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNetCore))] - public async Task Get_T() - { - string source = Get_T_Sources(); - - await VerifyAgainstBaselineUsingFile(Path.Combine("netcoreapp", "Get_T.generated.txt"), source); - } - - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNetFramework))] - public async Task Get_T_NetFwk() - { - string source = Get_T_Sources(); - await VerifyAgainstBaselineUsingFile(Path.Combine("net462", "Get_T.generated.txt"), source); + await VerifyAgainstBaselineUsingFile("Get_T.generated.txt", source, extType: ExtensionClassType.ConfigurationBinder); } - private string Get_T_BinderOptions_Sources() + [Fact] + public async Task Get_T_BinderOptions() { - return """ + string source = """ using System.Collections.Generic; using Microsoft.Extensions.Configuration; @@ -354,27 +285,14 @@ public class MyClass4 } } """; - } - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNetCore))] - public async Task Get_T_BinderOptions() - { - string source = Get_T_BinderOptions_Sources(); - - await VerifyAgainstBaselineUsingFile(Path.Combine("netcoreapp", "Get_T_BinderOptions.generated.txt"), source); - } - - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNetFramework))] - public async Task Get_T_BinderOptions_NetFwk() - { - string source = Get_T_BinderOptions_Sources(); - - await VerifyAgainstBaselineUsingFile(Path.Combine("net462", "Get_T_BinderOptions.generated.txt"), source); + await VerifyAgainstBaselineUsingFile("Get_T_BinderOptions.generated.txt", source, extType: ExtensionClassType.ConfigurationBinder); } - private string Get_TypeOf_Sources() + [Fact] + public async Task Get_TypeOf() { - return """ + string source = """ using System.Collections.Generic; using Microsoft.Extensions.Configuration; @@ -413,27 +331,14 @@ public class MyClass4 } } """; - } - - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNetCore))] - public async Task Get_TypeOf() - { - string source = Get_TypeOf_Sources(); - await VerifyAgainstBaselineUsingFile(Path.Combine("netcoreapp", "Get_TypeOf.generated.txt"), source); + await VerifyAgainstBaselineUsingFile("Get_TypeOf.generated.txt", source, extType: ExtensionClassType.ConfigurationBinder); } - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNetFramework))] - public async Task Get_TypeOf_NetFwk() - { - string source = Get_TypeOf_Sources(); - - await VerifyAgainstBaselineUsingFile(Path.Combine("net462", "Get_TypeOf.generated.txt"), source); - } - - private string Get_TypeOf_BinderOptions_Sources() + [Fact] + public async Task Get_TypeOf_BinderOptions() { - return """ + string source = """ using System.Collections.Generic; using Microsoft.Extensions.Configuration; @@ -472,27 +377,14 @@ public class MyClass4 } } """; - } - - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNetCore))] - public async Task Get_TypeOf_BinderOptions() - { - string source = Get_TypeOf_BinderOptions_Sources(); - - await VerifyAgainstBaselineUsingFile(Path.Combine("netcoreapp", "Get_TypeOf_BinderOptions.generated.txt"), source); - } - - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNetFramework))] - public async Task Get_TypeOf_BinderOptions_NetFwk() - { - string source = Get_TypeOf_BinderOptions_Sources(); - await VerifyAgainstBaselineUsingFile(Path.Combine("net462", "Get_TypeOf_BinderOptions.generated.txt"), source); + await VerifyAgainstBaselineUsingFile("Get_TypeOf_BinderOptions.generated.txt", source, extType: ExtensionClassType.ConfigurationBinder); } - private string GetValue_Sources() + [Fact] + public async Task GetValue() { - return @" + string source = @" using System.Collections.Generic; using System.Globalization; using Microsoft.Extensions.Configuration; @@ -520,27 +412,14 @@ public class MyClass public Dictionary MyDictionary { get; set; } } }"; - } - - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNetCore))] - public async Task GetValue() - { - string source = GetValue_Sources(); - await VerifyAgainstBaselineUsingFile(Path.Combine("netcoreapp", "GetValue.generated.txt"), source); + await VerifyAgainstBaselineUsingFile("GetValue.generated.txt", source, extType: ExtensionClassType.ConfigurationBinder); } - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNetFramework))] - public async Task GetValue_NetFwk() - { - string source = GetValue_Sources(); - - await VerifyAgainstBaselineUsingFile(Path.Combine("net462", "GetValue.generated.txt"), source); - } - - private string GetValue_T_Key_Sources() + [Fact] + public async Task GetValue_T_Key() { - return """ + string source = """ using Microsoft.Extensions.Configuration; public class Program @@ -554,27 +433,14 @@ public static void Main() } } """; - } - - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNetCore))] - public async Task GetValue_T_Key() - { - string source = GetValue_T_Key_Sources(); - await VerifyAgainstBaselineUsingFile(Path.Combine("netcoreapp", "GetValue_T_Key.generated.txt"), source); + await VerifyAgainstBaselineUsingFile("GetValue_T_Key.generated.txt", source, extType: ExtensionClassType.ConfigurationBinder); } - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNetFramework))] - public async Task GetValue_T_Key_NetFwk() - { - string source = GetValue_T_Key_Sources(); - - await VerifyAgainstBaselineUsingFile(Path.Combine("net462", "GetValue_T_Key.generated.txt"), source); - } - - private string GetValue_T_Key_DefaultValue_Sources() + [Fact] + public async Task GetValue_T_Key_DefaultValue() { - return """ + string source = """ using System.Collections.Generic; using System.Globalization; using Microsoft.Extensions.Configuration; @@ -590,27 +456,14 @@ public static void Main() } } """; - } - - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNetCore))] - public async Task GetValue_T_Key_DefaultValue() - { - string source = GetValue_T_Key_DefaultValue_Sources(); - - await VerifyAgainstBaselineUsingFile(Path.Combine("netcoreapp", "GetValue_T_Key_DefaultValue.generated.txt"), source); - } - - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNetFramework))] - public async Task GetValue_T_Key_DefaultValue_NetFwk() - { - string source = GetValue_T_Key_DefaultValue_Sources(); - await VerifyAgainstBaselineUsingFile(Path.Combine("net462", "GetValue_T_Key_DefaultValue.generated.txt"), source); + await VerifyAgainstBaselineUsingFile("GetValue_T_Key_DefaultValue.generated.txt", source, extType: ExtensionClassType.ConfigurationBinder); } - private string GetValue_TypeOf_Key_Sources() + [Fact] + public async Task GetValue_TypeOf_Key() { - return """ + string source = """ using Microsoft.Extensions.Configuration; public class Program @@ -624,27 +477,14 @@ public static void Main() } } """; - } - - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNetCore))] - public async Task GetValue_TypeOf_Key() - { - string source = GetValue_TypeOf_Key_Sources(); - await VerifyAgainstBaselineUsingFile(Path.Combine("netcoreapp", "GetValue_TypeOf_Key.generated.txt"), source); + await VerifyAgainstBaselineUsingFile("GetValue_TypeOf_Key.generated.txt", source, extType: ExtensionClassType.ConfigurationBinder); } - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNetFramework))] - public async Task GetValue_TypeOf_Key_NetFwk() - { - string source = GetValue_TypeOf_Key_Sources(); - - await VerifyAgainstBaselineUsingFile(Path.Combine("net462", "GetValue_TypeOf_Key.generated.txt"), source); - } - - private string GetValue_TypeOf_Key_DefaultValue_Sources() + [Fact] + public async Task GetValue_TypeOf_Key_DefaultValue() { - return """ + string source = """ using System.Globalization; using Microsoft.Extensions.Configuration; @@ -659,22 +499,8 @@ public static void Main() } } """; - } - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNetCore))] - public async Task GetValue_TypeOf_Key_DefaultValue() - { - string source = GetValue_TypeOf_Key_DefaultValue_Sources(); - - await VerifyAgainstBaselineUsingFile(Path.Combine("netcoreapp", "GetValue_TypeOf_Key_DefaultValue.generated.txt"), source); - } - - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNetFramework))] - public async Task GetValue_TypeOf_Key_DefaultValue_NetFwk() - { - string source = GetValue_TypeOf_Key_DefaultValue_Sources(); - - await VerifyAgainstBaselineUsingFile(Path.Combine("net462", "GetValue_TypeOf_Key_DefaultValue.generated.txt"), source); + await VerifyAgainstBaselineUsingFile("GetValue_TypeOf_Key_DefaultValue.generated.txt", source, extType: ExtensionClassType.ConfigurationBinder); } [Fact] @@ -771,7 +597,7 @@ public class MyClass } } """; - await VerifyAgainstBaselineUsingFile(Path.Combine("netcoreapp", "Primitives.generated.txt"), source); + await VerifyAgainstBaselineUsingFile("Primitives.generated.txt", source); } [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNetFramework))] @@ -825,12 +651,13 @@ public class MyClass } """; - await VerifyAgainstBaselineUsingFile(Path.Combine("net462", "Primitives.generated.txt"), source); + await VerifyAgainstBaselineUsingFile("Primitives.generated.txt", source); } - private string GetCollectionsSource() + [Fact] + public async Task Collections() { - return """ + string source = """ using System.Collections.Generic; using Microsoft.Extensions.Configuration; @@ -873,28 +700,9 @@ public interface ICustomSet : ISet } } """; - } - - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNetCore))] - public async Task Collections() - { - string source = GetCollectionsSource(); - - await VerifyAgainstBaselineUsingFile(Path.Combine("netcoreapp", "Collections.generated.txt"), source, assessDiagnostics: (d) => - { - Assert.Equal(3, d.Where(diag => diag.Id == Diagnostics.TypeNotSupported.Id).Count()); - Assert.Equal(6, d.Where(diag => diag.Id == Diagnostics.PropertyNotSupported.Id).Count()); - }); - } - - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNetFramework))] - public async Task CollectionsFwk() - { - string source = GetCollectionsSource(); - await VerifyAgainstBaselineUsingFile(Path.Combine("net462", "Collections.generated.txt"), source, assessDiagnostics: (d) => + await VerifyAgainstBaselineUsingFile("Collections.generated.txt", source, assessDiagnostics: (d) => { - Console.WriteLine((d.Where(diag => diag.Id == Diagnostics.TypeNotSupported.Id).Count(), d.Where(diag => diag.Id == Diagnostics.PropertyNotSupported.Id).Count())); Assert.Equal(3, d.Where(diag => diag.Id == Diagnostics.TypeNotSupported.Id).Count()); Assert.Equal(6, d.Where(diag => diag.Id == Diagnostics.PropertyNotSupported.Id).Count()); }); diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/GeneratorTests.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/GeneratorTests.cs index 32b9ba6525161..8dece56db6cd1 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/GeneratorTests.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/GeneratorTests.cs @@ -376,9 +376,20 @@ private static async Task VerifyAgainstBaselineUsingFile( string filename, string testSourceCode, LanguageVersion languageVersion = LanguageVersion.Preview, - Action>? assessDiagnostics = null) + Action>? assessDiagnostics = null, + ExtensionClassType extType = ExtensionClassType.None) { - string path = Path.Combine("Baselines", filename); + string environmentSubFolder = +#if NETCOREAPP + "netcoreapp" +#else + "net462" +#endif + ; + string path = extType is ExtensionClassType.None + ? Path.Combine("Baselines", environmentSubFolder, filename) + : Path.Combine("Baselines", environmentSubFolder, extType.ToString(), filename); + string baseline = LineEndingsHelper.Normalize(File.ReadAllText(path)); string[] expectedLines = baseline.Replace("%VERSION%", typeof(ConfigurationBindingGenerator).Assembly.GetName().Version?.ToString()) .Split(new string[] { Environment.NewLine }, StringSplitOptions.None); diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Microsoft.Extensions.Configuration.Binder.SourceGeneration.Tests.csproj b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Microsoft.Extensions.Configuration.Binder.SourceGeneration.Tests.csproj index aa1880f7e0973..913ad9f195dc1 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Microsoft.Extensions.Configuration.Binder.SourceGeneration.Tests.csproj +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Microsoft.Extensions.Configuration.Binder.SourceGeneration.Tests.csproj @@ -45,7 +45,13 @@ + Baselines\net462\ConfigurationBinder\*.generated.txt; + Baselines\net462\OptionsBuilder\*.generated.txt; + Baselines\net462\ServiceCollection\*.generated.txt; + Baselines\netcoreapp\*.generated.txt; + Baselines\netcoreapp\ConfigurationBinder\*.generated.txt; + Baselines\netcoreapp\OptionsBuilder\*.generated.txt; + Baselines\netcoreapp\ServiceCollection\*.generated.txt;"> PreserveNewest @@ -54,6 +60,51 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 2ccc919450ed03fd381fead6aaef446af52cd970 Mon Sep 17 00:00:00 2001 From: pedrobsaila Date: Sat, 16 Sep 2023 11:56:29 +0200 Subject: [PATCH 09/17] fix remak about ArgumentNullException --- .../ConfigurationBindingGenerator.Parser.cs | 22 ++++++++++++++++++- .../gen/Model/KnownTypeSymbols.cs | 4 ++++ 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/ConfigurationBindingGenerator.Parser.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/ConfigurationBindingGenerator.Parser.cs index 01ce190c07866..55a0cc1108ef5 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/ConfigurationBindingGenerator.Parser.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/ConfigurationBindingGenerator.Parser.cs @@ -63,7 +63,27 @@ public Parser(SourceProductionContext context, KnownTypeSymbols typeSymbols, Imm } } - _sourceGenSpec.EmitThrowIfNullMethod = _typeSymbols.ArgumentNullException is not null && _typeSymbols.ArgumentNullException.GetMembers("ThrowIfNull").IsEmpty is false; + if (_typeSymbols.ArgumentNullException is not null) + { + var throwIfNullMethods = _typeSymbols.ArgumentNullException.GetMembers("ThrowIfNull"); + + foreach (var throwIfNullMethod in throwIfNullMethods) + { + if (throwIfNullMethod is IMethodSymbol throwIfNullMethodSymbol && throwIfNullMethodSymbol.IsStatic && throwIfNullMethodSymbol.Parameters.Length == 2) + { + var parameters = throwIfNullMethodSymbol.Parameters; + var firstParam = parameters[0]; + var secondParam = parameters[1]; + + if (firstParam.Name == "argument" && firstParam.Type.Equals(_typeSymbols.Object, SymbolEqualityComparer.Default) + && secondParam.Name == "paramName" && secondParam.Type.Equals(_typeSymbols.String, SymbolEqualityComparer.Default)) + { + _sourceGenSpec.EmitThrowIfNullMethod = true; + break; + } + } + } + } return _sourceGenSpec; } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Model/KnownTypeSymbols.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Model/KnownTypeSymbols.cs index 1334fd478fcb3..4f3b5d735b262 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Model/KnownTypeSymbols.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Model/KnownTypeSymbols.cs @@ -56,6 +56,7 @@ internal sealed record KnownTypeSymbols public INamedTypeSymbol? List { get; } public INamedTypeSymbol Enum { get; } public INamedTypeSymbol? ArgumentNullException { get; } + public INamedTypeSymbol Object { get; } public KnownTypeSymbols(CSharpCompilation compilation) { @@ -114,6 +115,9 @@ public KnownTypeSymbols(CSharpCompilation compilation) // needed to be able to know if a member exist inside the compilation unit Enum = compilation.GetSpecialType(SpecialType.System_Enum); ArgumentNullException = compilation.GetBestTypeByMetadataName(typeof(ArgumentNullException)); + + Object = compilation.GetBestTypeByMetadataName(typeof(object)); + String = compilation.GetBestTypeByMetadataName(typeof(string)); } } } From d3c36fefcf6a33961aa6cd9b52749abda30ccec7 Mon Sep 17 00:00:00 2001 From: pedrobsaila Date: Sat, 16 Sep 2023 12:06:39 +0200 Subject: [PATCH 10/17] fix rollback --- .../GeneratorTests.Baselines.Options.cs | 25 ----------- .../GeneratorTests.Baselines.cs | 2 +- ...ation.Binder.SourceGeneration.Tests.csproj | 45 ------------------- 3 files changed, 1 insertion(+), 71 deletions(-) diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/GeneratorTests.Baselines.Options.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/GeneratorTests.Baselines.Options.cs index 01ceb22835297..26e86a56000b5 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/GeneratorTests.Baselines.Options.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/GeneratorTests.Baselines.Options.cs @@ -46,7 +46,6 @@ public class MyClass2 #endregion IServiceCollection extensions. #region OptionsBuilder extensions. - [Fact] public async Task Configure_T() => await VerifyAgainstBaselineUsingFile("Configure_T.generated.txt", GetConfigureSource("section"), extType: ExtensionClassType.ServiceCollection); @@ -102,30 +101,6 @@ public async Task Bind_T_BinderOptions() await VerifyAgainstBaselineUsingFile("Bind_T_BinderOptions.generated.txt", GetBindSource(", _ => { }"), extType: ExtensionClassType.OptionsBuilder); } - string GetBindConfigurationSource(string? configureActions = null) => $$""" - using System.Collections.Generic; - using Microsoft.Extensions.Configuration; - using Microsoft.Extensions.DependencyInjection; - using Microsoft.Extensions.Options; - - public class Program - { - public static void Main() - { - var services = new ServiceCollection(); - OptionsBuilder optionsBuilder = new(services, Options.DefaultName); - optionsBuilder.BindConfiguration(""{{configureActions}}); - } - - public class MyClass - { - public string MyString { get; set; } - public int MyInt { get; set; } - public List MyList { get; set; } - } - } - """; - [Fact] public async Task BindConfiguration() { diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/GeneratorTests.Baselines.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/GeneratorTests.Baselines.cs index 367de2b974c50..e96eeeb5b55e5 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/GeneratorTests.Baselines.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/GeneratorTests.Baselines.cs @@ -192,7 +192,7 @@ public class MyClass4 { public int MyInt { get; set; } } - }"; ; + }"; await VerifyAgainstBaselineUsingFile("Get.generated.txt", source, extType: ExtensionClassType.ConfigurationBinder); } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Microsoft.Extensions.Configuration.Binder.SourceGeneration.Tests.csproj b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Microsoft.Extensions.Configuration.Binder.SourceGeneration.Tests.csproj index 913ad9f195dc1..b3c6680d82d57 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Microsoft.Extensions.Configuration.Binder.SourceGeneration.Tests.csproj +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Microsoft.Extensions.Configuration.Binder.SourceGeneration.Tests.csproj @@ -60,51 +60,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - From 9576f1280b24ac08b0d263ecee3c16e368e2f4dd Mon Sep 17 00:00:00 2001 From: pedrobsaila Date: Sat, 16 Sep 2023 12:08:29 +0200 Subject: [PATCH 11/17] fix revert 2 --- .../SourceGenerationTests/GeneratorTests.Baselines.Options.cs | 2 -- .../tests/SourceGenerationTests/GeneratorTests.Baselines.cs | 1 - 2 files changed, 3 deletions(-) diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/GeneratorTests.Baselines.Options.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/GeneratorTests.Baselines.Options.cs index 26e86a56000b5..0126744eacbfa 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/GeneratorTests.Baselines.Options.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/GeneratorTests.Baselines.Options.cs @@ -1,8 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System; -using System.IO; using System.Threading.Tasks; using Xunit; diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/GeneratorTests.Baselines.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/GeneratorTests.Baselines.cs index e96eeeb5b55e5..4c164450aa0ce 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/GeneratorTests.Baselines.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/GeneratorTests.Baselines.cs @@ -2,7 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. using System; -using System.IO; using System.Linq; using System.Threading.Tasks; using Microsoft.CodeAnalysis; From 8e8de8d814fd5107f8175c85fbb8a08c5f6c6631 Mon Sep 17 00:00:00 2001 From: pedrobsaila Date: Sat, 16 Sep 2023 13:43:21 +0200 Subject: [PATCH 12/17] fix merge issues --- .../net462/EmptyConfigType.generated.txt | 104 ++++++++++++++++ .../Baselines/net462/Primitives.generated.txt | 116 ++++++++++++++++-- .../netcoreapp/Collections.generated.txt | 30 ++--- .../ConfigurationBinder/Bind.generated.txt | 35 +++--- .../Bind_Instance.generated.txt | 27 ++-- .../Bind_Instance_BinderOptions.generated.txt | 27 ++-- .../Bind_Key_Instance.generated.txt | 27 ++-- ...ind_ParseTypeFromMethodParam.generated.txt | 72 +++++++++++ .../ConfigurationBinder/Get.generated.txt | 43 ++++--- .../GetValue.generated.txt | 8 +- .../GetValue_T_Key.generated.txt | 2 +- .../GetValue_T_Key_DefaultValue.generated.txt | 2 +- .../GetValue_TypeOf_Key.generated.txt | 2 +- ...alue_TypeOf_Key_DefaultValue.generated.txt | 2 +- .../ConfigurationBinder/Get_T.generated.txt | 29 +++-- .../Get_T_BinderOptions.generated.txt | 29 +++-- .../Get_TypeOf.generated.txt | 10 +- .../Get_TypeOf_BinderOptions.generated.txt | 10 +- .../netcoreapp/EmptyConfigType.generated.txt | 101 +++++++++++++++ .../BindConfiguration.generated.txt | 19 ++- .../OptionsBuilder/Bind_T.generated.txt | 19 ++- .../Bind_T_BinderOptions.generated.txt | 19 ++- .../Configure_T.generated.txt | 36 ++++-- .../Configure_T_BinderOptions.generated.txt | 36 ++++-- .../Configure_T_name.generated.txt | 36 ++++-- ...nfigure_T_name_BinderOptions.generated.txt | 36 ++++-- .../GeneratorTests.Baselines.cs | 6 +- .../GeneratorTests.Helpers.cs | 15 ++- .../SourceGenerationTests/GeneratorTests.cs | 2 +- 29 files changed, 705 insertions(+), 195 deletions(-) create mode 100644 src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/net462/EmptyConfigType.generated.txt create mode 100644 src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/ConfigurationBinder/Bind_ParseTypeFromMethodParam.generated.txt create mode 100644 src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/EmptyConfigType.generated.txt diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/net462/EmptyConfigType.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/net462/EmptyConfigType.generated.txt new file mode 100644 index 0000000000000..404ce7561cc47 --- /dev/null +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/net462/EmptyConfigType.generated.txt @@ -0,0 +1,104 @@ +// +#nullable enable +#pragma warning disable CS0612, CS0618 // Suppress warnings about [Obsolete] member usage in generated code. + +namespace System.Runtime.CompilerServices +{ + using System; + using System.CodeDom.Compiler; + + [GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")] + [AttributeUsage(AttributeTargets.Method, AllowMultiple = true)] + file sealed class InterceptsLocationAttribute : Attribute + { + public InterceptsLocationAttribute(string filePath, int line, int column) + { + } + } +} + +namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration +{ + using Microsoft.Extensions.Configuration; + using System; + using System.CodeDom.Compiler; + using System.Collections.Generic; + using System.Globalization; + using System.Runtime.CompilerServices; + + [GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")] + file static class BindingExtensions + { + #region IConfiguration extensions. + /// Attempts to bind the given object instance to configuration values by matching property names against configuration keys recursively. + [InterceptsLocation(@"src-0.cs", 12, 23)] + public static void Bind_TypeWithNoMembers(this IConfiguration configuration, object? instance) + { + } + + /// Attempts to bind the given object instance to configuration values by matching property names against configuration keys recursively. + [InterceptsLocation(@"src-0.cs", 15, 23)] + public static void Bind_TypeWithNoMembers_Wrapper(this IConfiguration configuration, object? instance) + { + if (configuration is null) + { + throw new ArgumentNullException(nameof(configuration)); + } + + if (instance is null) + { + return; + } + + var typedObj = (TypeWithNoMembers_Wrapper)instance; + BindCore(configuration, ref typedObj, defaultValueIfNotFound: false, binderOptions: null); + } + #endregion IConfiguration extensions. + + #region Core binding extensions. + private readonly static Lazy> s_configKeys_TypeWithNoMembers_Wrapper = new(() => new HashSet(StringComparer.OrdinalIgnoreCase) { "Member" }); + + public static void BindCore(IConfiguration configuration, ref TypeWithNoMembers_Wrapper instance, bool defaultValueIfNotFound, BinderOptions? binderOptions) + { + ValidateConfigurationKeys(typeof(TypeWithNoMembers_Wrapper), s_configKeys_TypeWithNoMembers_Wrapper, configuration, binderOptions); + + if (AsConfigWithChildren(configuration.GetSection("Member")) is IConfigurationSection section0) + { + instance.Member ??= new TypeWithNoMembers(); + } + } + + + /// If required by the binder options, validates that there are no unknown keys in the input configuration object. + public static void ValidateConfigurationKeys(Type type, Lazy> keys, IConfiguration configuration, BinderOptions? binderOptions) + { + if (binderOptions?.ErrorOnUnknownConfiguration is true) + { + List? temp = null; + + foreach (IConfigurationSection section in configuration.GetChildren()) + { + if (!keys.Value.Contains(section.Key)) + { + (temp ??= new List()).Add($"'{section.Key}'"); + } + } + + if (temp is not null) + { + throw new InvalidOperationException($"'ErrorOnUnknownConfiguration' was set on the provided BinderOptions, but the following properties were not found on the instance of {type}: {string.Join(", ", temp)}"); + } + } + } + + public static IConfiguration? AsConfigWithChildren(IConfiguration configuration) + { + foreach (IConfigurationSection _ in configuration.GetChildren()) + { + return configuration; + } + return null; + } + #endregion Core binding extensions. + } +} diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/net462/Primitives.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/net462/Primitives.generated.txt index 5128831e45f49..6f189bf2e55ba 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/net462/Primitives.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/net462/Primitives.generated.txt @@ -31,7 +31,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration { #region IConfiguration extensions. /// Attempts to bind the given object instance to configuration values by matching property names against configuration keys recursively. - [InterceptsLocationAttribute(@"src-0.cs", 13, 16)] + [InterceptsLocation(@"src-0.cs", 13, 16)] public static void Bind_ProgramMyClass(this IConfiguration configuration, object? instance) { if (configuration is null) @@ -45,14 +45,14 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration } var typedObj = (Program.MyClass)instance; - BindCore(configuration, ref typedObj, binderOptions: null); + BindCore(configuration, ref typedObj, defaultValueIfNotFound: false, binderOptions: null); } #endregion IConfiguration extensions. #region Core binding extensions. - private readonly static Lazy> s_configKeys_ProgramMyClass = new(() => new HashSet(StringComparer.OrdinalIgnoreCase) { "Prop0", "Prop1", "Prop2", "Prop3", "Prop4", "Prop5", "Prop6", "Prop8", "Prop9", "Prop10", "Prop13", "Prop14", "Prop15", "Prop16", "Prop17", "Prop19", "Prop20", "Prop21", "Prop23", "Prop24", "Prop25", "Prop26", "Prop27", "Prop22" }); + private readonly static Lazy> s_configKeys_ProgramMyClass = new(() => new HashSet(StringComparer.OrdinalIgnoreCase) { "Prop0", "Prop1", "Prop2", "Prop3", "Prop4", "Prop5", "Prop6", "Prop8", "Prop9", "Prop10", "Prop13", "Prop14", "Prop15", "Prop16", "Prop17", "Prop19", "Prop20", "Prop21", "Prop23", "Prop24", "Prop25", "Prop26", "Prop27", "Prop28", "Prop29", "Prop30" }); - public static void BindCore(IConfiguration configuration, ref Program.MyClass instance, BinderOptions? binderOptions) + public static void BindCore(IConfiguration configuration, ref Program.MyClass instance, bool defaultValueIfNotFound, BinderOptions? binderOptions) { ValidateConfigurationKeys(typeof(Program.MyClass), s_configKeys_ProgramMyClass, configuration, binderOptions); @@ -60,65 +60,119 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration { instance.Prop0 = ParseBool(value0, () => configuration.GetSection("Prop0").Path); } + else if (defaultValueIfNotFound) + { + instance.Prop0 = default; + } if (configuration["Prop1"] is string value1) { instance.Prop1 = ParseByte(value1, () => configuration.GetSection("Prop1").Path); } + else if (defaultValueIfNotFound) + { + instance.Prop1 = default; + } if (configuration["Prop2"] is string value2) { instance.Prop2 = ParseSbyte(value2, () => configuration.GetSection("Prop2").Path); } + else if (defaultValueIfNotFound) + { + instance.Prop2 = default; + } if (configuration["Prop3"] is string value3) { instance.Prop3 = ParseChar(value3, () => configuration.GetSection("Prop3").Path); } + else if (defaultValueIfNotFound) + { + instance.Prop3 = default; + } if (configuration["Prop4"] is string value4) { instance.Prop4 = ParseDouble(value4, () => configuration.GetSection("Prop4").Path); } + else if (defaultValueIfNotFound) + { + instance.Prop4 = default; + } - instance.Prop5 = configuration["Prop5"]!; + if (configuration["Prop5"] is string value5) + { + instance.Prop5 = value5; + } if (configuration["Prop6"] is string value6) { instance.Prop6 = ParseInt(value6, () => configuration.GetSection("Prop6").Path); } + else if (defaultValueIfNotFound) + { + instance.Prop6 = default; + } if (configuration["Prop8"] is string value7) { instance.Prop8 = ParseShort(value7, () => configuration.GetSection("Prop8").Path); } + else if (defaultValueIfNotFound) + { + instance.Prop8 = default; + } if (configuration["Prop9"] is string value8) { instance.Prop9 = ParseLong(value8, () => configuration.GetSection("Prop9").Path); } + else if (defaultValueIfNotFound) + { + instance.Prop9 = default; + } if (configuration["Prop10"] is string value9) { instance.Prop10 = ParseFloat(value9, () => configuration.GetSection("Prop10").Path); } + else if (defaultValueIfNotFound) + { + instance.Prop10 = default; + } if (configuration["Prop13"] is string value10) { instance.Prop13 = ParseUshort(value10, () => configuration.GetSection("Prop13").Path); } + else if (defaultValueIfNotFound) + { + instance.Prop13 = default; + } if (configuration["Prop14"] is string value11) { instance.Prop14 = ParseUint(value11, () => configuration.GetSection("Prop14").Path); } + else if (defaultValueIfNotFound) + { + instance.Prop14 = default; + } if (configuration["Prop15"] is string value12) { instance.Prop15 = ParseUlong(value12, () => configuration.GetSection("Prop15").Path); } + else if (defaultValueIfNotFound) + { + instance.Prop15 = default; + } - instance.Prop16 = configuration["Prop16"]!; + if (configuration["Prop16"] is string value13) + { + instance.Prop16 = value13; + } if (configuration["Prop17"] is string value14) { @@ -129,25 +183,45 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration { instance.Prop19 = ParseDateTime(value15, () => configuration.GetSection("Prop19").Path); } + else if (defaultValueIfNotFound) + { + instance.Prop19 = default; + } if (configuration["Prop20"] is string value16) { instance.Prop20 = ParseDateTimeOffset(value16, () => configuration.GetSection("Prop20").Path); } + else if (defaultValueIfNotFound) + { + instance.Prop20 = default; + } if (configuration["Prop21"] is string value17) { instance.Prop21 = ParseDecimal(value17, () => configuration.GetSection("Prop21").Path); } + else if (defaultValueIfNotFound) + { + instance.Prop21 = default; + } if (configuration["Prop23"] is string value18) { - instance.Prop23 = ParseInt(value18, () => configuration.GetSection("Prop23").Path); + instance.Prop23 = ParseTimeSpan(value18, () => configuration.GetSection("Prop23").Path); + } + else if (defaultValueIfNotFound) + { + instance.Prop23 = default; } if (configuration["Prop24"] is string value19) { - instance.Prop24 = ParseDateTime(value19, () => configuration.GetSection("Prop24").Path); + instance.Prop24 = ParseGuid(value19, () => configuration.GetSection("Prop24").Path); + } + else if (defaultValueIfNotFound) + { + instance.Prop24 = default; } if (configuration["Prop25"] is string value20) @@ -164,10 +238,32 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration { instance.Prop27 = ParseEnum(value22, () => configuration.GetSection("Prop27").Path); } + else if (defaultValueIfNotFound) + { + instance.Prop27 = default; + } + + if (configuration["Prop28"] is string value23) + { + instance.Prop28 = ParseByteArray(value23, () => configuration.GetSection("Prop28").Path); + } + + if (configuration["Prop29"] is string value24) + { + instance.Prop29 = ParseInt(value24, () => configuration.GetSection("Prop29").Path); + } + else if (defaultValueIfNotFound) + { + instance.Prop29 = default; + } - if (configuration["Prop22"] is string value23) + if (configuration["Prop30"] is string value25) + { + instance.Prop30 = ParseDateTime(value25, () => configuration.GetSection("Prop30").Path); + } + else if (defaultValueIfNotFound) { - instance.Prop22 = ParseByteArray(value23, () => configuration.GetSection("Prop22").Path); + instance.Prop30 = default; } } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/Collections.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/Collections.generated.txt index 4e8e9df814c13..683c791845c62 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/Collections.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/Collections.generated.txt @@ -32,7 +32,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration { #region IConfiguration extensions. /// Attempts to bind the configuration instance to a new instance of type T. - [InterceptsLocationAttribute(@"src-0.cs", 12, 17)] + [InterceptsLocation(@"src-0.cs", 12, 17)] public static T? Get(this IConfiguration configuration) => (T?)(GetCore(configuration, typeof(T), configureOptions: null) ?? default(T)); #endregion IConfiguration extensions. @@ -53,14 +53,14 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration if (type == typeof(Program.MyClassWithCustomCollections)) { var instance = new Program.MyClassWithCustomCollections(); - BindCore(configuration, ref instance, binderOptions); + BindCore(configuration, ref instance, defaultValueIfNotFound: true, binderOptions); return instance; } throw new NotSupportedException($"Unable to bind to type '{type}': generator did not detect the type as input."); } - public static void BindCore(IConfiguration configuration, ref Program.CustomDictionary instance, BinderOptions? binderOptions) + public static void BindCore(IConfiguration configuration, ref Program.CustomDictionary instance, bool defaultValueIfNotFound, BinderOptions? binderOptions) { foreach (IConfigurationSection section in configuration.GetChildren()) { @@ -71,7 +71,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration } } - public static void BindCore(IConfiguration configuration, ref Program.CustomList instance, BinderOptions? binderOptions) + public static void BindCore(IConfiguration configuration, ref Program.CustomList instance, bool defaultValueIfNotFound, BinderOptions? binderOptions) { foreach (IConfigurationSection section in configuration.GetChildren()) { @@ -82,7 +82,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration } } - public static void BindCore(IConfiguration configuration, ref List instance, BinderOptions? binderOptions) + public static void BindCore(IConfiguration configuration, ref List instance, bool defaultValueIfNotFound, BinderOptions? binderOptions) { foreach (IConfigurationSection section in configuration.GetChildren()) { @@ -93,7 +93,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration } } - public static void BindCore(IConfiguration configuration, ref ICollection instance, BinderOptions? binderOptions) + public static void BindCore(IConfiguration configuration, ref ICollection instance, bool defaultValueIfNotFound, BinderOptions? binderOptions) { foreach (IConfigurationSection section in configuration.GetChildren()) { @@ -104,7 +104,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration } } - public static void BindCore(IConfiguration configuration, ref IReadOnlyList instance, BinderOptions? binderOptions) + public static void BindCore(IConfiguration configuration, ref IReadOnlyList instance, bool defaultValueIfNotFound, BinderOptions? binderOptions) { if (instance is not ICollection temp) { @@ -120,7 +120,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration } } - public static void BindCore(IConfiguration configuration, ref Dictionary instance, BinderOptions? binderOptions) + public static void BindCore(IConfiguration configuration, ref Dictionary instance, bool defaultValueIfNotFound, BinderOptions? binderOptions) { foreach (IConfigurationSection section in configuration.GetChildren()) { @@ -131,7 +131,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration } } - public static void BindCore(IConfiguration configuration, ref IDictionary instance, BinderOptions? binderOptions) + public static void BindCore(IConfiguration configuration, ref IDictionary instance, bool defaultValueIfNotFound, BinderOptions? binderOptions) { foreach (IConfigurationSection section in configuration.GetChildren()) { @@ -142,7 +142,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration } } - public static void BindCore(IConfiguration configuration, ref IReadOnlyDictionary instance, BinderOptions? binderOptions) + public static void BindCore(IConfiguration configuration, ref IReadOnlyDictionary instance, bool defaultValueIfNotFound, BinderOptions? binderOptions) { if (instance is not IDictionary temp) { @@ -158,7 +158,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration } } - public static void BindCore(IConfiguration configuration, ref Program.MyClassWithCustomCollections instance, BinderOptions? binderOptions) + public static void BindCore(IConfiguration configuration, ref Program.MyClassWithCustomCollections instance, bool defaultValueIfNotFound, BinderOptions? binderOptions) { ValidateConfigurationKeys(typeof(Program.MyClassWithCustomCollections), s_configKeys_ProgramMyClassWithCustomCollections, configuration, binderOptions); @@ -166,7 +166,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration { Program.CustomDictionary? temp3 = instance.CustomDictionary; temp3 ??= new Program.CustomDictionary(); - BindCore(section1, ref temp3, binderOptions); + BindCore(section1, ref temp3, defaultValueIfNotFound: false, binderOptions); instance.CustomDictionary = temp3; } @@ -174,7 +174,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration { Program.CustomList? temp6 = instance.CustomList; temp6 ??= new Program.CustomList(); - BindCore(section4, ref temp6, binderOptions); + BindCore(section4, ref temp6, defaultValueIfNotFound: false, binderOptions); instance.CustomList = temp6; } @@ -182,7 +182,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration { IReadOnlyList? temp9 = instance.IReadOnlyList; temp9 = temp9 is null ? new List() : new List(temp9); - BindCore(section7, ref temp9, binderOptions); + BindCore(section7, ref temp9, defaultValueIfNotFound: false, binderOptions); instance.IReadOnlyList = temp9; } @@ -190,7 +190,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration { IReadOnlyDictionary? temp12 = instance.IReadOnlyDictionary; temp12 = temp12 is null ? new Dictionary() : temp12.ToDictionary(pair => pair.Key, pair => pair.Value); - BindCore(section10, ref temp12, binderOptions); + BindCore(section10, ref temp12, defaultValueIfNotFound: false, binderOptions); instance.IReadOnlyDictionary = temp12; } } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/ConfigurationBinder/Bind.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/ConfigurationBinder/Bind.generated.txt index 078846538f1db..c1c98b7d1e162 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/ConfigurationBinder/Bind.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/ConfigurationBinder/Bind.generated.txt @@ -31,7 +31,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration { #region IConfiguration extensions. /// Attempts to bind the given object instance to configuration values by matching property names against configuration keys recursively. - [InterceptsLocationAttribute(@"src-0.cs", 13, 18)] + [InterceptsLocation(@"src-0.cs", 12, 14)] public static void Bind_ProgramMyClass(this IConfiguration configuration, object? instance) { ArgumentNullException.ThrowIfNull(configuration); @@ -42,11 +42,11 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration } var typedObj = (Program.MyClass)instance; - BindCore(configuration, ref typedObj, binderOptions: null); + BindCore(configuration, ref typedObj, defaultValueIfNotFound: false, binderOptions: null); } /// Attempts to bind the given object instance to configuration values by matching property names against configuration keys recursively. - [InterceptsLocationAttribute(@"src-0.cs", 14, 24)] + [InterceptsLocation(@"src-0.cs", 13, 20)] public static void Bind_ProgramMyClass(this IConfiguration configuration, object? instance, Action? configureOptions) { ArgumentNullException.ThrowIfNull(configuration); @@ -57,11 +57,11 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration } var typedObj = (Program.MyClass)instance; - BindCore(configuration, ref typedObj, GetBinderOptions(configureOptions)); + BindCore(configuration, ref typedObj, defaultValueIfNotFound: false, GetBinderOptions(configureOptions)); } /// Attempts to bind the given object instance to configuration values by matching property names against configuration keys recursively. - [InterceptsLocationAttribute(@"src-0.cs", 15, 24)] + [InterceptsLocation(@"src-0.cs", 14, 20)] public static void Bind_ProgramMyClass(this IConfiguration configuration, string key, object? instance) { ArgumentNullException.ThrowIfNull(configuration); @@ -72,14 +72,14 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration } var typedObj = (Program.MyClass)instance; - BindCore(configuration.GetSection(key), ref typedObj, binderOptions: null); + BindCore(configuration.GetSection(key), ref typedObj, defaultValueIfNotFound: false, binderOptions: null); } #endregion IConfiguration extensions. #region Core binding extensions. private readonly static Lazy> s_configKeys_ProgramMyClass = new(() => new HashSet(StringComparer.OrdinalIgnoreCase) { "MyString", "MyInt", "MyList", "MyDictionary", "MyComplexDictionary" }); - public static void BindCore(IConfiguration configuration, ref List instance, BinderOptions? binderOptions) + public static void BindCore(IConfiguration configuration, ref List instance, bool defaultValueIfNotFound, BinderOptions? binderOptions) { foreach (IConfigurationSection section in configuration.GetChildren()) { @@ -90,7 +90,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration } } - public static void BindCore(IConfiguration configuration, ref Dictionary instance, BinderOptions? binderOptions) + public static void BindCore(IConfiguration configuration, ref Dictionary instance, bool defaultValueIfNotFound, BinderOptions? binderOptions) { foreach (IConfigurationSection section in configuration.GetChildren()) { @@ -101,7 +101,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration } } - public static void BindCore(IConfiguration configuration, ref Dictionary instance, BinderOptions? binderOptions) + public static void BindCore(IConfiguration configuration, ref Dictionary instance, bool defaultValueIfNotFound, BinderOptions? binderOptions) { foreach (IConfigurationSection section in configuration.GetChildren()) { @@ -113,22 +113,29 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration } } - public static void BindCore(IConfiguration configuration, ref Program.MyClass instance, BinderOptions? binderOptions) + public static void BindCore(IConfiguration configuration, ref Program.MyClass instance, bool defaultValueIfNotFound, BinderOptions? binderOptions) { ValidateConfigurationKeys(typeof(Program.MyClass), s_configKeys_ProgramMyClass, configuration, binderOptions); - instance.MyString = configuration["MyString"]!; + if (configuration["MyString"] is string value0) + { + instance.MyString = value0; + } if (configuration["MyInt"] is string value1) { instance.MyInt = ParseInt(value1, () => configuration.GetSection("MyInt").Path); } + else if (defaultValueIfNotFound) + { + instance.MyInt = default; + } if (AsConfigWithChildren(configuration.GetSection("MyList")) is IConfigurationSection section2) { List? temp4 = instance.MyList; temp4 ??= new List(); - BindCore(section2, ref temp4, binderOptions); + BindCore(section2, ref temp4, defaultValueIfNotFound: false, binderOptions); instance.MyList = temp4; } @@ -136,7 +143,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration { Dictionary? temp7 = instance.MyDictionary; temp7 ??= new Dictionary(); - BindCore(section5, ref temp7, binderOptions); + BindCore(section5, ref temp7, defaultValueIfNotFound: false, binderOptions); instance.MyDictionary = temp7; } @@ -144,7 +151,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration { Dictionary? temp10 = instance.MyComplexDictionary; temp10 ??= new Dictionary(); - BindCore(section8, ref temp10, binderOptions); + BindCore(section8, ref temp10, defaultValueIfNotFound: false, binderOptions); instance.MyComplexDictionary = temp10; } } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/ConfigurationBinder/Bind_Instance.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/ConfigurationBinder/Bind_Instance.generated.txt index 5ee8d25e6b9a5..8c961fff97813 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/ConfigurationBinder/Bind_Instance.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/ConfigurationBinder/Bind_Instance.generated.txt @@ -31,7 +31,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration { #region IConfiguration extensions. /// Attempts to bind the given object instance to configuration values by matching property names against configuration keys recursively. - [InterceptsLocationAttribute(@"src-0.cs", 12, 20)] + [InterceptsLocation(@"src-0.cs", 12, 20)] public static void Bind_ProgramMyClass(this IConfiguration configuration, object? instance) { ArgumentNullException.ThrowIfNull(configuration); @@ -42,14 +42,14 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration } var typedObj = (Program.MyClass)instance; - BindCore(configuration, ref typedObj, binderOptions: null); + BindCore(configuration, ref typedObj, defaultValueIfNotFound: false, binderOptions: null); } #endregion IConfiguration extensions. #region Core binding extensions. private readonly static Lazy> s_configKeys_ProgramMyClass = new(() => new HashSet(StringComparer.OrdinalIgnoreCase) { "MyString", "MyInt", "MyList", "MyDictionary", "MyComplexDictionary" }); - public static void BindCore(IConfiguration configuration, ref List instance, BinderOptions? binderOptions) + public static void BindCore(IConfiguration configuration, ref List instance, bool defaultValueIfNotFound, BinderOptions? binderOptions) { foreach (IConfigurationSection section in configuration.GetChildren()) { @@ -60,7 +60,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration } } - public static void BindCore(IConfiguration configuration, ref Dictionary instance, BinderOptions? binderOptions) + public static void BindCore(IConfiguration configuration, ref Dictionary instance, bool defaultValueIfNotFound, BinderOptions? binderOptions) { foreach (IConfigurationSection section in configuration.GetChildren()) { @@ -71,7 +71,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration } } - public static void BindCore(IConfiguration configuration, ref Dictionary instance, BinderOptions? binderOptions) + public static void BindCore(IConfiguration configuration, ref Dictionary instance, bool defaultValueIfNotFound, BinderOptions? binderOptions) { foreach (IConfigurationSection section in configuration.GetChildren()) { @@ -83,22 +83,29 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration } } - public static void BindCore(IConfiguration configuration, ref Program.MyClass instance, BinderOptions? binderOptions) + public static void BindCore(IConfiguration configuration, ref Program.MyClass instance, bool defaultValueIfNotFound, BinderOptions? binderOptions) { ValidateConfigurationKeys(typeof(Program.MyClass), s_configKeys_ProgramMyClass, configuration, binderOptions); - instance.MyString = configuration["MyString"]!; + if (configuration["MyString"] is string value0) + { + instance.MyString = value0; + } if (configuration["MyInt"] is string value1) { instance.MyInt = ParseInt(value1, () => configuration.GetSection("MyInt").Path); } + else if (defaultValueIfNotFound) + { + instance.MyInt = default; + } if (AsConfigWithChildren(configuration.GetSection("MyList")) is IConfigurationSection section2) { List? temp4 = instance.MyList; temp4 ??= new List(); - BindCore(section2, ref temp4, binderOptions); + BindCore(section2, ref temp4, defaultValueIfNotFound: false, binderOptions); instance.MyList = temp4; } @@ -106,7 +113,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration { Dictionary? temp7 = instance.MyDictionary; temp7 ??= new Dictionary(); - BindCore(section5, ref temp7, binderOptions); + BindCore(section5, ref temp7, defaultValueIfNotFound: false, binderOptions); instance.MyDictionary = temp7; } @@ -114,7 +121,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration { Dictionary? temp10 = instance.MyComplexDictionary; temp10 ??= new Dictionary(); - BindCore(section8, ref temp10, binderOptions); + BindCore(section8, ref temp10, defaultValueIfNotFound: false, binderOptions); instance.MyComplexDictionary = temp10; } } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/ConfigurationBinder/Bind_Instance_BinderOptions.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/ConfigurationBinder/Bind_Instance_BinderOptions.generated.txt index 8d030022f5560..f7ea54e511a57 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/ConfigurationBinder/Bind_Instance_BinderOptions.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/ConfigurationBinder/Bind_Instance_BinderOptions.generated.txt @@ -31,7 +31,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration { #region IConfiguration extensions. /// Attempts to bind the given object instance to configuration values by matching property names against configuration keys recursively. - [InterceptsLocationAttribute(@"src-0.cs", 12, 20)] + [InterceptsLocation(@"src-0.cs", 12, 20)] public static void Bind_ProgramMyClass(this IConfiguration configuration, object? instance, Action? configureOptions) { ArgumentNullException.ThrowIfNull(configuration); @@ -42,14 +42,14 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration } var typedObj = (Program.MyClass)instance; - BindCore(configuration, ref typedObj, GetBinderOptions(configureOptions)); + BindCore(configuration, ref typedObj, defaultValueIfNotFound: false, GetBinderOptions(configureOptions)); } #endregion IConfiguration extensions. #region Core binding extensions. private readonly static Lazy> s_configKeys_ProgramMyClass = new(() => new HashSet(StringComparer.OrdinalIgnoreCase) { "MyString", "MyInt", "MyList", "MyDictionary", "MyComplexDictionary" }); - public static void BindCore(IConfiguration configuration, ref List instance, BinderOptions? binderOptions) + public static void BindCore(IConfiguration configuration, ref List instance, bool defaultValueIfNotFound, BinderOptions? binderOptions) { foreach (IConfigurationSection section in configuration.GetChildren()) { @@ -60,7 +60,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration } } - public static void BindCore(IConfiguration configuration, ref Dictionary instance, BinderOptions? binderOptions) + public static void BindCore(IConfiguration configuration, ref Dictionary instance, bool defaultValueIfNotFound, BinderOptions? binderOptions) { foreach (IConfigurationSection section in configuration.GetChildren()) { @@ -71,7 +71,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration } } - public static void BindCore(IConfiguration configuration, ref Dictionary instance, BinderOptions? binderOptions) + public static void BindCore(IConfiguration configuration, ref Dictionary instance, bool defaultValueIfNotFound, BinderOptions? binderOptions) { foreach (IConfigurationSection section in configuration.GetChildren()) { @@ -83,22 +83,29 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration } } - public static void BindCore(IConfiguration configuration, ref Program.MyClass instance, BinderOptions? binderOptions) + public static void BindCore(IConfiguration configuration, ref Program.MyClass instance, bool defaultValueIfNotFound, BinderOptions? binderOptions) { ValidateConfigurationKeys(typeof(Program.MyClass), s_configKeys_ProgramMyClass, configuration, binderOptions); - instance.MyString = configuration["MyString"]!; + if (configuration["MyString"] is string value0) + { + instance.MyString = value0; + } if (configuration["MyInt"] is string value1) { instance.MyInt = ParseInt(value1, () => configuration.GetSection("MyInt").Path); } + else if (defaultValueIfNotFound) + { + instance.MyInt = default; + } if (AsConfigWithChildren(configuration.GetSection("MyList")) is IConfigurationSection section2) { List? temp4 = instance.MyList; temp4 ??= new List(); - BindCore(section2, ref temp4, binderOptions); + BindCore(section2, ref temp4, defaultValueIfNotFound: false, binderOptions); instance.MyList = temp4; } @@ -106,7 +113,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration { Dictionary? temp7 = instance.MyDictionary; temp7 ??= new Dictionary(); - BindCore(section5, ref temp7, binderOptions); + BindCore(section5, ref temp7, defaultValueIfNotFound: false, binderOptions); instance.MyDictionary = temp7; } @@ -114,7 +121,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration { Dictionary? temp10 = instance.MyComplexDictionary; temp10 ??= new Dictionary(); - BindCore(section8, ref temp10, binderOptions); + BindCore(section8, ref temp10, defaultValueIfNotFound: false, binderOptions); instance.MyComplexDictionary = temp10; } } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/ConfigurationBinder/Bind_Key_Instance.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/ConfigurationBinder/Bind_Key_Instance.generated.txt index 53de396b69b8a..22e430f70e6b7 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/ConfigurationBinder/Bind_Key_Instance.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/ConfigurationBinder/Bind_Key_Instance.generated.txt @@ -31,7 +31,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration { #region IConfiguration extensions. /// Attempts to bind the given object instance to configuration values by matching property names against configuration keys recursively. - [InterceptsLocationAttribute(@"src-0.cs", 12, 20)] + [InterceptsLocation(@"src-0.cs", 12, 20)] public static void Bind_ProgramMyClass(this IConfiguration configuration, string key, object? instance) { ArgumentNullException.ThrowIfNull(configuration); @@ -42,14 +42,14 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration } var typedObj = (Program.MyClass)instance; - BindCore(configuration.GetSection(key), ref typedObj, binderOptions: null); + BindCore(configuration.GetSection(key), ref typedObj, defaultValueIfNotFound: false, binderOptions: null); } #endregion IConfiguration extensions. #region Core binding extensions. private readonly static Lazy> s_configKeys_ProgramMyClass = new(() => new HashSet(StringComparer.OrdinalIgnoreCase) { "MyString", "MyInt", "MyList", "MyDictionary", "MyComplexDictionary" }); - public static void BindCore(IConfiguration configuration, ref List instance, BinderOptions? binderOptions) + public static void BindCore(IConfiguration configuration, ref List instance, bool defaultValueIfNotFound, BinderOptions? binderOptions) { foreach (IConfigurationSection section in configuration.GetChildren()) { @@ -60,7 +60,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration } } - public static void BindCore(IConfiguration configuration, ref Dictionary instance, BinderOptions? binderOptions) + public static void BindCore(IConfiguration configuration, ref Dictionary instance, bool defaultValueIfNotFound, BinderOptions? binderOptions) { foreach (IConfigurationSection section in configuration.GetChildren()) { @@ -71,7 +71,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration } } - public static void BindCore(IConfiguration configuration, ref Dictionary instance, BinderOptions? binderOptions) + public static void BindCore(IConfiguration configuration, ref Dictionary instance, bool defaultValueIfNotFound, BinderOptions? binderOptions) { foreach (IConfigurationSection section in configuration.GetChildren()) { @@ -83,22 +83,29 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration } } - public static void BindCore(IConfiguration configuration, ref Program.MyClass instance, BinderOptions? binderOptions) + public static void BindCore(IConfiguration configuration, ref Program.MyClass instance, bool defaultValueIfNotFound, BinderOptions? binderOptions) { ValidateConfigurationKeys(typeof(Program.MyClass), s_configKeys_ProgramMyClass, configuration, binderOptions); - instance.MyString = configuration["MyString"]!; + if (configuration["MyString"] is string value0) + { + instance.MyString = value0; + } if (configuration["MyInt"] is string value1) { instance.MyInt = ParseInt(value1, () => configuration.GetSection("MyInt").Path); } + else if (defaultValueIfNotFound) + { + instance.MyInt = default; + } if (AsConfigWithChildren(configuration.GetSection("MyList")) is IConfigurationSection section2) { List? temp4 = instance.MyList; temp4 ??= new List(); - BindCore(section2, ref temp4, binderOptions); + BindCore(section2, ref temp4, defaultValueIfNotFound: false, binderOptions); instance.MyList = temp4; } @@ -106,7 +113,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration { Dictionary? temp7 = instance.MyDictionary; temp7 ??= new Dictionary(); - BindCore(section5, ref temp7, binderOptions); + BindCore(section5, ref temp7, defaultValueIfNotFound: false, binderOptions); instance.MyDictionary = temp7; } @@ -114,7 +121,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration { Dictionary? temp10 = instance.MyComplexDictionary; temp10 ??= new Dictionary(); - BindCore(section8, ref temp10, binderOptions); + BindCore(section8, ref temp10, defaultValueIfNotFound: false, binderOptions); instance.MyComplexDictionary = temp10; } } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/ConfigurationBinder/Bind_ParseTypeFromMethodParam.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/ConfigurationBinder/Bind_ParseTypeFromMethodParam.generated.txt new file mode 100644 index 0000000000000..14753a4a1f8e4 --- /dev/null +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/ConfigurationBinder/Bind_ParseTypeFromMethodParam.generated.txt @@ -0,0 +1,72 @@ +// +#nullable enable +#pragma warning disable CS0612, CS0618 // Suppress warnings about [Obsolete] member usage in generated code. + +namespace System.Runtime.CompilerServices +{ + using System; + using System.CodeDom.Compiler; + + [GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")] + [AttributeUsage(AttributeTargets.Method, AllowMultiple = true)] + file sealed class InterceptsLocationAttribute : Attribute + { + public InterceptsLocationAttribute(string filePath, int line, int column) + { + } + } +} + +namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration +{ + using Microsoft.Extensions.Configuration; + using System; + using System.CodeDom.Compiler; + using System.Collections.Generic; + using System.Globalization; + using System.Runtime.CompilerServices; + + [GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")] + file static class BindingExtensions + { + #region IConfiguration extensions. + /// Attempts to bind the given object instance to configuration values by matching property names against configuration keys recursively. + [InterceptsLocation(@"src-0.cs", 18, 16)] + public static void Bind_ProgramMyClass0(this IConfiguration configuration, object? instance) + { + } + + /// Attempts to bind the given object instance to configuration values by matching property names against configuration keys recursively. + [InterceptsLocation(@"src-0.cs", 23, 16)] + public static void Bind_ProgramMyClass1(this IConfiguration configuration, object? instance, Action? configureOptions) + { + } + + /// Attempts to bind the given object instance to configuration values by matching property names against configuration keys recursively. + [InterceptsLocation(@"src-0.cs", 28, 16)] + public static void Bind_ProgramMyClass2(this IConfiguration configuration, string key, object? instance) + { + } + #endregion IConfiguration extensions. + + #region Core binding extensions. + public static BinderOptions? GetBinderOptions(Action? configureOptions) + { + if (configureOptions is null) + { + return null; + } + + BinderOptions binderOptions = new(); + configureOptions(binderOptions); + + if (binderOptions.BindNonPublicProperties) + { + throw new NotSupportedException($"The configuration binding source generator does not support 'BinderOptions.BindNonPublicProperties'."); + } + + return binderOptions; + } + #endregion Core binding extensions. + } +} diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/ConfigurationBinder/Get.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/ConfigurationBinder/Get.generated.txt index eb07147617d7a..bac51d3c24420 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/ConfigurationBinder/Get.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/ConfigurationBinder/Get.generated.txt @@ -31,19 +31,19 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration { #region IConfiguration extensions. /// Attempts to bind the configuration instance to a new instance of type T. - [InterceptsLocationAttribute(@"src-0.cs", 12, 38)] + [InterceptsLocation(@"src-0.cs", 12, 38)] public static T? Get(this IConfiguration configuration) => (T?)(GetCore(configuration, typeof(T), configureOptions: null) ?? default(T)); /// Attempts to bind the configuration instance to a new instance of type T. - [InterceptsLocationAttribute(@"src-0.cs", 14, 36)] + [InterceptsLocation(@"src-0.cs", 14, 36)] public static T? Get(this IConfiguration configuration, Action? configureOptions) => (T?)(GetCore(configuration, typeof(T), configureOptions) ?? default(T)); /// Attempts to bind the configuration instance to a new instance of type T. - [InterceptsLocationAttribute(@"src-0.cs", 13, 36)] + [InterceptsLocation(@"src-0.cs", 13, 56)] public static object? Get(this IConfiguration configuration, Type type) => GetCore(configuration, type, configureOptions: null); /// Attempts to bind the configuration instance to a new instance of type T. - [InterceptsLocationAttribute(@"src-0.cs", 15, 36)] + [InterceptsLocation(@"src-0.cs", 15, 47)] public static object? Get(this IConfiguration configuration, Type type, Action? configureOptions) => GetCore(configuration, type, configureOptions); #endregion IConfiguration extensions. @@ -65,20 +65,20 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration if (type == typeof(Program.MyClass)) { var instance = new Program.MyClass(); - BindCore(configuration, ref instance, binderOptions); + BindCore(configuration, ref instance, defaultValueIfNotFound: true, binderOptions); return instance; } else if (type == typeof(Program.MyClass2)) { var instance = new Program.MyClass2(); - BindCore(configuration, ref instance, binderOptions); + BindCore(configuration, ref instance, defaultValueIfNotFound: true, binderOptions); return instance; } throw new NotSupportedException($"Unable to bind to type '{type}': generator did not detect the type as input."); } - public static void BindCore(IConfiguration configuration, ref List instance, BinderOptions? binderOptions) + public static void BindCore(IConfiguration configuration, ref List instance, bool defaultValueIfNotFound, BinderOptions? binderOptions) { foreach (IConfigurationSection section in configuration.GetChildren()) { @@ -89,16 +89,16 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration } } - public static void BindCore(IConfiguration configuration, ref int[] instance, BinderOptions? binderOptions) + public static void BindCore(IConfiguration configuration, ref int[] instance, bool defaultValueIfNotFound, BinderOptions? binderOptions) { var temp2 = new List(); - BindCore(configuration, ref temp2, binderOptions); + BindCore(configuration, ref temp2, defaultValueIfNotFound: false, binderOptions); int originalCount = instance.Length; Array.Resize(ref instance, originalCount + temp2.Count); temp2.CopyTo(instance, originalCount); } - public static void BindCore(IConfiguration configuration, ref Dictionary instance, BinderOptions? binderOptions) + public static void BindCore(IConfiguration configuration, ref Dictionary instance, bool defaultValueIfNotFound, BinderOptions? binderOptions) { foreach (IConfigurationSection section in configuration.GetChildren()) { @@ -109,22 +109,29 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration } } - public static void BindCore(IConfiguration configuration, ref Program.MyClass instance, BinderOptions? binderOptions) + public static void BindCore(IConfiguration configuration, ref Program.MyClass instance, bool defaultValueIfNotFound, BinderOptions? binderOptions) { ValidateConfigurationKeys(typeof(Program.MyClass), s_configKeys_ProgramMyClass, configuration, binderOptions); - instance.MyString = configuration["MyString"]!; + if (configuration["MyString"] is string value4) + { + instance.MyString = value4; + } if (configuration["MyInt"] is string value5) { instance.MyInt = ParseInt(value5, () => configuration.GetSection("MyInt").Path); } + else if (defaultValueIfNotFound) + { + instance.MyInt = default; + } if (AsConfigWithChildren(configuration.GetSection("MyList")) is IConfigurationSection section6) { List? temp8 = instance.MyList; temp8 ??= new List(); - BindCore(section6, ref temp8, binderOptions); + BindCore(section6, ref temp8, defaultValueIfNotFound: false, binderOptions); instance.MyList = temp8; } @@ -132,7 +139,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration { int[]? temp11 = instance.MyArray; temp11 ??= new int[0]; - BindCore(section9, ref temp11, binderOptions); + BindCore(section9, ref temp11, defaultValueIfNotFound: false, binderOptions); instance.MyArray = temp11; } @@ -140,12 +147,12 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration { Dictionary? temp14 = instance.MyDictionary; temp14 ??= new Dictionary(); - BindCore(section12, ref temp14, binderOptions); + BindCore(section12, ref temp14, defaultValueIfNotFound: false, binderOptions); instance.MyDictionary = temp14; } } - public static void BindCore(IConfiguration configuration, ref Program.MyClass2 instance, BinderOptions? binderOptions) + public static void BindCore(IConfiguration configuration, ref Program.MyClass2 instance, bool defaultValueIfNotFound, BinderOptions? binderOptions) { ValidateConfigurationKeys(typeof(Program.MyClass2), s_configKeys_ProgramMyClass2, configuration, binderOptions); @@ -153,6 +160,10 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration { instance.MyInt = ParseInt(value15, () => configuration.GetSection("MyInt").Path); } + else if (defaultValueIfNotFound) + { + instance.MyInt = default; + } } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/ConfigurationBinder/GetValue.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/ConfigurationBinder/GetValue.generated.txt index 7f953e8bee734..cd7bd92c05b8d 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/ConfigurationBinder/GetValue.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/ConfigurationBinder/GetValue.generated.txt @@ -30,19 +30,19 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration { #region IConfiguration extensions. /// Extracts the value with the specified key and converts it to the specified type. - [InterceptsLocationAttribute(@"src-0.cs", 13, 18)] + [InterceptsLocation(@"src-0.cs", 13, 18)] public static T? GetValue(this IConfiguration configuration, string key) => (T?)(BindingExtensions.GetValueCore(configuration, typeof(T), key) ?? default(T)); /// Extracts the value with the specified key and converts it to the specified type. - [InterceptsLocationAttribute(@"src-0.cs", 16, 24)] + [InterceptsLocation(@"src-0.cs", 16, 24)] public static T? GetValue(this IConfiguration configuration, string key, T defaultValue) => (T?)(BindingExtensions.GetValueCore(configuration, typeof(T), key) ?? defaultValue); /// Extracts the value with the specified key and converts it to the specified type. - [InterceptsLocationAttribute(@"src-0.cs", 14, 24)] + [InterceptsLocation(@"src-0.cs", 14, 24)] public static object? GetValue(this IConfiguration configuration, Type type, string key) => BindingExtensions.GetValueCore(configuration, type, key); /// Extracts the value with the specified key and converts it to the specified type. - [InterceptsLocationAttribute(@"src-0.cs", 17, 24)] + [InterceptsLocation(@"src-0.cs", 17, 24)] public static object? GetValue(this IConfiguration configuration, Type type, string key, object? defaultValue) => BindingExtensions.GetValueCore(configuration, type, key) ?? defaultValue; #endregion IConfiguration extensions. diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/ConfigurationBinder/GetValue_T_Key.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/ConfigurationBinder/GetValue_T_Key.generated.txt index e32282a61de77..1ebddd4bdc3ac 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/ConfigurationBinder/GetValue_T_Key.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/ConfigurationBinder/GetValue_T_Key.generated.txt @@ -30,7 +30,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration { #region IConfiguration extensions. /// Extracts the value with the specified key and converts it to the specified type. - [InterceptsLocationAttribute(@"src-0.cs", 10, 20)] + [InterceptsLocation(@"src-0.cs", 10, 20)] public static T? GetValue(this IConfiguration configuration, string key) => (T?)(BindingExtensions.GetValueCore(configuration, typeof(T), key) ?? default(T)); #endregion IConfiguration extensions. diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/ConfigurationBinder/GetValue_T_Key_DefaultValue.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/ConfigurationBinder/GetValue_T_Key_DefaultValue.generated.txt index 1d2ef31f595c7..897a937ea31f6 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/ConfigurationBinder/GetValue_T_Key_DefaultValue.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/ConfigurationBinder/GetValue_T_Key_DefaultValue.generated.txt @@ -30,7 +30,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration { #region IConfiguration extensions. /// Extracts the value with the specified key and converts it to the specified type. - [InterceptsLocationAttribute(@"src-0.cs", 12, 20)] + [InterceptsLocation(@"src-0.cs", 12, 20)] public static T? GetValue(this IConfiguration configuration, string key, T defaultValue) => (T?)(BindingExtensions.GetValueCore(configuration, typeof(T), key) ?? defaultValue); #endregion IConfiguration extensions. diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/ConfigurationBinder/GetValue_TypeOf_Key.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/ConfigurationBinder/GetValue_TypeOf_Key.generated.txt index e82cb9516c514..8fd4c52ad6c93 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/ConfigurationBinder/GetValue_TypeOf_Key.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/ConfigurationBinder/GetValue_TypeOf_Key.generated.txt @@ -30,7 +30,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration { #region IConfiguration extensions. /// Extracts the value with the specified key and converts it to the specified type. - [InterceptsLocationAttribute(@"src-0.cs", 10, 20)] + [InterceptsLocation(@"src-0.cs", 10, 20)] public static object? GetValue(this IConfiguration configuration, Type type, string key) => BindingExtensions.GetValueCore(configuration, type, key); #endregion IConfiguration extensions. diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/ConfigurationBinder/GetValue_TypeOf_Key_DefaultValue.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/ConfigurationBinder/GetValue_TypeOf_Key_DefaultValue.generated.txt index 5973a4a315f15..e500077432612 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/ConfigurationBinder/GetValue_TypeOf_Key_DefaultValue.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/ConfigurationBinder/GetValue_TypeOf_Key_DefaultValue.generated.txt @@ -30,7 +30,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration { #region IConfiguration extensions. /// Extracts the value with the specified key and converts it to the specified type. - [InterceptsLocationAttribute(@"src-0.cs", 11, 20)] + [InterceptsLocation(@"src-0.cs", 11, 20)] public static object? GetValue(this IConfiguration configuration, Type type, string key, object? defaultValue) => BindingExtensions.GetValueCore(configuration, type, key) ?? defaultValue; #endregion IConfiguration extensions. diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/ConfigurationBinder/Get_T.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/ConfigurationBinder/Get_T.generated.txt index f7fa75a30e791..7b7de0ba7d146 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/ConfigurationBinder/Get_T.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/ConfigurationBinder/Get_T.generated.txt @@ -31,7 +31,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration { #region IConfiguration extensions. /// Attempts to bind the configuration instance to a new instance of type T. - [InterceptsLocationAttribute(@"src-0.cs", 11, 40)] + [InterceptsLocation(@"src-0.cs", 11, 40)] public static T? Get(this IConfiguration configuration) => (T?)(GetCore(configuration, typeof(T), configureOptions: null) ?? default(T)); #endregion IConfiguration extensions. @@ -52,14 +52,14 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration if (type == typeof(Program.MyClass)) { var instance = new Program.MyClass(); - BindCore(configuration, ref instance, binderOptions); + BindCore(configuration, ref instance, defaultValueIfNotFound: true, binderOptions); return instance; } throw new NotSupportedException($"Unable to bind to type '{type}': generator did not detect the type as input."); } - public static void BindCore(IConfiguration configuration, ref List instance, BinderOptions? binderOptions) + public static void BindCore(IConfiguration configuration, ref List instance, bool defaultValueIfNotFound, BinderOptions? binderOptions) { foreach (IConfigurationSection section in configuration.GetChildren()) { @@ -70,16 +70,16 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration } } - public static void BindCore(IConfiguration configuration, ref int[] instance, BinderOptions? binderOptions) + public static void BindCore(IConfiguration configuration, ref int[] instance, bool defaultValueIfNotFound, BinderOptions? binderOptions) { var temp1 = new List(); - BindCore(configuration, ref temp1, binderOptions); + BindCore(configuration, ref temp1, defaultValueIfNotFound: false, binderOptions); int originalCount = instance.Length; Array.Resize(ref instance, originalCount + temp1.Count); temp1.CopyTo(instance, originalCount); } - public static void BindCore(IConfiguration configuration, ref Dictionary instance, BinderOptions? binderOptions) + public static void BindCore(IConfiguration configuration, ref Dictionary instance, bool defaultValueIfNotFound, BinderOptions? binderOptions) { foreach (IConfigurationSection section in configuration.GetChildren()) { @@ -90,22 +90,29 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration } } - public static void BindCore(IConfiguration configuration, ref Program.MyClass instance, BinderOptions? binderOptions) + public static void BindCore(IConfiguration configuration, ref Program.MyClass instance, bool defaultValueIfNotFound, BinderOptions? binderOptions) { ValidateConfigurationKeys(typeof(Program.MyClass), s_configKeys_ProgramMyClass, configuration, binderOptions); - instance.MyString = configuration["MyString"]!; + if (configuration["MyString"] is string value3) + { + instance.MyString = value3; + } if (configuration["MyInt"] is string value4) { instance.MyInt = ParseInt(value4, () => configuration.GetSection("MyInt").Path); } + else if (defaultValueIfNotFound) + { + instance.MyInt = default; + } if (AsConfigWithChildren(configuration.GetSection("MyList")) is IConfigurationSection section5) { List? temp7 = instance.MyList; temp7 ??= new List(); - BindCore(section5, ref temp7, binderOptions); + BindCore(section5, ref temp7, defaultValueIfNotFound: false, binderOptions); instance.MyList = temp7; } @@ -113,7 +120,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration { int[]? temp10 = instance.MyArray; temp10 ??= new int[0]; - BindCore(section8, ref temp10, binderOptions); + BindCore(section8, ref temp10, defaultValueIfNotFound: false, binderOptions); instance.MyArray = temp10; } @@ -121,7 +128,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration { Dictionary? temp13 = instance.MyDictionary; temp13 ??= new Dictionary(); - BindCore(section11, ref temp13, binderOptions); + BindCore(section11, ref temp13, defaultValueIfNotFound: false, binderOptions); instance.MyDictionary = temp13; } } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/ConfigurationBinder/Get_T_BinderOptions.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/ConfigurationBinder/Get_T_BinderOptions.generated.txt index 21475909d4447..0243ad41eb3c7 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/ConfigurationBinder/Get_T_BinderOptions.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/ConfigurationBinder/Get_T_BinderOptions.generated.txt @@ -31,7 +31,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration { #region IConfiguration extensions. /// Attempts to bind the configuration instance to a new instance of type T. - [InterceptsLocationAttribute(@"src-0.cs", 11, 40)] + [InterceptsLocation(@"src-0.cs", 11, 40)] public static T? Get(this IConfiguration configuration, Action? configureOptions) => (T?)(GetCore(configuration, typeof(T), configureOptions) ?? default(T)); #endregion IConfiguration extensions. @@ -52,14 +52,14 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration if (type == typeof(Program.MyClass)) { var instance = new Program.MyClass(); - BindCore(configuration, ref instance, binderOptions); + BindCore(configuration, ref instance, defaultValueIfNotFound: true, binderOptions); return instance; } throw new NotSupportedException($"Unable to bind to type '{type}': generator did not detect the type as input."); } - public static void BindCore(IConfiguration configuration, ref List instance, BinderOptions? binderOptions) + public static void BindCore(IConfiguration configuration, ref List instance, bool defaultValueIfNotFound, BinderOptions? binderOptions) { foreach (IConfigurationSection section in configuration.GetChildren()) { @@ -70,16 +70,16 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration } } - public static void BindCore(IConfiguration configuration, ref int[] instance, BinderOptions? binderOptions) + public static void BindCore(IConfiguration configuration, ref int[] instance, bool defaultValueIfNotFound, BinderOptions? binderOptions) { var temp1 = new List(); - BindCore(configuration, ref temp1, binderOptions); + BindCore(configuration, ref temp1, defaultValueIfNotFound: false, binderOptions); int originalCount = instance.Length; Array.Resize(ref instance, originalCount + temp1.Count); temp1.CopyTo(instance, originalCount); } - public static void BindCore(IConfiguration configuration, ref Dictionary instance, BinderOptions? binderOptions) + public static void BindCore(IConfiguration configuration, ref Dictionary instance, bool defaultValueIfNotFound, BinderOptions? binderOptions) { foreach (IConfigurationSection section in configuration.GetChildren()) { @@ -90,22 +90,29 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration } } - public static void BindCore(IConfiguration configuration, ref Program.MyClass instance, BinderOptions? binderOptions) + public static void BindCore(IConfiguration configuration, ref Program.MyClass instance, bool defaultValueIfNotFound, BinderOptions? binderOptions) { ValidateConfigurationKeys(typeof(Program.MyClass), s_configKeys_ProgramMyClass, configuration, binderOptions); - instance.MyString = configuration["MyString"]!; + if (configuration["MyString"] is string value3) + { + instance.MyString = value3; + } if (configuration["MyInt"] is string value4) { instance.MyInt = ParseInt(value4, () => configuration.GetSection("MyInt").Path); } + else if (defaultValueIfNotFound) + { + instance.MyInt = default; + } if (AsConfigWithChildren(configuration.GetSection("MyList")) is IConfigurationSection section5) { List? temp7 = instance.MyList; temp7 ??= new List(); - BindCore(section5, ref temp7, binderOptions); + BindCore(section5, ref temp7, defaultValueIfNotFound: false, binderOptions); instance.MyList = temp7; } @@ -113,7 +120,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration { int[]? temp10 = instance.MyArray; temp10 ??= new int[0]; - BindCore(section8, ref temp10, binderOptions); + BindCore(section8, ref temp10, defaultValueIfNotFound: false, binderOptions); instance.MyArray = temp10; } @@ -121,7 +128,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration { Dictionary? temp13 = instance.MyDictionary; temp13 ??= new Dictionary(); - BindCore(section11, ref temp13, binderOptions); + BindCore(section11, ref temp13, defaultValueIfNotFound: false, binderOptions); instance.MyDictionary = temp13; } } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/ConfigurationBinder/Get_TypeOf.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/ConfigurationBinder/Get_TypeOf.generated.txt index 590a745175280..8818894f387c4 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/ConfigurationBinder/Get_TypeOf.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/ConfigurationBinder/Get_TypeOf.generated.txt @@ -31,7 +31,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration { #region IConfiguration extensions. /// Attempts to bind the configuration instance to a new instance of type T. - [InterceptsLocationAttribute(@"src-0.cs", 11, 40)] + [InterceptsLocation(@"src-0.cs", 11, 51)] public static object? Get(this IConfiguration configuration, Type type) => GetCore(configuration, type, configureOptions: null); #endregion IConfiguration extensions. @@ -52,14 +52,14 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration if (type == typeof(Program.MyClass2)) { var instance = new Program.MyClass2(); - BindCore(configuration, ref instance, binderOptions); + BindCore(configuration, ref instance, defaultValueIfNotFound: true, binderOptions); return instance; } throw new NotSupportedException($"Unable to bind to type '{type}': generator did not detect the type as input."); } - public static void BindCore(IConfiguration configuration, ref Program.MyClass2 instance, BinderOptions? binderOptions) + public static void BindCore(IConfiguration configuration, ref Program.MyClass2 instance, bool defaultValueIfNotFound, BinderOptions? binderOptions) { ValidateConfigurationKeys(typeof(Program.MyClass2), s_configKeys_ProgramMyClass2, configuration, binderOptions); @@ -67,6 +67,10 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration { instance.MyInt = ParseInt(value1, () => configuration.GetSection("MyInt").Path); } + else if (defaultValueIfNotFound) + { + instance.MyInt = default; + } } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/ConfigurationBinder/Get_TypeOf_BinderOptions.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/ConfigurationBinder/Get_TypeOf_BinderOptions.generated.txt index 322d7c2eb5ee0..6202545f7ae8d 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/ConfigurationBinder/Get_TypeOf_BinderOptions.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/ConfigurationBinder/Get_TypeOf_BinderOptions.generated.txt @@ -31,7 +31,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration { #region IConfiguration extensions. /// Attempts to bind the configuration instance to a new instance of type T. - [InterceptsLocationAttribute(@"src-0.cs", 11, 20)] + [InterceptsLocation(@"src-0.cs", 11, 20)] public static object? Get(this IConfiguration configuration, Type type, Action? configureOptions) => GetCore(configuration, type, configureOptions); #endregion IConfiguration extensions. @@ -52,14 +52,14 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration if (type == typeof(Program.MyClass2)) { var instance = new Program.MyClass2(); - BindCore(configuration, ref instance, binderOptions); + BindCore(configuration, ref instance, defaultValueIfNotFound: true, binderOptions); return instance; } throw new NotSupportedException($"Unable to bind to type '{type}': generator did not detect the type as input."); } - public static void BindCore(IConfiguration configuration, ref Program.MyClass2 instance, BinderOptions? binderOptions) + public static void BindCore(IConfiguration configuration, ref Program.MyClass2 instance, bool defaultValueIfNotFound, BinderOptions? binderOptions) { ValidateConfigurationKeys(typeof(Program.MyClass2), s_configKeys_ProgramMyClass2, configuration, binderOptions); @@ -67,6 +67,10 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration { instance.MyInt = ParseInt(value1, () => configuration.GetSection("MyInt").Path); } + else if (defaultValueIfNotFound) + { + instance.MyInt = default; + } } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/EmptyConfigType.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/EmptyConfigType.generated.txt new file mode 100644 index 0000000000000..0bb9d336b81e9 --- /dev/null +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/EmptyConfigType.generated.txt @@ -0,0 +1,101 @@ +// +#nullable enable +#pragma warning disable CS0612, CS0618 // Suppress warnings about [Obsolete] member usage in generated code. + +namespace System.Runtime.CompilerServices +{ + using System; + using System.CodeDom.Compiler; + + [GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")] + [AttributeUsage(AttributeTargets.Method, AllowMultiple = true)] + file sealed class InterceptsLocationAttribute : Attribute + { + public InterceptsLocationAttribute(string filePath, int line, int column) + { + } + } +} + +namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration +{ + using Microsoft.Extensions.Configuration; + using System; + using System.CodeDom.Compiler; + using System.Collections.Generic; + using System.Globalization; + using System.Runtime.CompilerServices; + + [GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")] + file static class BindingExtensions + { + #region IConfiguration extensions. + /// Attempts to bind the given object instance to configuration values by matching property names against configuration keys recursively. + [InterceptsLocation(@"src-0.cs", 12, 23)] + public static void Bind_TypeWithNoMembers(this IConfiguration configuration, object? instance) + { + } + + /// Attempts to bind the given object instance to configuration values by matching property names against configuration keys recursively. + [InterceptsLocation(@"src-0.cs", 15, 23)] + public static void Bind_TypeWithNoMembers_Wrapper(this IConfiguration configuration, object? instance) + { + ArgumentNullException.ThrowIfNull(configuration); + + if (instance is null) + { + return; + } + + var typedObj = (TypeWithNoMembers_Wrapper)instance; + BindCore(configuration, ref typedObj, defaultValueIfNotFound: false, binderOptions: null); + } + #endregion IConfiguration extensions. + + #region Core binding extensions. + private readonly static Lazy> s_configKeys_TypeWithNoMembers_Wrapper = new(() => new HashSet(StringComparer.OrdinalIgnoreCase) { "Member" }); + + public static void BindCore(IConfiguration configuration, ref TypeWithNoMembers_Wrapper instance, bool defaultValueIfNotFound, BinderOptions? binderOptions) + { + ValidateConfigurationKeys(typeof(TypeWithNoMembers_Wrapper), s_configKeys_TypeWithNoMembers_Wrapper, configuration, binderOptions); + + if (AsConfigWithChildren(configuration.GetSection("Member")) is IConfigurationSection section0) + { + instance.Member ??= new TypeWithNoMembers(); + } + } + + + /// If required by the binder options, validates that there are no unknown keys in the input configuration object. + public static void ValidateConfigurationKeys(Type type, Lazy> keys, IConfiguration configuration, BinderOptions? binderOptions) + { + if (binderOptions?.ErrorOnUnknownConfiguration is true) + { + List? temp = null; + + foreach (IConfigurationSection section in configuration.GetChildren()) + { + if (!keys.Value.Contains(section.Key)) + { + (temp ??= new List()).Add($"'{section.Key}'"); + } + } + + if (temp is not null) + { + throw new InvalidOperationException($"'ErrorOnUnknownConfiguration' was set on the provided BinderOptions, but the following properties were not found on the instance of {type}: {string.Join(", ", temp)}"); + } + } + } + + public static IConfiguration? AsConfigWithChildren(IConfiguration configuration) + { + foreach (IConfigurationSection _ in configuration.GetChildren()) + { + return configuration; + } + return null; + } + #endregion Core binding extensions. + } +} diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/OptionsBuilder/BindConfiguration.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/OptionsBuilder/BindConfiguration.generated.txt index 62e6228266d16..682eacc221dde 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/OptionsBuilder/BindConfiguration.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/OptionsBuilder/BindConfiguration.generated.txt @@ -33,7 +33,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration { #region OptionsBuilder extensions. /// Registers the dependency injection container to bind against the obtained from the DI service provider. - [InterceptsLocationAttribute(@"src-0.cs", 12, 24)] + [InterceptsLocation(@"src-0.cs", 12, 24)] public static OptionsBuilder BindConfiguration(this OptionsBuilder optionsBuilder, string configSectionPath, Action? configureBinder = null) where TOptions : class { ArgumentNullException.ThrowIfNull(optionsBuilder); @@ -73,14 +73,14 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration if (type == typeof(Program.MyClass)) { var temp = (Program.MyClass)instance; - BindCore(configuration, ref temp, binderOptions); + BindCore(configuration, ref temp, defaultValueIfNotFound: false, binderOptions); return; } throw new NotSupportedException($"Unable to bind to type '{type}': generator did not detect the type as input."); } - public static void BindCore(IConfiguration configuration, ref List instance, BinderOptions? binderOptions) + public static void BindCore(IConfiguration configuration, ref List instance, bool defaultValueIfNotFound, BinderOptions? binderOptions) { foreach (IConfigurationSection section in configuration.GetChildren()) { @@ -91,22 +91,29 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration } } - public static void BindCore(IConfiguration configuration, ref Program.MyClass instance, BinderOptions? binderOptions) + public static void BindCore(IConfiguration configuration, ref Program.MyClass instance, bool defaultValueIfNotFound, BinderOptions? binderOptions) { ValidateConfigurationKeys(typeof(Program.MyClass), s_configKeys_ProgramMyClass, configuration, binderOptions); - instance.MyString = configuration["MyString"]!; + if (configuration["MyString"] is string value1) + { + instance.MyString = value1; + } if (configuration["MyInt"] is string value2) { instance.MyInt = ParseInt(value2, () => configuration.GetSection("MyInt").Path); } + else if (defaultValueIfNotFound) + { + instance.MyInt = default; + } if (AsConfigWithChildren(configuration.GetSection("MyList")) is IConfigurationSection section3) { List? temp5 = instance.MyList; temp5 ??= new List(); - BindCore(section3, ref temp5, binderOptions); + BindCore(section3, ref temp5, defaultValueIfNotFound: false, binderOptions); instance.MyList = temp5; } } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/OptionsBuilder/Bind_T.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/OptionsBuilder/Bind_T.generated.txt index be3d065da5f06..76023bb8f04e2 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/OptionsBuilder/Bind_T.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/OptionsBuilder/Bind_T.generated.txt @@ -33,7 +33,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration { #region OptionsBuilder extensions. /// Registers a configuration instance which will bind against. - [InterceptsLocationAttribute(@"src-0.cs", 15, 24)] + [InterceptsLocation(@"src-0.cs", 15, 24)] public static OptionsBuilder Bind(this OptionsBuilder optionsBuilder, IConfiguration config) where TOptions : class { return Bind(optionsBuilder, config, configureBinder: null); @@ -83,14 +83,14 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration if (type == typeof(Program.MyClass)) { var temp = (Program.MyClass)instance; - BindCore(configuration, ref temp, binderOptions); + BindCore(configuration, ref temp, defaultValueIfNotFound: false, binderOptions); return; } throw new NotSupportedException($"Unable to bind to type '{type}': generator did not detect the type as input."); } - public static void BindCore(IConfiguration configuration, ref List instance, BinderOptions? binderOptions) + public static void BindCore(IConfiguration configuration, ref List instance, bool defaultValueIfNotFound, BinderOptions? binderOptions) { foreach (IConfigurationSection section in configuration.GetChildren()) { @@ -101,22 +101,29 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration } } - public static void BindCore(IConfiguration configuration, ref Program.MyClass instance, BinderOptions? binderOptions) + public static void BindCore(IConfiguration configuration, ref Program.MyClass instance, bool defaultValueIfNotFound, BinderOptions? binderOptions) { ValidateConfigurationKeys(typeof(Program.MyClass), s_configKeys_ProgramMyClass, configuration, binderOptions); - instance.MyString = configuration["MyString"]!; + if (configuration["MyString"] is string value1) + { + instance.MyString = value1; + } if (configuration["MyInt"] is string value2) { instance.MyInt = ParseInt(value2, () => configuration.GetSection("MyInt").Path); } + else if (defaultValueIfNotFound) + { + instance.MyInt = default; + } if (AsConfigWithChildren(configuration.GetSection("MyList")) is IConfigurationSection section3) { List? temp5 = instance.MyList; temp5 ??= new List(); - BindCore(section3, ref temp5, binderOptions); + BindCore(section3, ref temp5, defaultValueIfNotFound: false, binderOptions); instance.MyList = temp5; } } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/OptionsBuilder/Bind_T_BinderOptions.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/OptionsBuilder/Bind_T_BinderOptions.generated.txt index 905537274c667..c6336da8dfaec 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/OptionsBuilder/Bind_T_BinderOptions.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/OptionsBuilder/Bind_T_BinderOptions.generated.txt @@ -33,7 +33,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration { #region OptionsBuilder extensions. /// Registers a configuration instance which will bind against. - [InterceptsLocationAttribute(@"src-0.cs", 15, 24)] + [InterceptsLocation(@"src-0.cs", 15, 24)] public static OptionsBuilder Bind(this OptionsBuilder optionsBuilder, IConfiguration config, Action? configureBinder) where TOptions : class { ArgumentNullException.ThrowIfNull(optionsBuilder); @@ -77,14 +77,14 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration if (type == typeof(Program.MyClass)) { var temp = (Program.MyClass)instance; - BindCore(configuration, ref temp, binderOptions); + BindCore(configuration, ref temp, defaultValueIfNotFound: false, binderOptions); return; } throw new NotSupportedException($"Unable to bind to type '{type}': generator did not detect the type as input."); } - public static void BindCore(IConfiguration configuration, ref List instance, BinderOptions? binderOptions) + public static void BindCore(IConfiguration configuration, ref List instance, bool defaultValueIfNotFound, BinderOptions? binderOptions) { foreach (IConfigurationSection section in configuration.GetChildren()) { @@ -95,22 +95,29 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration } } - public static void BindCore(IConfiguration configuration, ref Program.MyClass instance, BinderOptions? binderOptions) + public static void BindCore(IConfiguration configuration, ref Program.MyClass instance, bool defaultValueIfNotFound, BinderOptions? binderOptions) { ValidateConfigurationKeys(typeof(Program.MyClass), s_configKeys_ProgramMyClass, configuration, binderOptions); - instance.MyString = configuration["MyString"]!; + if (configuration["MyString"] is string value1) + { + instance.MyString = value1; + } if (configuration["MyInt"] is string value2) { instance.MyInt = ParseInt(value2, () => configuration.GetSection("MyInt").Path); } + else if (defaultValueIfNotFound) + { + instance.MyInt = default; + } if (AsConfigWithChildren(configuration.GetSection("MyList")) is IConfigurationSection section3) { List? temp5 = instance.MyList; temp5 ??= new List(); - BindCore(section3, ref temp5, binderOptions); + BindCore(section3, ref temp5, defaultValueIfNotFound: false, binderOptions); instance.MyList = temp5; } } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/ServiceCollection/Configure_T.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/ServiceCollection/Configure_T.generated.txt index 60da6ae0b0b45..5d5b84cc1765a 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/ServiceCollection/Configure_T.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/ServiceCollection/Configure_T.generated.txt @@ -21,6 +21,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration { using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; + using Microsoft.Extensions.Options; using System; using System.CodeDom.Compiler; using System.Collections.Generic; @@ -32,7 +33,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration { #region IServiceCollection extensions. /// Registers a configuration instance which TOptions will bind against. - [InterceptsLocationAttribute(@"src-0.cs", 14, 18)] + [InterceptsLocation(@"src-0.cs", 14, 18)] public static IServiceCollection Configure(this IServiceCollection services, IConfiguration config) where TOptions : class { return Configure(services, string.Empty, config, configureOptions: null); @@ -72,14 +73,14 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration if (type == typeof(Program.MyClass)) { var temp = (Program.MyClass)instance; - BindCore(configuration, ref temp, binderOptions); + BindCore(configuration, ref temp, defaultValueIfNotFound: false, binderOptions); return; } throw new NotSupportedException($"Unable to bind to type '{type}': generator did not detect the type as input."); } - public static void BindCore(IConfiguration configuration, ref List instance, BinderOptions? binderOptions) + public static void BindCore(IConfiguration configuration, ref List instance, bool defaultValueIfNotFound, BinderOptions? binderOptions) { foreach (IConfigurationSection section in configuration.GetChildren()) { @@ -90,7 +91,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration } } - public static void BindCore(IConfiguration configuration, ref Program.MyClass2 instance, BinderOptions? binderOptions) + public static void BindCore(IConfiguration configuration, ref Program.MyClass2 instance, bool defaultValueIfNotFound, BinderOptions? binderOptions) { ValidateConfigurationKeys(typeof(Program.MyClass2), s_configKeys_ProgramMyClass2, configuration, binderOptions); @@ -98,19 +99,23 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration { instance.MyInt = ParseInt(value1, () => configuration.GetSection("MyInt").Path); } + else if (defaultValueIfNotFound) + { + instance.MyInt = default; + } } - public static void BindCore(IConfiguration configuration, ref List instance, BinderOptions? binderOptions) + public static void BindCore(IConfiguration configuration, ref List instance, bool defaultValueIfNotFound, BinderOptions? binderOptions) { foreach (IConfigurationSection section in configuration.GetChildren()) { var value = new Program.MyClass2(); - BindCore(section, ref value, binderOptions); + BindCore(section, ref value, defaultValueIfNotFound: false, binderOptions); instance.Add(value); } } - public static void BindCore(IConfiguration configuration, ref Dictionary instance, BinderOptions? binderOptions) + public static void BindCore(IConfiguration configuration, ref Dictionary instance, bool defaultValueIfNotFound, BinderOptions? binderOptions) { foreach (IConfigurationSection section in configuration.GetChildren()) { @@ -121,22 +126,29 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration } } - public static void BindCore(IConfiguration configuration, ref Program.MyClass instance, BinderOptions? binderOptions) + public static void BindCore(IConfiguration configuration, ref Program.MyClass instance, bool defaultValueIfNotFound, BinderOptions? binderOptions) { ValidateConfigurationKeys(typeof(Program.MyClass), s_configKeys_ProgramMyClass, configuration, binderOptions); - instance.MyString = configuration["MyString"]!; + if (configuration["MyString"] is string value3) + { + instance.MyString = value3; + } if (configuration["MyInt"] is string value4) { instance.MyInt = ParseInt(value4, () => configuration.GetSection("MyInt").Path); } + else if (defaultValueIfNotFound) + { + instance.MyInt = default; + } if (AsConfigWithChildren(configuration.GetSection("MyList")) is IConfigurationSection section5) { List? temp7 = instance.MyList; temp7 ??= new List(); - BindCore(section5, ref temp7, binderOptions); + BindCore(section5, ref temp7, defaultValueIfNotFound: false, binderOptions); instance.MyList = temp7; } @@ -144,7 +156,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration { List? temp10 = instance.MyList2; temp10 ??= new List(); - BindCore(section8, ref temp10, binderOptions); + BindCore(section8, ref temp10, defaultValueIfNotFound: false, binderOptions); instance.MyList2 = temp10; } @@ -152,7 +164,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration { Dictionary? temp13 = instance.MyDictionary; temp13 ??= new Dictionary(); - BindCore(section11, ref temp13, binderOptions); + BindCore(section11, ref temp13, defaultValueIfNotFound: false, binderOptions); instance.MyDictionary = temp13; } } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/ServiceCollection/Configure_T_BinderOptions.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/ServiceCollection/Configure_T_BinderOptions.generated.txt index 682131e6f2e97..9c75578aef9f7 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/ServiceCollection/Configure_T_BinderOptions.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/ServiceCollection/Configure_T_BinderOptions.generated.txt @@ -21,6 +21,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration { using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; + using Microsoft.Extensions.Options; using System; using System.CodeDom.Compiler; using System.Collections.Generic; @@ -32,7 +33,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration { #region IServiceCollection extensions. /// Registers a configuration instance which TOptions will bind against. - [InterceptsLocationAttribute(@"src-0.cs", 14, 18)] + [InterceptsLocation(@"src-0.cs", 14, 18)] public static IServiceCollection Configure(this IServiceCollection services, IConfiguration config, Action? configureOptions) where TOptions : class { return Configure(services, string.Empty, config, configureOptions); @@ -72,14 +73,14 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration if (type == typeof(Program.MyClass)) { var temp = (Program.MyClass)instance; - BindCore(configuration, ref temp, binderOptions); + BindCore(configuration, ref temp, defaultValueIfNotFound: false, binderOptions); return; } throw new NotSupportedException($"Unable to bind to type '{type}': generator did not detect the type as input."); } - public static void BindCore(IConfiguration configuration, ref List instance, BinderOptions? binderOptions) + public static void BindCore(IConfiguration configuration, ref List instance, bool defaultValueIfNotFound, BinderOptions? binderOptions) { foreach (IConfigurationSection section in configuration.GetChildren()) { @@ -90,7 +91,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration } } - public static void BindCore(IConfiguration configuration, ref Program.MyClass2 instance, BinderOptions? binderOptions) + public static void BindCore(IConfiguration configuration, ref Program.MyClass2 instance, bool defaultValueIfNotFound, BinderOptions? binderOptions) { ValidateConfigurationKeys(typeof(Program.MyClass2), s_configKeys_ProgramMyClass2, configuration, binderOptions); @@ -98,19 +99,23 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration { instance.MyInt = ParseInt(value1, () => configuration.GetSection("MyInt").Path); } + else if (defaultValueIfNotFound) + { + instance.MyInt = default; + } } - public static void BindCore(IConfiguration configuration, ref List instance, BinderOptions? binderOptions) + public static void BindCore(IConfiguration configuration, ref List instance, bool defaultValueIfNotFound, BinderOptions? binderOptions) { foreach (IConfigurationSection section in configuration.GetChildren()) { var value = new Program.MyClass2(); - BindCore(section, ref value, binderOptions); + BindCore(section, ref value, defaultValueIfNotFound: false, binderOptions); instance.Add(value); } } - public static void BindCore(IConfiguration configuration, ref Dictionary instance, BinderOptions? binderOptions) + public static void BindCore(IConfiguration configuration, ref Dictionary instance, bool defaultValueIfNotFound, BinderOptions? binderOptions) { foreach (IConfigurationSection section in configuration.GetChildren()) { @@ -121,22 +126,29 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration } } - public static void BindCore(IConfiguration configuration, ref Program.MyClass instance, BinderOptions? binderOptions) + public static void BindCore(IConfiguration configuration, ref Program.MyClass instance, bool defaultValueIfNotFound, BinderOptions? binderOptions) { ValidateConfigurationKeys(typeof(Program.MyClass), s_configKeys_ProgramMyClass, configuration, binderOptions); - instance.MyString = configuration["MyString"]!; + if (configuration["MyString"] is string value3) + { + instance.MyString = value3; + } if (configuration["MyInt"] is string value4) { instance.MyInt = ParseInt(value4, () => configuration.GetSection("MyInt").Path); } + else if (defaultValueIfNotFound) + { + instance.MyInt = default; + } if (AsConfigWithChildren(configuration.GetSection("MyList")) is IConfigurationSection section5) { List? temp7 = instance.MyList; temp7 ??= new List(); - BindCore(section5, ref temp7, binderOptions); + BindCore(section5, ref temp7, defaultValueIfNotFound: false, binderOptions); instance.MyList = temp7; } @@ -144,7 +156,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration { List? temp10 = instance.MyList2; temp10 ??= new List(); - BindCore(section8, ref temp10, binderOptions); + BindCore(section8, ref temp10, defaultValueIfNotFound: false, binderOptions); instance.MyList2 = temp10; } @@ -152,7 +164,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration { Dictionary? temp13 = instance.MyDictionary; temp13 ??= new Dictionary(); - BindCore(section11, ref temp13, binderOptions); + BindCore(section11, ref temp13, defaultValueIfNotFound: false, binderOptions); instance.MyDictionary = temp13; } } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/ServiceCollection/Configure_T_name.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/ServiceCollection/Configure_T_name.generated.txt index 417c7a8dfb9ad..6d396b26bdefd 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/ServiceCollection/Configure_T_name.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/ServiceCollection/Configure_T_name.generated.txt @@ -21,6 +21,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration { using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; + using Microsoft.Extensions.Options; using System; using System.CodeDom.Compiler; using System.Collections.Generic; @@ -32,7 +33,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration { #region IServiceCollection extensions. /// Registers a configuration instance which TOptions will bind against. - [InterceptsLocationAttribute(@"src-0.cs", 14, 18)] + [InterceptsLocation(@"src-0.cs", 14, 18)] public static IServiceCollection Configure(this IServiceCollection services, string? name, IConfiguration config) where TOptions : class { return Configure(services, name, config, configureOptions: null); @@ -72,14 +73,14 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration if (type == typeof(Program.MyClass)) { var temp = (Program.MyClass)instance; - BindCore(configuration, ref temp, binderOptions); + BindCore(configuration, ref temp, defaultValueIfNotFound: false, binderOptions); return; } throw new NotSupportedException($"Unable to bind to type '{type}': generator did not detect the type as input."); } - public static void BindCore(IConfiguration configuration, ref List instance, BinderOptions? binderOptions) + public static void BindCore(IConfiguration configuration, ref List instance, bool defaultValueIfNotFound, BinderOptions? binderOptions) { foreach (IConfigurationSection section in configuration.GetChildren()) { @@ -90,7 +91,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration } } - public static void BindCore(IConfiguration configuration, ref Program.MyClass2 instance, BinderOptions? binderOptions) + public static void BindCore(IConfiguration configuration, ref Program.MyClass2 instance, bool defaultValueIfNotFound, BinderOptions? binderOptions) { ValidateConfigurationKeys(typeof(Program.MyClass2), s_configKeys_ProgramMyClass2, configuration, binderOptions); @@ -98,19 +99,23 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration { instance.MyInt = ParseInt(value1, () => configuration.GetSection("MyInt").Path); } + else if (defaultValueIfNotFound) + { + instance.MyInt = default; + } } - public static void BindCore(IConfiguration configuration, ref List instance, BinderOptions? binderOptions) + public static void BindCore(IConfiguration configuration, ref List instance, bool defaultValueIfNotFound, BinderOptions? binderOptions) { foreach (IConfigurationSection section in configuration.GetChildren()) { var value = new Program.MyClass2(); - BindCore(section, ref value, binderOptions); + BindCore(section, ref value, defaultValueIfNotFound: false, binderOptions); instance.Add(value); } } - public static void BindCore(IConfiguration configuration, ref Dictionary instance, BinderOptions? binderOptions) + public static void BindCore(IConfiguration configuration, ref Dictionary instance, bool defaultValueIfNotFound, BinderOptions? binderOptions) { foreach (IConfigurationSection section in configuration.GetChildren()) { @@ -121,22 +126,29 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration } } - public static void BindCore(IConfiguration configuration, ref Program.MyClass instance, BinderOptions? binderOptions) + public static void BindCore(IConfiguration configuration, ref Program.MyClass instance, bool defaultValueIfNotFound, BinderOptions? binderOptions) { ValidateConfigurationKeys(typeof(Program.MyClass), s_configKeys_ProgramMyClass, configuration, binderOptions); - instance.MyString = configuration["MyString"]!; + if (configuration["MyString"] is string value3) + { + instance.MyString = value3; + } if (configuration["MyInt"] is string value4) { instance.MyInt = ParseInt(value4, () => configuration.GetSection("MyInt").Path); } + else if (defaultValueIfNotFound) + { + instance.MyInt = default; + } if (AsConfigWithChildren(configuration.GetSection("MyList")) is IConfigurationSection section5) { List? temp7 = instance.MyList; temp7 ??= new List(); - BindCore(section5, ref temp7, binderOptions); + BindCore(section5, ref temp7, defaultValueIfNotFound: false, binderOptions); instance.MyList = temp7; } @@ -144,7 +156,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration { List? temp10 = instance.MyList2; temp10 ??= new List(); - BindCore(section8, ref temp10, binderOptions); + BindCore(section8, ref temp10, defaultValueIfNotFound: false, binderOptions); instance.MyList2 = temp10; } @@ -152,7 +164,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration { Dictionary? temp13 = instance.MyDictionary; temp13 ??= new Dictionary(); - BindCore(section11, ref temp13, binderOptions); + BindCore(section11, ref temp13, defaultValueIfNotFound: false, binderOptions); instance.MyDictionary = temp13; } } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/ServiceCollection/Configure_T_name_BinderOptions.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/ServiceCollection/Configure_T_name_BinderOptions.generated.txt index 60927f977deb1..2834491e35135 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/ServiceCollection/Configure_T_name_BinderOptions.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/ServiceCollection/Configure_T_name_BinderOptions.generated.txt @@ -21,6 +21,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration { using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; + using Microsoft.Extensions.Options; using System; using System.CodeDom.Compiler; using System.Collections.Generic; @@ -32,7 +33,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration { #region IServiceCollection extensions. /// Registers a configuration instance which TOptions will bind against. - [InterceptsLocationAttribute(@"src-0.cs", 14, 18)] + [InterceptsLocation(@"src-0.cs", 14, 18)] public static IServiceCollection Configure(this IServiceCollection services, string? name, IConfiguration config, Action? configureOptions) where TOptions : class { ArgumentNullException.ThrowIfNull(services); @@ -66,14 +67,14 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration if (type == typeof(Program.MyClass)) { var temp = (Program.MyClass)instance; - BindCore(configuration, ref temp, binderOptions); + BindCore(configuration, ref temp, defaultValueIfNotFound: false, binderOptions); return; } throw new NotSupportedException($"Unable to bind to type '{type}': generator did not detect the type as input."); } - public static void BindCore(IConfiguration configuration, ref List instance, BinderOptions? binderOptions) + public static void BindCore(IConfiguration configuration, ref List instance, bool defaultValueIfNotFound, BinderOptions? binderOptions) { foreach (IConfigurationSection section in configuration.GetChildren()) { @@ -84,7 +85,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration } } - public static void BindCore(IConfiguration configuration, ref Program.MyClass2 instance, BinderOptions? binderOptions) + public static void BindCore(IConfiguration configuration, ref Program.MyClass2 instance, bool defaultValueIfNotFound, BinderOptions? binderOptions) { ValidateConfigurationKeys(typeof(Program.MyClass2), s_configKeys_ProgramMyClass2, configuration, binderOptions); @@ -92,19 +93,23 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration { instance.MyInt = ParseInt(value1, () => configuration.GetSection("MyInt").Path); } + else if (defaultValueIfNotFound) + { + instance.MyInt = default; + } } - public static void BindCore(IConfiguration configuration, ref List instance, BinderOptions? binderOptions) + public static void BindCore(IConfiguration configuration, ref List instance, bool defaultValueIfNotFound, BinderOptions? binderOptions) { foreach (IConfigurationSection section in configuration.GetChildren()) { var value = new Program.MyClass2(); - BindCore(section, ref value, binderOptions); + BindCore(section, ref value, defaultValueIfNotFound: false, binderOptions); instance.Add(value); } } - public static void BindCore(IConfiguration configuration, ref Dictionary instance, BinderOptions? binderOptions) + public static void BindCore(IConfiguration configuration, ref Dictionary instance, bool defaultValueIfNotFound, BinderOptions? binderOptions) { foreach (IConfigurationSection section in configuration.GetChildren()) { @@ -115,22 +120,29 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration } } - public static void BindCore(IConfiguration configuration, ref Program.MyClass instance, BinderOptions? binderOptions) + public static void BindCore(IConfiguration configuration, ref Program.MyClass instance, bool defaultValueIfNotFound, BinderOptions? binderOptions) { ValidateConfigurationKeys(typeof(Program.MyClass), s_configKeys_ProgramMyClass, configuration, binderOptions); - instance.MyString = configuration["MyString"]!; + if (configuration["MyString"] is string value3) + { + instance.MyString = value3; + } if (configuration["MyInt"] is string value4) { instance.MyInt = ParseInt(value4, () => configuration.GetSection("MyInt").Path); } + else if (defaultValueIfNotFound) + { + instance.MyInt = default; + } if (AsConfigWithChildren(configuration.GetSection("MyList")) is IConfigurationSection section5) { List? temp7 = instance.MyList; temp7 ??= new List(); - BindCore(section5, ref temp7, binderOptions); + BindCore(section5, ref temp7, defaultValueIfNotFound: false, binderOptions); instance.MyList = temp7; } @@ -138,7 +150,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration { List? temp10 = instance.MyList2; temp10 ??= new List(); - BindCore(section8, ref temp10, binderOptions); + BindCore(section8, ref temp10, defaultValueIfNotFound: false, binderOptions); instance.MyList2 = temp10; } @@ -146,7 +158,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration { Dictionary? temp13 = instance.MyDictionary; temp13 ??= new Dictionary(); - BindCore(section11, ref temp13, binderOptions); + BindCore(section11, ref temp13, defaultValueIfNotFound: false, binderOptions); instance.MyDictionary = temp13; } } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/GeneratorTests.Baselines.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/GeneratorTests.Baselines.cs index 2914b29a7af14..ba40f902e9847 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/GeneratorTests.Baselines.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/GeneratorTests.Baselines.cs @@ -655,9 +655,9 @@ public class MyClass public Uri Prop25 { get; set; } public Version Prop26 { get; set; } public DayOfWeek Prop27 { get; set; } - public byte[] Prop22 { get; set; } - public int Prop23 { get; set; } - public DateTime Prop24 { get; set; } + public byte[] Prop28 { get; set; } + public int Prop29 { get; set; } + public DateTime Prop30 { get; set; } } } """; diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/GeneratorTests.Helpers.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/GeneratorTests.Helpers.cs index c7b3b3a328176..6e8329574d413 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/GeneratorTests.Helpers.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/GeneratorTests.Helpers.cs @@ -92,12 +92,19 @@ private static async Task VerifyAgainstBaselineUsingFile( ExtensionClassType extType = ExtensionClassType.None, bool validateOutputCompDiags = true) { + string environmentSubFolder = +#if NETCOREAPP + "netcoreapp" +#else + "net462" +#endif + ; string path = extType is ExtensionClassType.None - ? Path.Combine("Baselines", filename) - : Path.Combine("Baselines", extType.ToString(), filename); - string baseline = LineEndingsHelper.Normalize(await File.ReadAllTextAsync(path).ConfigureAwait(false)); + ? Path.Combine("Baselines", environmentSubFolder, filename) + : Path.Combine("Baselines", environmentSubFolder, extType.ToString(), filename); + string baseline = LineEndingsHelper.Normalize(File.ReadAllText(path)); string[] expectedLines = baseline.Replace("%VERSION%", typeof(ConfigurationBindingGenerator).Assembly.GetName().Version?.ToString()) - .Split(Environment.NewLine); + .Split(new string[] { Environment.NewLine }, StringSplitOptions.None); var (d, r) = await RunGenerator(testSourceCode, validateOutputCompDiags); bool success = RoslynTestUtils.CompareLines(expectedLines, r[0].SourceText, out string errorMessage); diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/GeneratorTests.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/GeneratorTests.cs index 541705f24fabe..2e1afd7767ad4 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/GeneratorTests.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/GeneratorTests.cs @@ -233,7 +233,7 @@ async Task Test(bool expectOutput) } } - [Fact] + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNetCore))] public async Task IssueDiagnosticsForAllOffendingCallsites() { string source = """ From ce804496c1196bb66b5b829e7823f0597e0dc911 Mon Sep 17 00:00:00 2001 From: pedrobsaila Date: Sat, 16 Sep 2023 13:46:43 +0200 Subject: [PATCH 13/17] fix merge issues 2 --- .../Baselines/EmptyConfigType.generated.txt | 104 ------------------ 1 file changed, 104 deletions(-) delete mode 100644 src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/EmptyConfigType.generated.txt diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/EmptyConfigType.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/EmptyConfigType.generated.txt deleted file mode 100644 index 404ce7561cc47..0000000000000 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/EmptyConfigType.generated.txt +++ /dev/null @@ -1,104 +0,0 @@ -// -#nullable enable -#pragma warning disable CS0612, CS0618 // Suppress warnings about [Obsolete] member usage in generated code. - -namespace System.Runtime.CompilerServices -{ - using System; - using System.CodeDom.Compiler; - - [GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")] - [AttributeUsage(AttributeTargets.Method, AllowMultiple = true)] - file sealed class InterceptsLocationAttribute : Attribute - { - public InterceptsLocationAttribute(string filePath, int line, int column) - { - } - } -} - -namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration -{ - using Microsoft.Extensions.Configuration; - using System; - using System.CodeDom.Compiler; - using System.Collections.Generic; - using System.Globalization; - using System.Runtime.CompilerServices; - - [GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")] - file static class BindingExtensions - { - #region IConfiguration extensions. - /// Attempts to bind the given object instance to configuration values by matching property names against configuration keys recursively. - [InterceptsLocation(@"src-0.cs", 12, 23)] - public static void Bind_TypeWithNoMembers(this IConfiguration configuration, object? instance) - { - } - - /// Attempts to bind the given object instance to configuration values by matching property names against configuration keys recursively. - [InterceptsLocation(@"src-0.cs", 15, 23)] - public static void Bind_TypeWithNoMembers_Wrapper(this IConfiguration configuration, object? instance) - { - if (configuration is null) - { - throw new ArgumentNullException(nameof(configuration)); - } - - if (instance is null) - { - return; - } - - var typedObj = (TypeWithNoMembers_Wrapper)instance; - BindCore(configuration, ref typedObj, defaultValueIfNotFound: false, binderOptions: null); - } - #endregion IConfiguration extensions. - - #region Core binding extensions. - private readonly static Lazy> s_configKeys_TypeWithNoMembers_Wrapper = new(() => new HashSet(StringComparer.OrdinalIgnoreCase) { "Member" }); - - public static void BindCore(IConfiguration configuration, ref TypeWithNoMembers_Wrapper instance, bool defaultValueIfNotFound, BinderOptions? binderOptions) - { - ValidateConfigurationKeys(typeof(TypeWithNoMembers_Wrapper), s_configKeys_TypeWithNoMembers_Wrapper, configuration, binderOptions); - - if (AsConfigWithChildren(configuration.GetSection("Member")) is IConfigurationSection section0) - { - instance.Member ??= new TypeWithNoMembers(); - } - } - - - /// If required by the binder options, validates that there are no unknown keys in the input configuration object. - public static void ValidateConfigurationKeys(Type type, Lazy> keys, IConfiguration configuration, BinderOptions? binderOptions) - { - if (binderOptions?.ErrorOnUnknownConfiguration is true) - { - List? temp = null; - - foreach (IConfigurationSection section in configuration.GetChildren()) - { - if (!keys.Value.Contains(section.Key)) - { - (temp ??= new List()).Add($"'{section.Key}'"); - } - } - - if (temp is not null) - { - throw new InvalidOperationException($"'ErrorOnUnknownConfiguration' was set on the provided BinderOptions, but the following properties were not found on the instance of {type}: {string.Join(", ", temp)}"); - } - } - } - - public static IConfiguration? AsConfigWithChildren(IConfiguration configuration) - { - foreach (IConfigurationSection _ in configuration.GetChildren()) - { - return configuration; - } - return null; - } - #endregion Core binding extensions. - } -} From 080fca3a67e9a7a5447f68b3787357a828589668 Mon Sep 17 00:00:00 2001 From: pedrobsaila Date: Sat, 7 Oct 2023 13:16:00 +0200 Subject: [PATCH 14/17] fix merge conflict --- .../ConfigurationBindingGenerator.Emitter.cs | 6 + .../ConfigurationBindingGenerator.Parser.cs | 78 ++++---- .../gen/Emitter/ConfigurationBinder.cs | 4 +- .../gen/Emitter/CoreBindingHelpers.cs | 21 +- .../gen/Emitter/Helpers.cs | 4 +- .../OptionsBuilderConfigurationExtensions.cs | 8 +- ...onfigurationServiceCollectionExtensions.cs | 4 +- .../Get_PrimitivesOnly.generated.txt | 179 ++++++++++++++++++ 8 files changed, 247 insertions(+), 57 deletions(-) create mode 100644 src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/ConfigurationBinder/Get_PrimitivesOnly.generated.txt diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/ConfigurationBindingGenerator.Emitter.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/ConfigurationBindingGenerator.Emitter.cs index 1721a124dead9..9182555af10fa 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/ConfigurationBindingGenerator.Emitter.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/ConfigurationBindingGenerator.Emitter.cs @@ -13,6 +13,9 @@ private sealed partial class Emitter private readonly InterceptorInfo _interceptorInfo; private readonly BindingHelperInfo _bindingHelperInfo; private readonly TypeIndex _typeIndex; + private readonly bool _emitEnumParseMethod; + private readonly bool _emitGenericParseEnum; + private readonly bool _emitThrowIfNullMethod; private readonly SourceWriter _writer = new(); @@ -21,6 +24,9 @@ public Emitter(SourceGenerationSpec sourceGenSpec) _interceptorInfo = sourceGenSpec.InterceptorInfo; _bindingHelperInfo = sourceGenSpec.BindingHelperInfo; _typeIndex = new TypeIndex(sourceGenSpec.ConfigTypes); + _emitEnumParseMethod = sourceGenSpec.EmitEnumParseMethod; + _emitGenericParseEnum = sourceGenSpec.EmitGenericParseEnum; + _emitThrowIfNullMethod = sourceGenSpec.EmitThrowIfNullMethod; } public void Emit(SourceProductionContext context) diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/ConfigurationBindingGenerator.Parser.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/ConfigurationBindingGenerator.Parser.cs index 98c8ae6c94006..75a1f66b461f4 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/ConfigurationBindingGenerator.Parser.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/ConfigurationBindingGenerator.Parser.cs @@ -26,6 +26,8 @@ internal sealed partial class Parser(CompilationData compilationData) private readonly InterceptorInfo.Builder _interceptorInfoBuilder = new(); private BindingHelperInfo.Builder? _helperInfoBuilder; // Init'ed with type index when registering interceptors, after creating type specs. + private bool _emitEnumParseMethod; + private bool _emitGenericParseEnum; public List? Diagnostics { get; private set; } @@ -45,37 +47,16 @@ internal sealed partial class Parser(CompilationData compilationData) ParseInvocations(invocations); CreateTypeSpecs(cancellationToken); RegisterInterceptors(); - - bool emitThrowIfNullMethod = false; - - if (_typeSymbols.ArgumentNullException is not null) - { - var throwIfNullMethods = _typeSymbols.ArgumentNullException.GetMembers("ThrowIfNull"); - - foreach (var throwIfNullMethod in throwIfNullMethods) - { - if (throwIfNullMethod is IMethodSymbol throwIfNullMethodSymbol && throwIfNullMethodSymbol.IsStatic && throwIfNullMethodSymbol.Parameters.Length == 2) - { - var parameters = throwIfNullMethodSymbol.Parameters; - var firstParam = parameters[0]; - var secondParam = parameters[1]; - - if (firstParam.Name == "argument" && firstParam.Type.Equals(_typeSymbols.Object, SymbolEqualityComparer.Default) - && secondParam.Name == "paramName" && secondParam.Type.Equals(_typeSymbols.String, SymbolEqualityComparer.Default)) - { - emitThrowIfNullMethod = true; - break; - } - } - } - } + CheckIfToEmitParseEnumMethod(); return new SourceGenerationSpec { InterceptorInfo = _interceptorInfoBuilder.ToIncrementalValue(), BindingHelperInfo = _helperInfoBuilder!.ToIncrementalValue(), ConfigTypes = _createdTypeSpecs.Values.OrderBy(s => s.TypeRef.FullyQualifiedName).ToImmutableEquatableArray(), - EmitThrowIfNullMethod = emitThrowIfNullMethod + EmitEnumParseMethod = _emitEnumParseMethod, + EmitGenericParseEnum = _emitGenericParseEnum, + EmitThrowIfNullMethod = IsThrowIfNullMethodToBeEmitted() }; } @@ -131,15 +112,6 @@ private void CreateTypeSpecs(CancellationToken cancellationToken) { _createdTypeSpecs.Add(typeSymbol, CreateTypeSpec(typeParseInfo)); } - - if (IsEnum(typeSymbol)) - { - if (!_sourceGenSpec.EmitEnumParseMethod) - { - _sourceGenSpec.EmitEnumParseMethod = true; - _sourceGenSpec.EmitGenericParseEnum = _typeSymbols.Enum.GetMembers("Parse").Any(m => m is IMethodSymbol methodSymbol && methodSymbol.IsGenericMethod); - } - } } } @@ -876,6 +848,44 @@ private void RecordDiagnostic(DiagnosticDescriptor descriptor, Location trimmedL Diagnostics ??= new List(); Diagnostics.Add(DiagnosticInfo.Create(descriptor, trimmedLocation, messageArgs)); } + + private void CheckIfToEmitParseEnumMethod() + { + foreach (var typeSymbol in _createdTypeSpecs.Keys) + { + if (typeSymbol.TypeKind.HasFlag(TypeKind.Enum)) + { + _emitEnumParseMethod = true; + _emitGenericParseEnum = typeSymbol.GetMembers("Parse").Any(m => m is IMethodSymbol methodSymbol && methodSymbol.IsGenericMethod); + } + } + } + + private bool IsThrowIfNullMethodToBeEmitted() + { + if (_typeSymbols.ArgumentNullException is not null) + { + var throwIfNullMethods = _typeSymbols.ArgumentNullException.GetMembers("ThrowIfNull"); + + foreach (var throwIfNullMethod in throwIfNullMethods) + { + if (throwIfNullMethod is IMethodSymbol throwIfNullMethodSymbol && throwIfNullMethodSymbol.IsStatic && throwIfNullMethodSymbol.Parameters.Length == 2) + { + var parameters = throwIfNullMethodSymbol.Parameters; + var firstParam = parameters[0]; + var secondParam = parameters[1]; + + if (firstParam.Name == "argument" && firstParam.Type.Equals(_typeSymbols.Object, SymbolEqualityComparer.Default) + && secondParam.Name == "paramName" && secondParam.Type.Equals(_typeSymbols.String, SymbolEqualityComparer.Default)) + { + return true; + } + } + } + } + + return false; + } } } } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Emitter/ConfigurationBinder.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Emitter/ConfigurationBinder.cs index 7d723139bde3e..4dbe36accbc6e 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Emitter/ConfigurationBinder.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Emitter/ConfigurationBinder.cs @@ -144,8 +144,8 @@ void EmitMethods(ImmutableEquatableArray? interc Debug.Assert(!type.IsValueType); string binderOptionsArg = configureOptions ? $"{Identifier.GetBinderOptions}({Identifier.configureOptions})" : $"{Identifier.binderOptions}: null"; - EmitCheckForNullArgument_WithBlankLine(Identifier.configuration); - EmitCheckForNullArgument_WithBlankLine(Identifier.instance, voidReturn: true); + EmitCheckForNullArgument_WithBlankLine(Identifier.configuration, _emitThrowIfNullMethod); + EmitCheckForNullArgument_WithBlankLine(Identifier.instance, _emitThrowIfNullMethod, voidReturn: true); _writer.WriteLine($$""" var {{Identifier.typedObj}} = ({{type.DisplayString}}){{Identifier.instance}}; {{nameof(MethodsToGen_CoreBindingHelper.BindCore)}}({{configExpression}}, ref {{Identifier.typedObj}}, defaultValueIfNotFound: false, {{binderOptionsArg}}); diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Emitter/CoreBindingHelpers.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Emitter/CoreBindingHelpers.cs index 7a542be6c2a21..17a97b23de147 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Emitter/CoreBindingHelpers.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Emitter/CoreBindingHelpers.cs @@ -92,7 +92,7 @@ private void EmitGetCoreMethod() EmitBlankLineIfRequired(); EmitStartBlock($"public static object? {nameof(MethodsToGen_CoreBindingHelper.GetCore)}(this {Identifier.IConfiguration} {Identifier.configuration}, Type {Identifier.type}, Action<{Identifier.BinderOptions}>? {Identifier.configureOptions})"); - EmitCheckForNullArgument_WithBlankLine(Identifier.configuration); + EmitCheckForNullArgument_WithBlankLine(Identifier.configuration, _emitThrowIfNullMethod); _writer.WriteLine($"{Identifier.BinderOptions}? {Identifier.binderOptions} = {Identifier.GetBinderOptions}({Identifier.configureOptions});"); _writer.WriteLine(); @@ -178,7 +178,7 @@ private void EmitGetValueCoreMethod() EmitBlankLineIfRequired(); EmitStartBlock($"public static object? {nameof(MethodsToGen_CoreBindingHelper.GetValueCore)}(this {Identifier.IConfiguration} {Identifier.configuration}, Type {Identifier.type}, string {Identifier.key})"); - EmitCheckForNullArgument_WithBlankLine(Identifier.configuration); + EmitCheckForNullArgument_WithBlankLine(Identifier.configuration, _emitThrowIfNullMethod); _writer.WriteLine($@"{Identifier.IConfigurationSection} {Identifier.section} = {GetSectionFromConfigurationExpression(Identifier.key, addQuotes: false)};"); _writer.WriteLine(); @@ -224,7 +224,7 @@ private void EmitBindCoreMainMethod() EmitBlankLineIfRequired(); EmitStartBlock($"public static void {nameof(MethodsToGen_CoreBindingHelper.BindCoreMain)}({Identifier.IConfiguration} {Identifier.configuration}, object {Identifier.instance}, Type {Identifier.type}, {TypeDisplayString.NullableActionOfBinderOptions} {Identifier.configureOptions})"); - EmitCheckForNullArgument_WithBlankLine(Identifier.instance, voidReturn: true); + EmitCheckForNullArgument_WithBlankLine(Identifier.instance, _emitThrowIfNullMethod, voidReturn: true); EmitIConfigurationHasValueOrChildrenCheck(voidReturn: true); _writer.WriteLine($"{Identifier.BinderOptions}? {Identifier.binderOptions} = {Identifier.GetBinderOptions}({Identifier.configureOptions});"); _writer.WriteLine(); @@ -475,16 +475,11 @@ private void EmitHelperMethods() EmitGetBinderOptionsHelper(); } - if (_bindingHelperInfo.TypesForGen_ParsePrimitive is { Count: not 0 } stringParsableTypes) + if (_emitEnumParseMethod) { - bool enumTypeExists = false; - - if (_sourceGenSpec.EmitEnumParseMethod) - { - _writer.WriteLine(); - EmitEnumParseMethod(); - _emitBlankLineBeforeNextStatement = true; - } + _writer.WriteLine(); + EmitEnumParseMethod(); + _emitBlankLineBeforeNextStatement = true; } } @@ -574,7 +569,7 @@ private void EmitEnumParseMethod() { string exceptionArg1 = string.Format(ExceptionMessages.FailedBinding, $"{{{Identifier.getPath}()}}", $"{{typeof(T)}}"); - string parseEnumCall = _sourceGenSpec.EmitGenericParseEnum ? "Enum.Parse(value, ignoreCase: true)" : "(T)Enum.Parse(typeof(T), value, ignoreCase: true)"; + string parseEnumCall = _emitGenericParseEnum ? "Enum.Parse(value, ignoreCase: true)" : "(T)Enum.Parse(typeof(T), value, ignoreCase: true)"; _writer.WriteLine($$""" public static T ParseEnum(string value, Func getPath) where T : struct { diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Emitter/Helpers.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Emitter/Helpers.cs index 2e8e80e4e12cc..26c1f0c2c916d 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Emitter/Helpers.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Emitter/Helpers.cs @@ -229,7 +229,7 @@ private void EmitBlankLineIfRequired() _emitBlankLineBeforeNextStatement = true; } - private void EmitCheckForNullArgument_WithBlankLine(string paramName, bool voidReturn = false) + private void EmitCheckForNullArgument_WithBlankLine(string paramName, bool useThrowIfNullMethod, bool voidReturn = false) { if (voidReturn) { @@ -242,7 +242,7 @@ private void EmitCheckForNullArgument_WithBlankLine(string paramName, bool voidR } else { - string throwIfNullExpr = _sourceGenSpec.EmitThrowIfNullMethod + string throwIfNullExpr = useThrowIfNullMethod ? $"ArgumentNullException.ThrowIfNull({paramName});" : $$""" if ({{paramName}} is null) diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Emitter/OptionsBuilderConfigurationExtensions.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Emitter/OptionsBuilderConfigurationExtensions.cs index fdc4286e34c55..14fab1e56f71f 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Emitter/OptionsBuilderConfigurationExtensions.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Emitter/OptionsBuilderConfigurationExtensions.cs @@ -43,7 +43,7 @@ private void EmitBindMethods_Extensions_OptionsBuilder() paramList + $", {TypeDisplayString.NullableActionOfBinderOptions} {Identifier.configureBinder}", documentation); - EmitCheckForNullArgument_WithBlankLine(Identifier.optionsBuilder); + EmitCheckForNullArgument_WithBlankLine(Identifier.optionsBuilder, _emitThrowIfNullMethod); _writer.WriteLine($$""" {{Identifier.Configure}}<{{Identifier.TOptions}}>({{Identifier.optionsBuilder}}.{{Identifier.Services}}, {{Identifier.optionsBuilder}}.Name, {{Identifier.config}}, {{Identifier.configureBinder}}); @@ -65,11 +65,11 @@ private void EmitBindConfigurationMethod() EmitMethodStartBlock(MethodsToGen.OptionsBuilderExt_BindConfiguration, "BindConfiguration", paramList, documentation); - EmitCheckForNullArgument_WithBlankLine(Identifier.optionsBuilder); - EmitCheckForNullArgument_WithBlankLine(Identifier.configSectionPath); + EmitCheckForNullArgument_WithBlankLine(Identifier.optionsBuilder, _emitThrowIfNullMethod); + EmitCheckForNullArgument_WithBlankLine(Identifier.configSectionPath, _emitThrowIfNullMethod); EmitStartBlock($"{Identifier.optionsBuilder}.{Identifier.Configure}<{Identifier.IConfiguration}>(({Identifier.instance}, {Identifier.config}) =>"); - EmitCheckForNullArgument_WithBlankLine(Identifier.config); + EmitCheckForNullArgument_WithBlankLine(Identifier.config, _emitThrowIfNullMethod); _writer.WriteLine($$""" {{Identifier.IConfiguration}} {{Identifier.section}} = string.Equals(string.Empty, {{Identifier.configSectionPath}}, StringComparison.OrdinalIgnoreCase) ? {{Identifier.config}} : {{Identifier.config}}.{{Identifier.GetSection}}({{Identifier.configSectionPath}}); {{nameof(MethodsToGen_CoreBindingHelper.BindCoreMain)}}({{Identifier.section}}, {{Identifier.instance}}, typeof({{Identifier.TOptions}}), {{Identifier.configureBinder}}); diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Emitter/OptionsConfigurationServiceCollectionExtensions.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Emitter/OptionsConfigurationServiceCollectionExtensions.cs index daa3b79db8abc..63314facf5b72 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Emitter/OptionsConfigurationServiceCollectionExtensions.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Emitter/OptionsConfigurationServiceCollectionExtensions.cs @@ -53,8 +53,8 @@ private void EmitConfigureMethods() // Like the others, it is public API that could be called directly by users. // So, it is always generated whenever a Configure overload is called. EmitStartMethod(MethodsToGen.ServiceCollectionExt_Configure_T_name_BinderOptions, paramList: $"string? {Identifier.name}, " + configParam + $", {TypeDisplayString.NullableActionOfBinderOptions} {Identifier.configureOptions}"); - EmitCheckForNullArgument_WithBlankLine(Identifier.services); - EmitCheckForNullArgument_WithBlankLine(Identifier.config); + EmitCheckForNullArgument_WithBlankLine(Identifier.services, _emitThrowIfNullMethod); + EmitCheckForNullArgument_WithBlankLine(Identifier.config, _emitThrowIfNullMethod); _writer.WriteLine($$""" OptionsServiceCollectionExtensions.AddOptions({{Identifier.services}}); {{Identifier.services}}.{{Identifier.AddSingleton}}<{{Identifier.IOptionsChangeTokenSource}}<{{Identifier.TOptions}}>>(new {{Identifier.ConfigurationChangeTokenSource}}<{{Identifier.TOptions}}>({{Identifier.name}}, {{Identifier.config}})); diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/ConfigurationBinder/Get_PrimitivesOnly.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/ConfigurationBinder/Get_PrimitivesOnly.generated.txt new file mode 100644 index 0000000000000..1d676377b35e9 --- /dev/null +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/ConfigurationBinder/Get_PrimitivesOnly.generated.txt @@ -0,0 +1,179 @@ +// +#nullable enable +#pragma warning disable CS0612, CS0618 // Suppress warnings about [Obsolete] member usage in generated code. + +namespace System.Runtime.CompilerServices +{ + using System; + using System.CodeDom.Compiler; + + [GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")] + [AttributeUsage(AttributeTargets.Method, AllowMultiple = true)] + file sealed class InterceptsLocationAttribute : Attribute + { + public InterceptsLocationAttribute(string filePath, int line, int column) + { + } + } +} + +namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration +{ + using Microsoft.Extensions.Configuration; + using System; + using System.CodeDom.Compiler; + using System.Globalization; + using System.Runtime.CompilerServices; + + [GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")] + file static class BindingExtensions + { + #region IConfiguration extensions. + /// Attempts to bind the configuration instance to a new instance of type T. + [InterceptsLocation(@"src-0.cs", 10, 16)] + public static T? Get(this IConfiguration configuration) => (T?)(GetCore(configuration, typeof(T), configureOptions: null) ?? default(T)); + + /// Attempts to bind the configuration instance to a new instance of type T. + [InterceptsLocation(@"src-0.cs", 12, 16)] + public static T? Get(this IConfiguration configuration, Action? configureOptions) => (T?)(GetCore(configuration, typeof(T), configureOptions) ?? default(T)); + + /// Attempts to bind the configuration instance to a new instance of type T. + [InterceptsLocation(@"src-0.cs", 11, 16)] + public static object? Get(this IConfiguration configuration, Type type) => GetCore(configuration, type, configureOptions: null); + + /// Attempts to bind the configuration instance to a new instance of type T. + [InterceptsLocation(@"src-0.cs", 13, 16)] + public static object? Get(this IConfiguration configuration, Type type, Action? configureOptions) => GetCore(configuration, type, configureOptions); + #endregion IConfiguration extensions. + + #region Core binding extensions. + public static object? GetCore(this IConfiguration configuration, Type type, Action? configureOptions) + { + ArgumentNullException.ThrowIfNull(configuration), + + BinderOptions? binderOptions = GetBinderOptions(configureOptions); + + if (!HasValueOrChildren(configuration)) + { + return null; + } + + if (type == typeof(int)) + { + if (configuration is not IConfigurationSection section) + { + throw new InvalidOperationException(); + } + if (section.Value is string value) + { + return ParseInt(value, () => section.Path); + } + } + else if (type == typeof(string)) + { + if (configuration is not IConfigurationSection section) + { + throw new InvalidOperationException(); + } + return section.Value; + } + else if (type == typeof(float)) + { + if (configuration is not IConfigurationSection section) + { + throw new InvalidOperationException(); + } + if (section.Value is string value) + { + return ParseFloat(value, () => section.Path); + } + } + else if (type == typeof(double)) + { + if (configuration is not IConfigurationSection section) + { + throw new InvalidOperationException(); + } + if (section.Value is string value) + { + return ParseDouble(value, () => section.Path); + } + } + + throw new NotSupportedException($"Unable to bind to type '{type}': generator did not detect the type as input."); + } + + public static bool HasValueOrChildren(IConfiguration configuration) + { + if ((configuration as IConfigurationSection)?.Value is not null) + { + return true; + } + return AsConfigWithChildren(configuration) is not null; + } + + public static IConfiguration? AsConfigWithChildren(IConfiguration configuration) + { + foreach (IConfigurationSection _ in configuration.GetChildren()) + { + return configuration; + } + return null; + } + + public static BinderOptions? GetBinderOptions(Action? configureOptions) + { + if (configureOptions is null) + { + return null; + } + + BinderOptions binderOptions = new(); + configureOptions(binderOptions); + + if (binderOptions.BindNonPublicProperties) + { + throw new NotSupportedException($"The configuration binding source generator does not support 'BinderOptions.BindNonPublicProperties'."); + } + + return binderOptions; + } + + public static int ParseInt(string value, Func getPath) + { + try + { + return int.Parse(value, NumberStyles.Integer, CultureInfo.InvariantCulture); + } + catch (Exception exception) + { + throw new InvalidOperationException($"Failed to convert configuration value at '{getPath()}' to type '{typeof(int)}'.", exception); + } + } + + public static float ParseFloat(string value, Func getPath) + { + try + { + return float.Parse(value, NumberStyles.Float, CultureInfo.InvariantCulture); + } + catch (Exception exception) + { + throw new InvalidOperationException($"Failed to convert configuration value at '{getPath()}' to type '{typeof(float)}'.", exception); + } + } + + public static double ParseDouble(string value, Func getPath) + { + try + { + return double.Parse(value, NumberStyles.Float, CultureInfo.InvariantCulture); + } + catch (Exception exception) + { + throw new InvalidOperationException($"Failed to convert configuration value at '{getPath()}' to type '{typeof(double)}'.", exception); + } + } + #endregion Core binding extensions. + } +} From 576e784780641e02d2e0fc9357afc22eac423743 Mon Sep 17 00:00:00 2001 From: pedrobsaila Date: Sat, 7 Oct 2023 14:36:50 +0200 Subject: [PATCH 15/17] fix merge issues --- .../ConfigurationBindingGenerator.Parser.cs | 5 +- .../gen/Emitter/CoreBindingHelpers.cs | 12 +++++ .../netcoreapp/Collections.generated.txt | 50 ++---------------- .../ConfigurationBinder/Get.generated.txt | 52 +++++++++++-------- .../Get_PrimitivesOnly.generated.txt | 2 +- .../ConfigurationBinder/Get_T.generated.txt | 48 ++++++++++------- .../Get_T_BinderOptions.generated.txt | 48 ++++++++++------- .../ConfigBindingGenTestDriver.cs | 10 ++-- 8 files changed, 110 insertions(+), 117 deletions(-) diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/ConfigurationBindingGenerator.Parser.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/ConfigurationBindingGenerator.Parser.cs index 75a1f66b461f4..605fe106e5ba6 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/ConfigurationBindingGenerator.Parser.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/ConfigurationBindingGenerator.Parser.cs @@ -853,10 +853,11 @@ private void CheckIfToEmitParseEnumMethod() { foreach (var typeSymbol in _createdTypeSpecs.Keys) { - if (typeSymbol.TypeKind.HasFlag(TypeKind.Enum)) + if (IsEnum(typeSymbol)) { _emitEnumParseMethod = true; - _emitGenericParseEnum = typeSymbol.GetMembers("Parse").Any(m => m is IMethodSymbol methodSymbol && methodSymbol.IsGenericMethod); + _emitGenericParseEnum = _typeSymbols.Enum.GetMembers("Parse").Any(m => m is IMethodSymbol methodSymbol && methodSymbol.IsGenericMethod); + return; } } } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Emitter/CoreBindingHelpers.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Emitter/CoreBindingHelpers.cs index f8eda06195eaf..03366f8b49810 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Emitter/CoreBindingHelpers.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Emitter/CoreBindingHelpers.cs @@ -481,6 +481,18 @@ private void EmitHelperMethods() EmitEnumParseMethod(); _emitBlankLineBeforeNextStatement = true; } + + if (_bindingHelperInfo.TypesForGen_ParsePrimitive is { Count: not 0 } stringParsableTypes) + { + foreach (ParsableFromStringSpec type in stringParsableTypes) + { + if (type.StringParsableTypeKind is not StringParsableTypeKind.Enum) + { + EmitBlankLineIfRequired(); + EmitPrimitiveParseMethod(type); + } + } + } } private void EmitValidateConfigurationKeysMethod() diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/Collections.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/Collections.generated.txt index 683c791845c62..b0210df5e044e 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/Collections.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/Collections.generated.txt @@ -37,7 +37,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration #endregion IConfiguration extensions. #region Core binding extensions. - private readonly static Lazy> s_configKeys_ProgramMyClassWithCustomCollections = new(() => new HashSet(StringComparer.OrdinalIgnoreCase) { "CustomDictionary", "CustomList", "IReadOnlyList", "IReadOnlyDictionary" }); + private readonly static Lazy> s_configKeys_ProgramMyClassWithCustomCollections = new(() => new HashSet(StringComparer.OrdinalIgnoreCase) { "CustomDictionary", "CustomList", "ICustomDictionary", "ICustomCollection", "IReadOnlyList", "UnsupportedIReadOnlyDictionaryUnsupported", "IReadOnlyDictionary" }); public static object? GetCore(this IConfiguration configuration, Type type, Action? configureOptions) { @@ -82,28 +82,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration } } - public static void BindCore(IConfiguration configuration, ref List instance, bool defaultValueIfNotFound, BinderOptions? binderOptions) - { - foreach (IConfigurationSection section in configuration.GetChildren()) - { - if (section.Value is string value) - { - instance.Add(ParseInt(value, () => section.Path)); - } - } - } - - public static void BindCore(IConfiguration configuration, ref ICollection instance, bool defaultValueIfNotFound, BinderOptions? binderOptions) - { - foreach (IConfigurationSection section in configuration.GetChildren()) - { - if (section.Value is string value) - { - instance.Add(ParseInt(value, () => section.Path)); - } - } - } - public static void BindCore(IConfiguration configuration, ref IReadOnlyList instance, bool defaultValueIfNotFound, BinderOptions? binderOptions) { if (instance is not ICollection temp) @@ -120,28 +98,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration } } - public static void BindCore(IConfiguration configuration, ref Dictionary instance, bool defaultValueIfNotFound, BinderOptions? binderOptions) - { - foreach (IConfigurationSection section in configuration.GetChildren()) - { - if (section.Value is string value) - { - instance[section.Key] = ParseInt(value, () => section.Path); - } - } - } - - public static void BindCore(IConfiguration configuration, ref IDictionary instance, bool defaultValueIfNotFound, BinderOptions? binderOptions) - { - foreach (IConfigurationSection section in configuration.GetChildren()) - { - if (section.Value is string value) - { - instance[section.Key] = ParseInt(value, () => section.Path); - } - } - } - public static void BindCore(IConfiguration configuration, ref IReadOnlyDictionary instance, bool defaultValueIfNotFound, BinderOptions? binderOptions) { if (instance is not IDictionary temp) @@ -181,7 +137,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration if (AsConfigWithChildren(configuration.GetSection("IReadOnlyList")) is IConfigurationSection section7) { IReadOnlyList? temp9 = instance.IReadOnlyList; - temp9 = temp9 is null ? new List() : new List(temp9); + temp9 = temp9 is null ? (IReadOnlyList)new List() : (IReadOnlyList)new List(temp9); BindCore(section7, ref temp9, defaultValueIfNotFound: false, binderOptions); instance.IReadOnlyList = temp9; } @@ -189,7 +145,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration if (AsConfigWithChildren(configuration.GetSection("IReadOnlyDictionary")) is IConfigurationSection section10) { IReadOnlyDictionary? temp12 = instance.IReadOnlyDictionary; - temp12 = temp12 is null ? new Dictionary() : temp12.ToDictionary(pair => pair.Key, pair => pair.Value); + temp12 = temp12 is null ? (IReadOnlyDictionary)new Dictionary() : (IReadOnlyDictionary)temp12.ToDictionary(pair => pair.Key, pair => pair.Value); BindCore(section10, ref temp12, defaultValueIfNotFound: false, binderOptions); instance.IReadOnlyDictionary = temp12; } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/ConfigurationBinder/Get.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/ConfigurationBinder/Get.generated.txt index bac51d3c24420..a050ddffd430f 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/ConfigurationBinder/Get.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/ConfigurationBinder/Get.generated.txt @@ -92,7 +92,15 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration public static void BindCore(IConfiguration configuration, ref int[] instance, bool defaultValueIfNotFound, BinderOptions? binderOptions) { var temp2 = new List(); - BindCore(configuration, ref temp2, defaultValueIfNotFound: false, binderOptions); + + foreach (IConfigurationSection section in configuration.GetChildren()) + { + if (section.Value is string value) + { + temp2.Add(ParseInt(value, () => section.Path)); + } + } + int originalCount = instance.Length; Array.Resize(ref instance, originalCount + temp2.Count); temp2.CopyTo(instance, originalCount); @@ -113,42 +121,42 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration { ValidateConfigurationKeys(typeof(Program.MyClass), s_configKeys_ProgramMyClass, configuration, binderOptions); - if (configuration["MyString"] is string value4) + if (configuration["MyString"] is string value3) { - instance.MyString = value4; + instance.MyString = value3; } - if (configuration["MyInt"] is string value5) + if (configuration["MyInt"] is string value4) { - instance.MyInt = ParseInt(value5, () => configuration.GetSection("MyInt").Path); + instance.MyInt = ParseInt(value4, () => configuration.GetSection("MyInt").Path); } else if (defaultValueIfNotFound) { instance.MyInt = default; } - if (AsConfigWithChildren(configuration.GetSection("MyList")) is IConfigurationSection section6) + if (AsConfigWithChildren(configuration.GetSection("MyList")) is IConfigurationSection section5) { - List? temp8 = instance.MyList; - temp8 ??= new List(); - BindCore(section6, ref temp8, defaultValueIfNotFound: false, binderOptions); - instance.MyList = temp8; + List? temp7 = instance.MyList; + temp7 ??= new List(); + BindCore(section5, ref temp7, defaultValueIfNotFound: false, binderOptions); + instance.MyList = temp7; } - if (AsConfigWithChildren(configuration.GetSection("MyArray")) is IConfigurationSection section9) + if (AsConfigWithChildren(configuration.GetSection("MyArray")) is IConfigurationSection section8) { - int[]? temp11 = instance.MyArray; - temp11 ??= new int[0]; - BindCore(section9, ref temp11, defaultValueIfNotFound: false, binderOptions); - instance.MyArray = temp11; + int[]? temp10 = instance.MyArray; + temp10 ??= new int[0]; + BindCore(section8, ref temp10, defaultValueIfNotFound: false, binderOptions); + instance.MyArray = temp10; } - if (AsConfigWithChildren(configuration.GetSection("MyDictionary")) is IConfigurationSection section12) + if (AsConfigWithChildren(configuration.GetSection("MyDictionary")) is IConfigurationSection section11) { - Dictionary? temp14 = instance.MyDictionary; - temp14 ??= new Dictionary(); - BindCore(section12, ref temp14, defaultValueIfNotFound: false, binderOptions); - instance.MyDictionary = temp14; + Dictionary? temp13 = instance.MyDictionary; + temp13 ??= new Dictionary(); + BindCore(section11, ref temp13, defaultValueIfNotFound: false, binderOptions); + instance.MyDictionary = temp13; } } @@ -156,9 +164,9 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration { ValidateConfigurationKeys(typeof(Program.MyClass2), s_configKeys_ProgramMyClass2, configuration, binderOptions); - if (configuration["MyInt"] is string value15) + if (configuration["MyInt"] is string value14) { - instance.MyInt = ParseInt(value15, () => configuration.GetSection("MyInt").Path); + instance.MyInt = ParseInt(value14, () => configuration.GetSection("MyInt").Path); } else if (defaultValueIfNotFound) { diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/ConfigurationBinder/Get_PrimitivesOnly.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/ConfigurationBinder/Get_PrimitivesOnly.generated.txt index 1d676377b35e9..021a4ca8bef4e 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/ConfigurationBinder/Get_PrimitivesOnly.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/ConfigurationBinder/Get_PrimitivesOnly.generated.txt @@ -49,7 +49,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration #region Core binding extensions. public static object? GetCore(this IConfiguration configuration, Type type, Action? configureOptions) { - ArgumentNullException.ThrowIfNull(configuration), + ArgumentNullException.ThrowIfNull(configuration); BinderOptions? binderOptions = GetBinderOptions(configureOptions); diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/ConfigurationBinder/Get_T.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/ConfigurationBinder/Get_T.generated.txt index 7b7de0ba7d146..c054010f560a0 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/ConfigurationBinder/Get_T.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/ConfigurationBinder/Get_T.generated.txt @@ -73,7 +73,15 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration public static void BindCore(IConfiguration configuration, ref int[] instance, bool defaultValueIfNotFound, BinderOptions? binderOptions) { var temp1 = new List(); - BindCore(configuration, ref temp1, defaultValueIfNotFound: false, binderOptions); + + foreach (IConfigurationSection section in configuration.GetChildren()) + { + if (section.Value is string value) + { + temp1.Add(ParseInt(value, () => section.Path)); + } + } + int originalCount = instance.Length; Array.Resize(ref instance, originalCount + temp1.Count); temp1.CopyTo(instance, originalCount); @@ -94,42 +102,42 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration { ValidateConfigurationKeys(typeof(Program.MyClass), s_configKeys_ProgramMyClass, configuration, binderOptions); - if (configuration["MyString"] is string value3) + if (configuration["MyString"] is string value2) { - instance.MyString = value3; + instance.MyString = value2; } - if (configuration["MyInt"] is string value4) + if (configuration["MyInt"] is string value3) { - instance.MyInt = ParseInt(value4, () => configuration.GetSection("MyInt").Path); + instance.MyInt = ParseInt(value3, () => configuration.GetSection("MyInt").Path); } else if (defaultValueIfNotFound) { instance.MyInt = default; } - if (AsConfigWithChildren(configuration.GetSection("MyList")) is IConfigurationSection section5) + if (AsConfigWithChildren(configuration.GetSection("MyList")) is IConfigurationSection section4) { - List? temp7 = instance.MyList; - temp7 ??= new List(); - BindCore(section5, ref temp7, defaultValueIfNotFound: false, binderOptions); - instance.MyList = temp7; + List? temp6 = instance.MyList; + temp6 ??= new List(); + BindCore(section4, ref temp6, defaultValueIfNotFound: false, binderOptions); + instance.MyList = temp6; } - if (AsConfigWithChildren(configuration.GetSection("MyArray")) is IConfigurationSection section8) + if (AsConfigWithChildren(configuration.GetSection("MyArray")) is IConfigurationSection section7) { - int[]? temp10 = instance.MyArray; - temp10 ??= new int[0]; - BindCore(section8, ref temp10, defaultValueIfNotFound: false, binderOptions); - instance.MyArray = temp10; + int[]? temp9 = instance.MyArray; + temp9 ??= new int[0]; + BindCore(section7, ref temp9, defaultValueIfNotFound: false, binderOptions); + instance.MyArray = temp9; } - if (AsConfigWithChildren(configuration.GetSection("MyDictionary")) is IConfigurationSection section11) + if (AsConfigWithChildren(configuration.GetSection("MyDictionary")) is IConfigurationSection section10) { - Dictionary? temp13 = instance.MyDictionary; - temp13 ??= new Dictionary(); - BindCore(section11, ref temp13, defaultValueIfNotFound: false, binderOptions); - instance.MyDictionary = temp13; + Dictionary? temp12 = instance.MyDictionary; + temp12 ??= new Dictionary(); + BindCore(section10, ref temp12, defaultValueIfNotFound: false, binderOptions); + instance.MyDictionary = temp12; } } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/ConfigurationBinder/Get_T_BinderOptions.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/ConfigurationBinder/Get_T_BinderOptions.generated.txt index 0243ad41eb3c7..9266520e105a6 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/ConfigurationBinder/Get_T_BinderOptions.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/ConfigurationBinder/Get_T_BinderOptions.generated.txt @@ -73,7 +73,15 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration public static void BindCore(IConfiguration configuration, ref int[] instance, bool defaultValueIfNotFound, BinderOptions? binderOptions) { var temp1 = new List(); - BindCore(configuration, ref temp1, defaultValueIfNotFound: false, binderOptions); + + foreach (IConfigurationSection section in configuration.GetChildren()) + { + if (section.Value is string value) + { + temp1.Add(ParseInt(value, () => section.Path)); + } + } + int originalCount = instance.Length; Array.Resize(ref instance, originalCount + temp1.Count); temp1.CopyTo(instance, originalCount); @@ -94,42 +102,42 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration { ValidateConfigurationKeys(typeof(Program.MyClass), s_configKeys_ProgramMyClass, configuration, binderOptions); - if (configuration["MyString"] is string value3) + if (configuration["MyString"] is string value2) { - instance.MyString = value3; + instance.MyString = value2; } - if (configuration["MyInt"] is string value4) + if (configuration["MyInt"] is string value3) { - instance.MyInt = ParseInt(value4, () => configuration.GetSection("MyInt").Path); + instance.MyInt = ParseInt(value3, () => configuration.GetSection("MyInt").Path); } else if (defaultValueIfNotFound) { instance.MyInt = default; } - if (AsConfigWithChildren(configuration.GetSection("MyList")) is IConfigurationSection section5) + if (AsConfigWithChildren(configuration.GetSection("MyList")) is IConfigurationSection section4) { - List? temp7 = instance.MyList; - temp7 ??= new List(); - BindCore(section5, ref temp7, defaultValueIfNotFound: false, binderOptions); - instance.MyList = temp7; + List? temp6 = instance.MyList; + temp6 ??= new List(); + BindCore(section4, ref temp6, defaultValueIfNotFound: false, binderOptions); + instance.MyList = temp6; } - if (AsConfigWithChildren(configuration.GetSection("MyArray")) is IConfigurationSection section8) + if (AsConfigWithChildren(configuration.GetSection("MyArray")) is IConfigurationSection section7) { - int[]? temp10 = instance.MyArray; - temp10 ??= new int[0]; - BindCore(section8, ref temp10, defaultValueIfNotFound: false, binderOptions); - instance.MyArray = temp10; + int[]? temp9 = instance.MyArray; + temp9 ??= new int[0]; + BindCore(section7, ref temp9, defaultValueIfNotFound: false, binderOptions); + instance.MyArray = temp9; } - if (AsConfigWithChildren(configuration.GetSection("MyDictionary")) is IConfigurationSection section11) + if (AsConfigWithChildren(configuration.GetSection("MyDictionary")) is IConfigurationSection section10) { - Dictionary? temp13 = instance.MyDictionary; - temp13 ??= new Dictionary(); - BindCore(section11, ref temp13, defaultValueIfNotFound: false, binderOptions); - instance.MyDictionary = temp13; + Dictionary? temp12 = instance.MyDictionary; + temp12 ??= new Dictionary(); + BindCore(section10, ref temp12, defaultValueIfNotFound: false, binderOptions); + instance.MyDictionary = temp12; } } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/ConfigBindingGenTestDriver.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/ConfigBindingGenTestDriver.cs index 4373b404fc67f..d4d207fff3c6b 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/ConfigBindingGenTestDriver.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/ConfigBindingGenTestDriver.cs @@ -96,18 +96,18 @@ private async Task UpdateCompilationWithSource(string? source = null) internal struct ConfigBindingGenRunResult { - public required Compilation OutputCompilation { get; init; } + public Compilation OutputCompilation { get; init; } - public required GeneratedSourceResult? GeneratedSource { get; init; } + public GeneratedSourceResult? GeneratedSource { get; init; } /// /// Diagnostics produced by the generator alone. Doesn't include any from other build participants. /// - public required ImmutableArray Diagnostics { get; init; } + public ImmutableArray Diagnostics { get; init; } - public required ImmutableArray TrackedSteps { get; init; } + public ImmutableArray TrackedSteps { get; init; } - public required SourceGenerationSpec? GenerationSpec { get; init; } + public SourceGenerationSpec? GenerationSpec { get; init; } } internal enum ExpectedDiagnostics From 438b37175e045fffe0a4451cbb160e7f4167dd33 Mon Sep 17 00:00:00 2001 From: pedrobsaila Date: Tue, 10 Oct 2023 21:52:03 +0200 Subject: [PATCH 16/17] fix remarks --- .../gen/ConfigurationBindingGenerator.Parser.cs | 2 +- .../gen/Parser/KnownTypeSymbols.cs | 2 -- ....Configuration.Binder.SourceGeneration.Tests.csproj | 10 ++-------- 3 files changed, 3 insertions(+), 11 deletions(-) diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/ConfigurationBindingGenerator.Parser.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/ConfigurationBindingGenerator.Parser.cs index 605fe106e5ba6..0c88aa0212ed1 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/ConfigurationBindingGenerator.Parser.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/ConfigurationBindingGenerator.Parser.cs @@ -876,7 +876,7 @@ private bool IsThrowIfNullMethodToBeEmitted() var firstParam = parameters[0]; var secondParam = parameters[1]; - if (firstParam.Name == "argument" && firstParam.Type.Equals(_typeSymbols.Object, SymbolEqualityComparer.Default) + if (firstParam.Name == "argument" && firstParam.Type.SpecialType == SpecialType.System_Object && secondParam.Name == "paramName" && secondParam.Type.Equals(_typeSymbols.String, SymbolEqualityComparer.Default)) { return true; diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Parser/KnownTypeSymbols.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Parser/KnownTypeSymbols.cs index 9b7c8fc4c5353..1b2b9d9d7f4a0 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Parser/KnownTypeSymbols.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Parser/KnownTypeSymbols.cs @@ -58,7 +58,6 @@ internal sealed class KnownTypeSymbols public INamedTypeSymbol? List { get; } public INamedTypeSymbol Enum { get; } public INamedTypeSymbol? ArgumentNullException { get; } - public INamedTypeSymbol Object { get; } public KnownTypeSymbols(CSharpCompilation compilation) { @@ -121,7 +120,6 @@ public KnownTypeSymbols(CSharpCompilation compilation) Enum = compilation.GetSpecialType(SpecialType.System_Enum); ArgumentNullException = compilation.GetBestTypeByMetadataName(typeof(ArgumentNullException)); - Object = compilation.GetBestTypeByMetadataName(typeof(object)); String = compilation.GetBestTypeByMetadataName(typeof(string)); } } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Microsoft.Extensions.Configuration.Binder.SourceGeneration.Tests.csproj b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Microsoft.Extensions.Configuration.Binder.SourceGeneration.Tests.csproj index 0817ed406a6b3..1677998c398b2 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Microsoft.Extensions.Configuration.Binder.SourceGeneration.Tests.csproj +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Microsoft.Extensions.Configuration.Binder.SourceGeneration.Tests.csproj @@ -49,14 +49,8 @@ - + PreserveNewest From a08f4cd6ef021ba251b6c5fc6436e3a591ad8f5e Mon Sep 17 00:00:00 2001 From: pedrobsaila Date: Tue, 10 Oct 2023 23:04:15 +0200 Subject: [PATCH 17/17] fix remark on baseline files path --- ...tensions.Configuration.Binder.SourceGeneration.Tests.csproj | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Microsoft.Extensions.Configuration.Binder.SourceGeneration.Tests.csproj b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Microsoft.Extensions.Configuration.Binder.SourceGeneration.Tests.csproj index 1677998c398b2..1580309ec0d67 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Microsoft.Extensions.Configuration.Binder.SourceGeneration.Tests.csproj +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Microsoft.Extensions.Configuration.Binder.SourceGeneration.Tests.csproj @@ -49,8 +49,7 @@ - + PreserveNewest