mirror of
https://github.com/VSadov/Satori.git
synced 2025-06-09 17:44:48 +09:00
Use Roslyn interceptors feature in binder gen (#90340)
* Use Roslyn interceptors feature in binder gen * Fix polymorphic issue and address feedback * Fix source build issue * Revert changes to options gen * Fix
This commit is contained in:
parent
a429b0ca4f
commit
a5ff66c825
67 changed files with 1590 additions and 1199 deletions
|
@ -270,3 +270,5 @@ The diagnostic id values reserved for .NET Libraries analyzer warnings are `SYSL
|
||||||
| Suppression ID | Suppressed Diagnostic ID | Description |
|
| Suppression ID | Suppressed Diagnostic ID | Description |
|
||||||
| :----------------------- | :----------------------- | :---------- |
|
| :----------------------- | :----------------------- | :---------- |
|
||||||
| __`SYSLIBSUPPRESS0001`__ | CA1822 | Do not offer to make methods static when the methods need to be instance methods for a custom marshaller shape. |
|
| __`SYSLIBSUPPRESS0001`__ | CA1822 | Do not offer to make methods static when the methods need to be instance methods for a custom marshaller shape. |
|
||||||
|
| __`SYSLIBSUPPRESS0002`__ | IL2026 | ConfigurationBindingGenerator: suppress RequiresUnreferencedCode diagnostic for binding call that has been intercepted by a generated static variant. |
|
||||||
|
| __`SYSLIBSUPPRESS0003`__ | IL3050 | ConfigurationBindingGenerator: suppress RequiresDynamicCode diagnostic for binding call that has been intercepted by a generated static variant. |
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
<UsagePattern IdentityGlob="System.Composition*/*7.*" />
|
<UsagePattern IdentityGlob="System.Composition*/*7.*" />
|
||||||
<UsagePattern IdentityGlob="Microsoft.CodeAnalysis*/*4.4.*" />
|
<UsagePattern IdentityGlob="Microsoft.CodeAnalysis*/*4.4.*" />
|
||||||
<UsagePattern IdentityGlob="Microsoft.CodeAnalysis*/*4.5.*" />
|
<UsagePattern IdentityGlob="Microsoft.CodeAnalysis*/*4.5.*" />
|
||||||
|
<UsagePattern IdentityGlob="Microsoft.CodeAnalysis*/*4.7.*" />
|
||||||
|
|
||||||
<!-- Allowed and pinned to major version due to https://github.com/dotnet/source-build/issues/3228 -->
|
<!-- Allowed and pinned to major version due to https://github.com/dotnet/source-build/issues/3228 -->
|
||||||
<UsagePattern IdentityGlob="Microsoft.NETCore.App.Crossgen2.linux-x64/*8.*" />
|
<UsagePattern IdentityGlob="Microsoft.NETCore.App.Crossgen2.linux-x64/*8.*" />
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
// The .NET Foundation licenses this file to you under the MIT license.
|
// The .NET Foundation licenses this file to you under the MIT license.
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Immutable;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
using Microsoft.CodeAnalysis;
|
using Microsoft.CodeAnalysis;
|
||||||
|
@ -17,7 +18,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
|
||||||
private readonly SourceGenerationSpec _sourceGenSpec;
|
private readonly SourceGenerationSpec _sourceGenSpec;
|
||||||
|
|
||||||
private bool _emitBlankLineBeforeNextStatement;
|
private bool _emitBlankLineBeforeNextStatement;
|
||||||
private bool _useFullyQualifiedNames;
|
|
||||||
private int _valueSuffixIndex;
|
private int _valueSuffixIndex;
|
||||||
|
|
||||||
private static readonly Regex s_arrayBracketsRegex = new(Regex.Escape("[]"));
|
private static readonly Regex s_arrayBracketsRegex = new(Regex.Escape("[]"));
|
||||||
|
@ -32,7 +32,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
|
||||||
|
|
||||||
public void Emit()
|
public void Emit()
|
||||||
{
|
{
|
||||||
if (!ShouldEmitBinders())
|
if (!ShouldEmitBindingExtensions())
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -42,17 +42,26 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
|
||||||
#nullable enable
|
#nullable enable
|
||||||
#pragma warning disable CS0612, CS0618 // Suppress warnings about [Obsolete] member usage in generated code.
|
#pragma warning disable CS0612, CS0618 // Suppress warnings about [Obsolete] member usage in generated code.
|
||||||
""");
|
""");
|
||||||
|
|
||||||
|
EmitInterceptsLocationAttrDecl();
|
||||||
|
|
||||||
|
EmitStartBlock($"namespace {ProjectName}");
|
||||||
|
EmitUsingStatements();
|
||||||
|
|
||||||
_writer.WriteLine();
|
_writer.WriteLine();
|
||||||
|
EmitStartBlock($$"""
|
||||||
|
{{Expression.GeneratedCodeAnnotation}}
|
||||||
|
file static class {{Identifier.BindingExtensions}}
|
||||||
|
""");
|
||||||
|
EmitBindingExtensions_IConfiguration();
|
||||||
|
EmitBindingExtensions_OptionsBuilder();
|
||||||
|
EmitBindingExtensions_IServiceCollection();
|
||||||
|
EmitCoreBindingHelpers();
|
||||||
|
EmitEndBlock(); // BindingExtensions class
|
||||||
|
|
||||||
_useFullyQualifiedNames = true;
|
EmitEndBlock(); // Binding namespace.
|
||||||
EmitBinder_Extensions_IConfiguration();
|
|
||||||
EmitBinder_Extensions_OptionsBuilder();
|
|
||||||
EmitBinder_Extensions_IServiceCollection();
|
|
||||||
|
|
||||||
_useFullyQualifiedNames = false;
|
_context.AddSource($"{Identifier.BindingExtensions}.g.cs", _writer.ToSourceText());
|
||||||
Emit_CoreBindingHelper();
|
|
||||||
|
|
||||||
_context.AddSource($"{Identifier.GeneratedConfigurationBinder}.g.cs", _writer.ToSourceText());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void EmitBindCoreCall(
|
private void EmitBindCoreCall(
|
||||||
|
@ -74,7 +83,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
|
||||||
if (initKind is InitializationKind.AssignmentWithNullCheck)
|
if (initKind is InitializationKind.AssignmentWithNullCheck)
|
||||||
{
|
{
|
||||||
Debug.Assert(!type.IsValueType);
|
Debug.Assert(!type.IsValueType);
|
||||||
_writer.WriteLine($"{type.MinimalDisplayString}? {tempIdentifier} = {memberAccessExpr};");
|
_writer.WriteLine($"{type.DisplayString}? {tempIdentifier} = {memberAccessExpr};");
|
||||||
EmitBindCoreCall(tempIdentifier, InitializationKind.AssignmentWithNullCheck);
|
EmitBindCoreCall(tempIdentifier, InitializationKind.AssignmentWithNullCheck);
|
||||||
}
|
}
|
||||||
else if (initKind is InitializationKind.None && type.IsValueType)
|
else if (initKind is InitializationKind.None && type.IsValueType)
|
||||||
|
@ -89,9 +98,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
|
||||||
|
|
||||||
void EmitBindCoreCall(string objExpression, InitializationKind initKind)
|
void EmitBindCoreCall(string objExpression, InitializationKind initKind)
|
||||||
{
|
{
|
||||||
string methodDisplayString = GetHelperMethodDisplayString(nameof(MethodsToGen_CoreBindingHelper.BindCore));
|
string bindCoreCall = $@"{nameof(MethodsToGen_CoreBindingHelper.BindCore)}({configArgExpr}, ref {objExpression}, {Identifier.binderOptions});";
|
||||||
string bindCoreCall = $@"{methodDisplayString}({configArgExpr}, ref {objExpression}, {Identifier.binderOptions});";
|
|
||||||
|
|
||||||
EmitObjectInit(objExpression, initKind);
|
EmitObjectInit(objExpression, initKind);
|
||||||
_writer.WriteLine(bindCoreCall);
|
_writer.WriteLine(bindCoreCall);
|
||||||
writeOnSuccess?.Invoke(objExpression);
|
writeOnSuccess?.Invoke(objExpression);
|
||||||
|
@ -127,12 +134,11 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
|
||||||
}
|
}
|
||||||
else if (typeKind is StringParsableTypeKind.Enum)
|
else if (typeKind is StringParsableTypeKind.Enum)
|
||||||
{
|
{
|
||||||
parsedValueExpr = $"ParseEnum<{type.MinimalDisplayString}>({stringValueToParse_Expr}, () => {sectionPathExpr})";
|
parsedValueExpr = $"ParseEnum<{type.DisplayString}>({stringValueToParse_Expr}, () => {sectionPathExpr})";
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
string helperMethodDisplayString = GetHelperMethodDisplayString(type.ParseMethodName);
|
parsedValueExpr = $"{type.ParseMethodName}({stringValueToParse_Expr}, () => {sectionPathExpr})";
|
||||||
parsedValueExpr = $"{helperMethodDisplayString}({stringValueToParse_Expr}, () => {sectionPathExpr})";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!checkForNullSectionValue)
|
if (!checkForNullSectionValue)
|
||||||
|
@ -156,7 +162,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
|
||||||
string initExpr;
|
string initExpr;
|
||||||
CollectionSpec? collectionType = type as CollectionSpec;
|
CollectionSpec? collectionType = type as CollectionSpec;
|
||||||
|
|
||||||
string effectiveDisplayString = GetTypeDisplayString(type);
|
string effectiveDisplayString = type.DisplayString;
|
||||||
if (collectionType is not null)
|
if (collectionType is not null)
|
||||||
{
|
{
|
||||||
if (collectionType is EnumerableSpec { InitializationStrategy: InitializationStrategy.Array })
|
if (collectionType is EnumerableSpec { InitializationStrategy: InitializationStrategy.Array })
|
||||||
|
@ -165,7 +171,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
effectiveDisplayString = GetTypeDisplayString(collectionType.ConcreteType ?? collectionType);
|
effectiveDisplayString = (collectionType.ConcreteType ?? collectionType).DisplayString;
|
||||||
initExpr = $"new {effectiveDisplayString}()";
|
initExpr = $"new {effectiveDisplayString}()";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -215,36 +221,41 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void EmitCastToIConfigurationSection()
|
private void EmitInterceptsLocationAttrDecl()
|
||||||
{
|
{
|
||||||
string sectionTypeDisplayString;
|
_writer.WriteLine();
|
||||||
string exceptionTypeDisplayString;
|
|
||||||
if (_useFullyQualifiedNames)
|
|
||||||
{
|
|
||||||
sectionTypeDisplayString = "global::Microsoft.Extensions.Configuration.IConfigurationSection";
|
|
||||||
exceptionTypeDisplayString = FullyQualifiedDisplayString.InvalidOperationException;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
sectionTypeDisplayString = Identifier.IConfigurationSection;
|
|
||||||
exceptionTypeDisplayString = nameof(InvalidOperationException);
|
|
||||||
}
|
|
||||||
|
|
||||||
_writer.WriteLine($$"""
|
_writer.WriteLine($$"""
|
||||||
if ({{Identifier.configuration}} is not {{sectionTypeDisplayString}} {{Identifier.section}})
|
namespace System.Runtime.CompilerServices
|
||||||
{
|
{
|
||||||
throw new {{exceptionTypeDisplayString}}();
|
using System;
|
||||||
|
using System.CodeDom.Compiler;
|
||||||
|
|
||||||
|
{{Expression.GeneratedCodeAnnotation}}
|
||||||
|
[AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]
|
||||||
|
file sealed class InterceptsLocationAttribute : Attribute
|
||||||
|
{
|
||||||
|
public InterceptsLocationAttribute(string filePath, int line, int column)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
""");
|
""");
|
||||||
|
_writer.WriteLine();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void EmitUsingStatements()
|
||||||
|
{
|
||||||
|
foreach (string @namespace in _sourceGenSpec.Namespaces.ToImmutableSortedSet())
|
||||||
|
{
|
||||||
|
_writer.WriteLine($"using {@namespace};");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void EmitIConfigurationHasValueOrChildrenCheck(bool voidReturn)
|
private void EmitIConfigurationHasValueOrChildrenCheck(bool voidReturn)
|
||||||
{
|
{
|
||||||
string returnPostfix = voidReturn ? string.Empty : " null";
|
string returnPostfix = voidReturn ? string.Empty : " null";
|
||||||
string methodDisplayString = GetHelperMethodDisplayString(Identifier.HasValueOrChildren);
|
|
||||||
|
|
||||||
_writer.WriteLine($$"""
|
_writer.WriteLine($$"""
|
||||||
if (!{{methodDisplayString}}({{Identifier.configuration}}))
|
if (!{{Identifier.HasValueOrChildren}}({{Identifier.configuration}}))
|
||||||
{
|
{
|
||||||
return{{returnPostfix}};
|
return{{returnPostfix}};
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,12 +1,14 @@
|
||||||
// Licensed to the .NET Foundation under one or more agreements.
|
// Licensed to the .NET Foundation under one or more agreements.
|
||||||
// The .NET Foundation licenses this file to you under the MIT license.
|
// The .NET Foundation licenses this file to you under the MIT license.
|
||||||
|
|
||||||
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Collections.Immutable;
|
using System.Collections.Immutable;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Diagnostics.CodeAnalysis;
|
using System.Diagnostics.CodeAnalysis;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Microsoft.CodeAnalysis;
|
using Microsoft.CodeAnalysis;
|
||||||
|
using Microsoft.CodeAnalysis.Operations;
|
||||||
|
|
||||||
namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
|
namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
|
||||||
{
|
{
|
||||||
|
@ -147,7 +149,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
|
||||||
{
|
{
|
||||||
// List<string> is used in generated code as a temp holder for formatting
|
// List<string> is used in generated code as a temp holder for formatting
|
||||||
// an error for config properties that don't map to object properties.
|
// an error for config properties that don't map to object properties.
|
||||||
_sourceGenSpec.TypeNamespaces.Add("System.Collections.Generic");
|
_sourceGenSpec.Namespaces.Add("System.Collections.Generic");
|
||||||
|
|
||||||
spec = CreateObjectSpec(namedType);
|
spec = CreateObjectSpec(namedType);
|
||||||
}
|
}
|
||||||
|
@ -169,12 +171,36 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
|
||||||
string @namespace = spec.Namespace;
|
string @namespace = spec.Namespace;
|
||||||
if (@namespace is not null and not "<global namespace>")
|
if (@namespace is not null and not "<global namespace>")
|
||||||
{
|
{
|
||||||
_sourceGenSpec.TypeNamespaces.Add(@namespace);
|
_sourceGenSpec.Namespaces.Add(@namespace);
|
||||||
}
|
}
|
||||||
|
|
||||||
return _createdSpecs[type] = spec;
|
return _createdSpecs[type] = spec;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void RegisterTypeForBindCoreMainGen(TypeSpec typeSpec)
|
||||||
|
{
|
||||||
|
if (typeSpec.NeedsMemberBinding)
|
||||||
|
{
|
||||||
|
RegisterTypeForMethodGen(MethodsToGen_CoreBindingHelper.BindCoreMain, typeSpec);
|
||||||
|
RegisterTypeForBindCoreGen(typeSpec);
|
||||||
|
_sourceGenSpec.MethodsToGen_CoreBindingHelper |= MethodsToGen_CoreBindingHelper.AsConfigWithChildren;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void RegisterTypeForBindCoreGen(TypeSpec typeSpec)
|
||||||
|
{
|
||||||
|
if (typeSpec.NeedsMemberBinding)
|
||||||
|
{
|
||||||
|
RegisterTypeForMethodGen(MethodsToGen_CoreBindingHelper.BindCore, typeSpec);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void RegisterTypeForGetCoreGen(TypeSpec typeSpec)
|
||||||
|
{
|
||||||
|
RegisterTypeForMethodGen(MethodsToGen_CoreBindingHelper.GetCore, typeSpec);
|
||||||
|
_sourceGenSpec.MethodsToGen_CoreBindingHelper |= MethodsToGen_CoreBindingHelper.AsConfigWithChildren;
|
||||||
|
}
|
||||||
|
|
||||||
private void RegisterTypeForMethodGen(MethodsToGen_CoreBindingHelper method, TypeSpec type)
|
private void RegisterTypeForMethodGen(MethodsToGen_CoreBindingHelper method, TypeSpec type)
|
||||||
{
|
{
|
||||||
if (!_sourceGenSpec.TypesForGen_CoreBindingHelper_Methods.TryGetValue(method, out HashSet<TypeSpec>? types))
|
if (!_sourceGenSpec.TypesForGen_CoreBindingHelper_Methods.TryGetValue(method, out HashSet<TypeSpec>? types))
|
||||||
|
@ -186,14 +212,12 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
|
||||||
_sourceGenSpec.MethodsToGen_CoreBindingHelper |= method;
|
_sourceGenSpec.MethodsToGen_CoreBindingHelper |= method;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void RegisterTypeForBindCoreUntypedGen(TypeSpec typeSpec)
|
/// <summary>
|
||||||
{
|
/// Registers interceptors for root binding methods, except for ConfigurationBinder.Bind,
|
||||||
if (typeSpec.NeedsMemberBinding)
|
/// which is handled by <see cref="RegisterAsInterceptor_ConfigBinder_BindMethod"/>
|
||||||
{
|
/// </summary>
|
||||||
RegisterTypeForMethodGen(MethodsToGen_CoreBindingHelper.BindCore, typeSpec);
|
private void RegisterAsInterceptor(Enum method, IInvocationOperation operation) =>
|
||||||
RegisterTypeForMethodGen(MethodsToGen_CoreBindingHelper.BindCoreUntyped, typeSpec);
|
_sourceGenSpec.InterceptionInfo.RegisterCacheEntry(method, new InterceptorLocationInfo(operation));
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static bool IsNullable(ITypeSymbol type, [NotNullWhen(true)] out ITypeSymbol? underlyingType)
|
private static bool IsNullable(ITypeSymbol type, [NotNullWhen(true)] out ITypeSymbol? underlyingType)
|
||||||
{
|
{
|
||||||
|
@ -335,7 +359,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
|
||||||
|
|
||||||
// We want a BindCore method for List<TElement> as a temp holder for the array values. We know the element type is supported.
|
// We want a BindCore method for List<TElement> as a temp holder for the array values. We know the element type is supported.
|
||||||
EnumerableSpec listSpec = (GetOrCreateTypeSpec(_typeSymbols.List.Construct(arrayType.ElementType)) as EnumerableSpec)!;
|
EnumerableSpec listSpec = (GetOrCreateTypeSpec(_typeSymbols.List.Construct(arrayType.ElementType)) as EnumerableSpec)!;
|
||||||
RegisterTypeForMethodGen(MethodsToGen_CoreBindingHelper.BindCore, listSpec);
|
RegisterTypeForBindCoreGen(listSpec);
|
||||||
|
|
||||||
EnumerableSpec spec = new EnumerableSpec(arrayType)
|
EnumerableSpec spec = new EnumerableSpec(arrayType)
|
||||||
{
|
{
|
||||||
|
@ -347,7 +371,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
|
||||||
};
|
};
|
||||||
|
|
||||||
Debug.Assert(spec.CanInitialize);
|
Debug.Assert(spec.CanInitialize);
|
||||||
RegisterTypeForMethodGen(MethodsToGen_CoreBindingHelper.BindCore, spec);
|
RegisterTypeForBindCoreGen(spec);
|
||||||
|
|
||||||
return spec;
|
return spec;
|
||||||
}
|
}
|
||||||
|
@ -383,7 +407,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
|
||||||
|
|
||||||
if (spec is not null)
|
if (spec is not null)
|
||||||
{
|
{
|
||||||
RegisterTypeForMethodGen(MethodsToGen_CoreBindingHelper.BindCore, spec);
|
RegisterTypeForBindCoreGen(spec);
|
||||||
spec.InitExceptionMessage ??= spec.ElementType.InitExceptionMessage;
|
spec.InitExceptionMessage ??= spec.ElementType.InitExceptionMessage;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -442,7 +466,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
|
||||||
constructionStrategy = InitializationStrategy.ToEnumerableMethod;
|
constructionStrategy = InitializationStrategy.ToEnumerableMethod;
|
||||||
populationStrategy = CollectionPopulationStrategy.Cast_Then_Add;
|
populationStrategy = CollectionPopulationStrategy.Cast_Then_Add;
|
||||||
toEnumerableMethodCall = "ToDictionary(pair => pair.Key, pair => pair.Value)";
|
toEnumerableMethodCall = "ToDictionary(pair => pair.Key, pair => pair.Value)";
|
||||||
_sourceGenSpec.TypeNamespaces.Add("System.Linq");
|
_sourceGenSpec.Namespaces.Add("System.Linq");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -711,7 +735,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
|
||||||
|
|
||||||
if (objectSpec.NeedsMemberBinding)
|
if (objectSpec.NeedsMemberBinding)
|
||||||
{
|
{
|
||||||
RegisterTypeForMethodGen(MethodsToGen_CoreBindingHelper.BindCore, objectSpec);
|
RegisterTypeForBindCoreGen(objectSpec);
|
||||||
}
|
}
|
||||||
|
|
||||||
return objectSpec;
|
return objectSpec;
|
||||||
|
@ -890,4 +914,19 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static class ParserExtensions
|
||||||
|
{
|
||||||
|
public static void RegisterCacheEntry<TKey, TValue, TEntry>(this Dictionary<TKey, TValue> cache, TKey key, TEntry entry)
|
||||||
|
where TKey : notnull
|
||||||
|
where TValue : ICollection<TEntry>, new()
|
||||||
|
{
|
||||||
|
if (!cache.TryGetValue(key, out TValue? entryCollection))
|
||||||
|
{
|
||||||
|
cache[key] = entryCollection = new TValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
entryCollection.Add(entry);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,70 @@
|
||||||
|
// Licensed to the .NET Foundation under one or more agreements.
|
||||||
|
// The .NET Foundation licenses this file to you under the MIT license.
|
||||||
|
|
||||||
|
using System.Collections.Immutable;
|
||||||
|
using Microsoft.CodeAnalysis;
|
||||||
|
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
||||||
|
using Microsoft.CodeAnalysis.Diagnostics;
|
||||||
|
using Microsoft.CodeAnalysis.Operations;
|
||||||
|
|
||||||
|
namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
|
||||||
|
{
|
||||||
|
public sealed partial class ConfigurationBindingGenerator
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Supresses false-positive diagnostics emitted by the linker
|
||||||
|
/// when analyzing binding invocations that we have intercepted.
|
||||||
|
/// Workaround for https://github.com/dotnet/roslyn/issues/68669.
|
||||||
|
/// </summary>
|
||||||
|
[DiagnosticAnalyzer(LanguageNames.CSharp)]
|
||||||
|
public sealed class Suppressor : DiagnosticSuppressor
|
||||||
|
{
|
||||||
|
private const string Justification = "The target method has been intercepted by a generated static variant.";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Suppression descriptor for IL2026: Members attributed with RequiresUnreferencedCode may break when trimming.
|
||||||
|
/// </summary>
|
||||||
|
private static readonly SuppressionDescriptor RUCDiagnostic = new(id: "SYSLIBSUPPRESS0002", suppressedDiagnosticId: "IL2026", Justification);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Suppression descriptor for IL3050: Avoid calling members annotated with 'RequiresDynamicCodeAttribute' when publishing as native AOT.
|
||||||
|
/// </summary>
|
||||||
|
private static readonly SuppressionDescriptor RDCDiagnostic = new(id: "SYSLIBSUPPRESS0003", suppressedDiagnosticId: "IL3050", Justification);
|
||||||
|
|
||||||
|
public override ImmutableArray<SuppressionDescriptor> SupportedSuppressions => ImmutableArray.Create(RUCDiagnostic, RDCDiagnostic);
|
||||||
|
|
||||||
|
public override void ReportSuppressions(SuppressionAnalysisContext context)
|
||||||
|
{
|
||||||
|
foreach (Diagnostic diagnostic in context.ReportedDiagnostics)
|
||||||
|
{
|
||||||
|
string diagnosticId = diagnostic.Id;
|
||||||
|
|
||||||
|
if (diagnosticId != RDCDiagnostic.SuppressedDiagnosticId && diagnosticId != RUCDiagnostic.SuppressedDiagnosticId)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
Location location = diagnostic.AdditionalLocations.Count > 0
|
||||||
|
? diagnostic.AdditionalLocations[0]
|
||||||
|
: diagnostic.Location;
|
||||||
|
|
||||||
|
bool shouldSuppressDiagnostic =
|
||||||
|
location.SourceTree is SyntaxTree sourceTree &&
|
||||||
|
sourceTree.GetRoot().FindNode(location.SourceSpan) is SyntaxNode syntaxNode &&
|
||||||
|
BinderInvocation.IsCandidateSyntaxNode(syntaxNode) &&
|
||||||
|
context.GetSemanticModel(sourceTree)
|
||||||
|
.GetOperation((InvocationExpressionSyntax)syntaxNode, context.CancellationToken) is IInvocationOperation operation &&
|
||||||
|
BinderInvocation.IsBindingOperation(operation);
|
||||||
|
|
||||||
|
if (shouldSuppressDiagnostic)
|
||||||
|
{
|
||||||
|
SuppressionDescriptor targetSuppression = diagnosticId == RUCDiagnostic.SuppressedDiagnosticId
|
||||||
|
? RUCDiagnostic
|
||||||
|
: RDCDiagnostic;
|
||||||
|
context.ReportSuppression(Suppression.Create(targetSuppression, diagnostic));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -5,7 +5,6 @@
|
||||||
using System.Collections.Immutable;
|
using System.Collections.Immutable;
|
||||||
using Microsoft.CodeAnalysis;
|
using Microsoft.CodeAnalysis;
|
||||||
using Microsoft.CodeAnalysis.CSharp;
|
using Microsoft.CodeAnalysis.CSharp;
|
||||||
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
|
||||||
|
|
||||||
namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
|
namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
|
||||||
{
|
{
|
||||||
|
@ -15,7 +14,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
|
||||||
[Generator]
|
[Generator]
|
||||||
public sealed partial class ConfigurationBindingGenerator : IIncrementalGenerator
|
public sealed partial class ConfigurationBindingGenerator : IIncrementalGenerator
|
||||||
{
|
{
|
||||||
internal const string ProjectName = "Microsoft.Extensions.Configuration.Binder.SourceGeneration";
|
private static readonly string ProjectName = Emitter.s_assemblyName.Name;
|
||||||
|
|
||||||
public void Initialize(IncrementalGeneratorInitializationContext context)
|
public void Initialize(IncrementalGeneratorInitializationContext context)
|
||||||
{
|
{
|
||||||
|
@ -42,9 +41,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
|
||||||
context.RegisterSourceOutput(inputData, (spc, source) => Execute(source.Item1, source.Item2, spc));
|
context.RegisterSourceOutput(inputData, (spc, source) => Execute(source.Item1, source.Item2, spc));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Generates source code to optimize binding with ConfigurationBinder.
|
|
||||||
/// </summary>
|
|
||||||
private static void Execute(CompilationData compilationData, ImmutableArray<BinderInvocation> inputCalls, SourceProductionContext context)
|
private static void Execute(CompilationData compilationData, ImmutableArray<BinderInvocation> inputCalls, SourceProductionContext context)
|
||||||
{
|
{
|
||||||
if (inputCalls.IsDefaultOrEmpty)
|
if (inputCalls.IsDefaultOrEmpty)
|
||||||
|
@ -73,7 +69,11 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
|
||||||
|
|
||||||
public CompilationData(CSharpCompilation compilation)
|
public CompilationData(CSharpCompilation compilation)
|
||||||
{
|
{
|
||||||
LanguageVersionIsSupported = compilation.LanguageVersion >= LanguageVersion.CSharp11;
|
// We don't have a CSharp21 value available yet. Polyfill the value here for forward compat, rather than use the LangugeVersion.Preview enum value.
|
||||||
|
// https://github.com/dotnet/roslyn/blob/168689931cb4e3150641ec2fb188a64ce4b3b790/src/Compilers/CSharp/Portable/LanguageVersion.cs#L218-L232
|
||||||
|
const int LangVersion_CSharp12 = 1200;
|
||||||
|
LanguageVersionIsSupported = (int)compilation.LanguageVersion >= LangVersion_CSharp12;
|
||||||
|
|
||||||
if (LanguageVersionIsSupported)
|
if (LanguageVersionIsSupported)
|
||||||
{
|
{
|
||||||
TypeSymbols = new KnownTypeSymbols(compilation);
|
TypeSymbols = new KnownTypeSymbols(compilation);
|
||||||
|
|
|
@ -2,9 +2,7 @@
|
||||||
// The .NET Foundation licenses this file to you under the MIT license.
|
// The .NET Foundation licenses this file to you under the MIT license.
|
||||||
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics;
|
using SourceGenerators;
|
||||||
using System.Linq;
|
|
||||||
using Microsoft.CodeAnalysis;
|
|
||||||
|
|
||||||
namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
|
namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
|
||||||
{
|
{
|
||||||
|
@ -14,91 +12,84 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
|
||||||
{
|
{
|
||||||
private bool ShouldEmitMethods(MethodsToGen_ConfigurationBinder methods) => (_sourceGenSpec.MethodsToGen_ConfigurationBinder & methods) != 0;
|
private bool ShouldEmitMethods(MethodsToGen_ConfigurationBinder methods) => (_sourceGenSpec.MethodsToGen_ConfigurationBinder & methods) != 0;
|
||||||
|
|
||||||
private void EmitBinder_Extensions_IConfiguration()
|
private void EmitBindingExtensions_IConfiguration()
|
||||||
{
|
{
|
||||||
Debug.Assert(_sourceGenSpec.TypesForGen_ConfigurationBinder_BindMethods.Count <= 3 &&
|
|
||||||
!_sourceGenSpec.TypesForGen_ConfigurationBinder_BindMethods.Keys.Any(overload => (overload & MethodsToGen_ConfigurationBinder.Bind) is 0));
|
|
||||||
|
|
||||||
if (!ShouldEmitMethods(MethodsToGen_ConfigurationBinder.Any))
|
if (!ShouldEmitMethods(MethodsToGen_ConfigurationBinder.Any))
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
_emitBlankLineBeforeNextStatement = false;
|
EmitBindingExtStartRegion(Identifier.IConfiguration);
|
||||||
EmitRootBindingClassStartBlock(Identifier.GeneratedConfigurationBinder);
|
|
||||||
|
|
||||||
EmitGetMethods();
|
EmitGetMethods();
|
||||||
EmitGetValueMethods();
|
EmitGetValueMethods();
|
||||||
EmitBindMethods_ConfigurationBinder();
|
EmitBindMethods_ConfigurationBinder();
|
||||||
|
EmitBindingExtEndRegion();
|
||||||
EmitEndBlock();
|
|
||||||
_emitBlankLineBeforeNextStatement = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void EmitGetMethods()
|
private void EmitGetMethods()
|
||||||
{
|
{
|
||||||
const string expressionForGetCore = $"{FullyQualifiedDisplayString.CoreBindingHelper}.{nameof(MethodsToGen_CoreBindingHelper.GetCore)}";
|
const string expressionForGetCore = nameof(MethodsToGen_CoreBindingHelper.GetCore);
|
||||||
const string documentation = "Attempts to bind the configuration instance to a new instance of type T.";
|
const string documentation = "Attempts to bind the configuration instance to a new instance of type T.";
|
||||||
|
|
||||||
if (ShouldEmitMethods(MethodsToGen_ConfigurationBinder.Get_T))
|
if (ShouldEmitMethods(MethodsToGen_ConfigurationBinder.Get_T))
|
||||||
{
|
{
|
||||||
StartMethodDefinition(documentation);
|
StartMethodDefinition(MethodsToGen_ConfigurationBinder.Get_T, documentation);
|
||||||
_writer.WriteLine($"public static T? {Identifier.Get}<T>(this {FullyQualifiedDisplayString.IConfiguration} {Identifier.configuration}) => " +
|
_writer.WriteLine($"public static T? {Identifier.Get}<T>(this {Identifier.IConfiguration} {Identifier.configuration}) => " +
|
||||||
$"(T?)({expressionForGetCore}({Identifier.configuration}, typeof(T), {Identifier.configureOptions}: null) ?? default(T));");
|
$"(T?)({expressionForGetCore}({Identifier.configuration}, typeof(T), {Identifier.configureOptions}: null) ?? default(T));");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ShouldEmitMethods(MethodsToGen_ConfigurationBinder.Get_T_BinderOptions))
|
if (ShouldEmitMethods(MethodsToGen_ConfigurationBinder.Get_T_BinderOptions))
|
||||||
{
|
{
|
||||||
StartMethodDefinition(documentation);
|
StartMethodDefinition(MethodsToGen_ConfigurationBinder.Get_T_BinderOptions, documentation);
|
||||||
_writer.WriteLine($"public static T? {Identifier.Get}<T>(this {FullyQualifiedDisplayString.IConfiguration} {Identifier.configuration}, {FullyQualifiedDisplayString.ActionOfBinderOptions}? {Identifier.configureOptions}) => " +
|
_writer.WriteLine($"public static T? {Identifier.Get}<T>(this {Identifier.IConfiguration} {Identifier.configuration}, {TypeDisplayString.NullableActionOfBinderOptions} {Identifier.configureOptions}) => " +
|
||||||
$"(T?)({expressionForGetCore}({Identifier.configuration}, typeof(T), {Identifier.configureOptions}) ?? default(T));");
|
$"(T?)({expressionForGetCore}({Identifier.configuration}, typeof(T), {Identifier.configureOptions}) ?? default(T));");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ShouldEmitMethods(MethodsToGen_ConfigurationBinder.Get_TypeOf))
|
if (ShouldEmitMethods(MethodsToGen_ConfigurationBinder.Get_TypeOf))
|
||||||
{
|
{
|
||||||
StartMethodDefinition(documentation);
|
StartMethodDefinition(MethodsToGen_ConfigurationBinder.Get_TypeOf, documentation);
|
||||||
_writer.WriteLine($"public static object? {Identifier.Get}(this {FullyQualifiedDisplayString.IConfiguration} {Identifier.configuration}, {FullyQualifiedDisplayString.Type} {Identifier.type}) => " +
|
_writer.WriteLine($"public static object? {Identifier.Get}(this {Identifier.IConfiguration} {Identifier.configuration}, Type {Identifier.type}) => " +
|
||||||
$"{expressionForGetCore}({Identifier.configuration}, {Identifier.type}, {Identifier.configureOptions}: null);");
|
$"{expressionForGetCore}({Identifier.configuration}, {Identifier.type}, {Identifier.configureOptions}: null);");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ShouldEmitMethods(MethodsToGen_ConfigurationBinder.Get_TypeOf_BinderOptions))
|
if (ShouldEmitMethods(MethodsToGen_ConfigurationBinder.Get_TypeOf_BinderOptions))
|
||||||
{
|
{
|
||||||
StartMethodDefinition(documentation);
|
StartMethodDefinition(MethodsToGen_ConfigurationBinder.Get_TypeOf_BinderOptions, documentation);
|
||||||
_writer.WriteLine($"public static object? {Identifier.Get}(this {FullyQualifiedDisplayString.IConfiguration} {Identifier.configuration}, {FullyQualifiedDisplayString.Type} {Identifier.type}, {FullyQualifiedDisplayString.ActionOfBinderOptions}? {Identifier.configureOptions}) => " +
|
_writer.WriteLine($"public static object? {Identifier.Get}(this {Identifier.IConfiguration} {Identifier.configuration}, Type {Identifier.type}, {TypeDisplayString.NullableActionOfBinderOptions} {Identifier.configureOptions}) => " +
|
||||||
$"{expressionForGetCore}({Identifier.configuration}, {Identifier.type}, {Identifier.configureOptions});");
|
$"{expressionForGetCore}({Identifier.configuration}, {Identifier.type}, {Identifier.configureOptions});");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void EmitGetValueMethods()
|
private void EmitGetValueMethods()
|
||||||
{
|
{
|
||||||
const string expressionForGetValueCore = $"{FullyQualifiedDisplayString.CoreBindingHelper}.{nameof(MethodsToGen_CoreBindingHelper.GetValueCore)}";
|
const string expressionForGetValueCore = $"{Identifier.BindingExtensions}.{nameof(MethodsToGen_CoreBindingHelper.GetValueCore)}";
|
||||||
const string documentation = "Extracts the value with the specified key and converts it to the specified type.";
|
const string documentation = "Extracts the value with the specified key and converts it to the specified type.";
|
||||||
|
|
||||||
if (ShouldEmitMethods(MethodsToGen_ConfigurationBinder.GetValue_T_key))
|
if (ShouldEmitMethods(MethodsToGen_ConfigurationBinder.GetValue_T_key))
|
||||||
{
|
{
|
||||||
StartMethodDefinition(documentation);
|
StartMethodDefinition(MethodsToGen_ConfigurationBinder.GetValue_T_key, documentation);
|
||||||
_writer.WriteLine($"public static T? {Identifier.GetValue}<T>(this {FullyQualifiedDisplayString.IConfiguration} {Identifier.configuration}, string {Identifier.key}) => " +
|
_writer.WriteLine($"public static T? {Identifier.GetValue}<T>(this {Identifier.IConfiguration} {Identifier.configuration}, string {Identifier.key}) => " +
|
||||||
$"(T?)({expressionForGetValueCore}({Identifier.configuration}, typeof(T), {Identifier.key}) ?? default(T));");
|
$"(T?)({expressionForGetValueCore}({Identifier.configuration}, typeof(T), {Identifier.key}) ?? default(T));");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ShouldEmitMethods(MethodsToGen_ConfigurationBinder.GetValue_T_key_defaultValue))
|
if (ShouldEmitMethods(MethodsToGen_ConfigurationBinder.GetValue_T_key_defaultValue))
|
||||||
{
|
{
|
||||||
StartMethodDefinition(documentation);
|
StartMethodDefinition(MethodsToGen_ConfigurationBinder.GetValue_T_key_defaultValue, documentation);
|
||||||
_writer.WriteLine($"public static T? {Identifier.GetValue}<T>(this {FullyQualifiedDisplayString.IConfiguration} {Identifier.configuration}, string {Identifier.key}, T {Identifier.defaultValue}) => " +
|
_writer.WriteLine($"public static T? {Identifier.GetValue}<T>(this {Identifier.IConfiguration} {Identifier.configuration}, string {Identifier.key}, T {Identifier.defaultValue}) => " +
|
||||||
$"(T?)({expressionForGetValueCore}({Identifier.configuration}, typeof(T), {Identifier.key}) ?? {Identifier.defaultValue});");
|
$"(T?)({expressionForGetValueCore}({Identifier.configuration}, typeof(T), {Identifier.key}) ?? {Identifier.defaultValue});");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ShouldEmitMethods(MethodsToGen_ConfigurationBinder.GetValue_TypeOf_key))
|
if (ShouldEmitMethods(MethodsToGen_ConfigurationBinder.GetValue_TypeOf_key))
|
||||||
{
|
{
|
||||||
StartMethodDefinition(documentation);
|
StartMethodDefinition(MethodsToGen_ConfigurationBinder.GetValue_TypeOf_key, documentation);
|
||||||
_writer.WriteLine($"public static object? {Identifier.GetValue}(this {FullyQualifiedDisplayString.IConfiguration} {Identifier.configuration}, {FullyQualifiedDisplayString.Type} {Identifier.type}, string {Identifier.key}) => " +
|
_writer.WriteLine($"public static object? {Identifier.GetValue}(this {Identifier.IConfiguration} {Identifier.configuration}, Type {Identifier.type}, string {Identifier.key}) => " +
|
||||||
$"{expressionForGetValueCore}({Identifier.configuration}, {Identifier.type}, {Identifier.key});");
|
$"{expressionForGetValueCore}({Identifier.configuration}, {Identifier.type}, {Identifier.key});");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ShouldEmitMethods(MethodsToGen_ConfigurationBinder.GetValue_TypeOf_key_defaultValue))
|
if (ShouldEmitMethods(MethodsToGen_ConfigurationBinder.GetValue_TypeOf_key_defaultValue))
|
||||||
{
|
{
|
||||||
StartMethodDefinition(documentation);
|
StartMethodDefinition(MethodsToGen_ConfigurationBinder.GetValue_TypeOf_key_defaultValue, documentation);
|
||||||
_writer.WriteLine($"public static object? {Identifier.GetValue}(this {FullyQualifiedDisplayString.IConfiguration} {Identifier.configuration}, {FullyQualifiedDisplayString.Type} {Identifier.type}, string {Identifier.key}, object? {Identifier.defaultValue}) => " +
|
_writer.WriteLine($"public static object? {Identifier.GetValue}(this {Identifier.IConfiguration} {Identifier.configuration}, Type {Identifier.type}, string {Identifier.key}, object? {Identifier.defaultValue}) => " +
|
||||||
$"{expressionForGetValueCore}({Identifier.configuration}, {Identifier.type}, {Identifier.key}) ?? {Identifier.defaultValue};");
|
$"{expressionForGetValueCore}({Identifier.configuration}, {Identifier.type}, {Identifier.key}) ?? {Identifier.defaultValue};");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -110,72 +101,71 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Dictionary<MethodsToGen_ConfigurationBinder, HashSet<TypeSpec>> types = _sourceGenSpec.TypesForGen_ConfigurationBinder_BindMethods;
|
string objParamExpr = $"object? {Identifier.obj}";
|
||||||
|
|
||||||
if (types.TryGetValue(MethodsToGen_ConfigurationBinder.Bind_instance, out HashSet<TypeSpec>? typeSpecs))
|
if (ShouldEmitMethods(MethodsToGen_ConfigurationBinder.Bind_instance))
|
||||||
{
|
{
|
||||||
foreach (TypeSpec type in typeSpecs)
|
EmitMethods(
|
||||||
{
|
MethodsToGen_ConfigurationBinder.Bind_instance,
|
||||||
EmitMethodImplementation(
|
additionalParams: objParamExpr,
|
||||||
type,
|
configExpression: Identifier.configuration,
|
||||||
additionalParams: GetObjParameter(type),
|
configureOptions: false);
|
||||||
configExpression: Identifier.configuration,
|
|
||||||
configureOptions: false);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (types.TryGetValue(MethodsToGen_ConfigurationBinder.Bind_instance_BinderOptions, out typeSpecs))
|
if (ShouldEmitMethods(MethodsToGen_ConfigurationBinder.Bind_instance_BinderOptions))
|
||||||
{
|
{
|
||||||
foreach (TypeSpec type in typeSpecs)
|
EmitMethods(
|
||||||
{
|
MethodsToGen_ConfigurationBinder.Bind_instance_BinderOptions,
|
||||||
EmitMethodImplementation(
|
additionalParams: $"{objParamExpr}, {TypeDisplayString.NullableActionOfBinderOptions} {Identifier.configureOptions}",
|
||||||
type,
|
configExpression: Identifier.configuration,
|
||||||
additionalParams: $"{GetObjParameter(type)}, {FullyQualifiedDisplayString.ActionOfBinderOptions}? {Identifier.configureOptions}",
|
configureOptions: true);
|
||||||
configExpression: Identifier.configuration,
|
|
||||||
configureOptions: true);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (types.TryGetValue(MethodsToGen_ConfigurationBinder.Bind_key_instance, out typeSpecs))
|
if (ShouldEmitMethods(MethodsToGen_ConfigurationBinder.Bind_key_instance))
|
||||||
{
|
{
|
||||||
foreach (TypeSpec type in typeSpecs)
|
EmitMethods(
|
||||||
{
|
MethodsToGen_ConfigurationBinder.Bind_key_instance,
|
||||||
EmitMethodImplementation(
|
additionalParams: $"string {Identifier.key}, {objParamExpr}",
|
||||||
type,
|
configExpression: $"{Expression.configurationGetSection}({Identifier.key})",
|
||||||
additionalParams: $"string {Identifier.key}, {GetObjParameter(type)}",
|
configureOptions: false);
|
||||||
configExpression: $"{Expression.configurationGetSection}({Identifier.key})",
|
|
||||||
configureOptions: false);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitMethodImplementation(TypeSpec type, string additionalParams, string configExpression, bool configureOptions)
|
void EmitMethods(MethodsToGen_ConfigurationBinder method, string additionalParams, string configExpression, bool configureOptions)
|
||||||
{
|
{
|
||||||
string binderOptionsArg = configureOptions ? $"{Expression.GetBinderOptions}({Identifier.configureOptions})" : $"{Identifier.binderOptions}: null";
|
foreach (KeyValuePair<TypeSpec, List<InterceptorLocationInfo>> pair in _sourceGenSpec.InterceptionInfo_ConfigBinder.GetOverloadInfo(method))
|
||||||
|
|
||||||
string returnExpression;
|
|
||||||
if (type.CanInitialize)
|
|
||||||
{
|
{
|
||||||
returnExpression = type.NeedsMemberBinding
|
(TypeSpec type, List<InterceptorLocationInfo> interceptorInfoList) = (pair.Key, pair.Value);
|
||||||
? $"{FullyQualifiedDisplayString.CoreBindingHelper}.{nameof(MethodsToGen_CoreBindingHelper.BindCore)}({configExpression}, ref {Identifier.obj}, {binderOptionsArg})"
|
|
||||||
: "{ }";
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
returnExpression = GetInitException(type.InitExceptionMessage);
|
|
||||||
}
|
|
||||||
|
|
||||||
StartMethodDefinition("Attempts to bind the given object instance to configuration values by matching property names against configuration keys recursively.");
|
EmitBlankLineIfRequired();
|
||||||
_writer.WriteLine($"public static void {Identifier.Bind}(this {FullyQualifiedDisplayString.IConfiguration} {Identifier.configuration}, {additionalParams}) => "
|
_writer.WriteLine($"/// <summary>Attempts to bind the given object instance to configuration values by matching property names against configuration keys recursively.</summary>");
|
||||||
+ $"{returnExpression};");
|
EmitInterceptsLocationAnnotations(interceptorInfoList);
|
||||||
|
EmitStartBlock($"public static void {Identifier.Bind}_{type.DisplayString.ToIdentifierSubstring()}(this {Identifier.IConfiguration} {Identifier.configuration}, {additionalParams})");
|
||||||
|
|
||||||
|
if (!EmitInitException(type) && type.NeedsMemberBinding)
|
||||||
|
{
|
||||||
|
string binderOptionsArg = configureOptions ? $"{Identifier.GetBinderOptions}({Identifier.configureOptions})" : $"{Identifier.binderOptions}: null";
|
||||||
|
|
||||||
|
EmitCheckForNullArgument_WithBlankLine(Identifier.configuration);
|
||||||
|
if (!type.IsValueType)
|
||||||
|
{
|
||||||
|
EmitCheckForNullArgument_WithBlankLine(Identifier.obj);
|
||||||
|
}
|
||||||
|
_writer.WriteLine($$"""
|
||||||
|
var {{Identifier.typedObj}} = ({{type.EffectiveType.DisplayString}}){{Identifier.obj}};
|
||||||
|
{{nameof(MethodsToGen_CoreBindingHelper.BindCore)}}({{configExpression}}, ref {{Identifier.typedObj}}, {{binderOptionsArg}});
|
||||||
|
""");
|
||||||
|
}
|
||||||
|
|
||||||
|
EmitEndBlock();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
string GetObjParameter(TypeSpec type) => $"{type.FullyQualifiedDisplayString} {Identifier.obj}";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void StartMethodDefinition(string documentation)
|
private void StartMethodDefinition(MethodsToGen_ConfigurationBinder method, string documentation)
|
||||||
{
|
{
|
||||||
EmitBlankLineIfRequired();
|
EmitBlankLineIfRequired();
|
||||||
_writer.WriteLine($"/// <summary>{documentation}</summary>");
|
_writer.WriteLine($"/// <summary>{documentation}</summary>");
|
||||||
|
EmitInterceptsLocationAnnotations(method);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,10 +3,10 @@
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Collections.Immutable;
|
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Microsoft.CodeAnalysis;
|
using Microsoft.CodeAnalysis;
|
||||||
|
using SourceGenerators;
|
||||||
|
|
||||||
namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
|
namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
|
||||||
{
|
{
|
||||||
|
@ -16,41 +16,18 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
|
||||||
{
|
{
|
||||||
private bool ShouldEmitMethods(MethodsToGen_CoreBindingHelper methods) => (_sourceGenSpec.MethodsToGen_CoreBindingHelper & methods) != 0;
|
private bool ShouldEmitMethods(MethodsToGen_CoreBindingHelper methods) => (_sourceGenSpec.MethodsToGen_CoreBindingHelper & methods) != 0;
|
||||||
|
|
||||||
private void Emit_CoreBindingHelper()
|
private void EmitCoreBindingHelpers()
|
||||||
{
|
{
|
||||||
Debug.Assert(_emitBlankLineBeforeNextStatement);
|
Debug.Assert(_emitBlankLineBeforeNextStatement);
|
||||||
_writer.WriteLine();
|
EmitBindingExtStartRegion("Core binding");
|
||||||
_emitBlankLineBeforeNextStatement = false;
|
|
||||||
|
|
||||||
EmitStartBlock($"namespace {ProjectName}");
|
|
||||||
EmitHelperUsingStatements();
|
|
||||||
|
|
||||||
_writer.WriteLine();
|
|
||||||
|
|
||||||
EmitStartBlock($$"""
|
|
||||||
/// <summary>Provide core binding logic.</summary>
|
|
||||||
{{GetGeneratedCodeAttributeSrc()}}
|
|
||||||
file static class {{Identifier.CoreBindingHelper}}
|
|
||||||
""");
|
|
||||||
|
|
||||||
EmitConfigurationKeyCaches();
|
EmitConfigurationKeyCaches();
|
||||||
EmitGetCoreMethod();
|
EmitGetCoreMethod();
|
||||||
EmitGetValueCoreMethod();
|
EmitGetValueCoreMethod();
|
||||||
EmitBindCoreUntypedMethod();
|
EmitBindCoreMainMethod();
|
||||||
EmitBindCoreMethods();
|
EmitBindCoreMethods();
|
||||||
EmitInitializeMethods();
|
EmitInitializeMethods();
|
||||||
EmitHelperMethods();
|
EmitHelperMethods();
|
||||||
|
EmitBindingExtEndRegion();
|
||||||
EmitEndBlock(); // End helper class.
|
|
||||||
EmitEndBlock(); // End namespace.
|
|
||||||
}
|
|
||||||
|
|
||||||
private void EmitHelperUsingStatements()
|
|
||||||
{
|
|
||||||
foreach (string @namespace in _sourceGenSpec.TypeNamespaces.ToImmutableSortedSet())
|
|
||||||
{
|
|
||||||
_writer.WriteLine($"using {@namespace};");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void EmitConfigurationKeyCaches()
|
private void EmitConfigurationKeyCaches()
|
||||||
|
@ -60,6 +37,8 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
EmitBlankLineIfRequired();
|
||||||
|
|
||||||
foreach (TypeSpec type in targetTypes)
|
foreach (TypeSpec type in targetTypes)
|
||||||
{
|
{
|
||||||
if (type is not ObjectSpec objectType)
|
if (type is not ObjectSpec objectType)
|
||||||
|
@ -73,10 +52,8 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
|
||||||
|
|
||||||
string configKeysSource = string.Join(", ", keys);
|
string configKeysSource = string.Join(", ", keys);
|
||||||
string fieldName = GetConfigKeyCacheFieldName(objectType);
|
string fieldName = GetConfigKeyCacheFieldName(objectType);
|
||||||
_writer.WriteLine($@"private readonly static Lazy<{MinimalDisplayString.HashSetOfString}> {fieldName} = new(() => new {MinimalDisplayString.HashSetOfString}(StringComparer.OrdinalIgnoreCase) {{ {configKeysSource} }});");
|
_writer.WriteLine($@"private readonly static Lazy<{TypeDisplayString.HashSetOfString}> {fieldName} = new(() => new {TypeDisplayString.HashSetOfString}(StringComparer.OrdinalIgnoreCase) {{ {configKeysSource} }});");
|
||||||
}
|
}
|
||||||
|
|
||||||
_emitBlankLineBeforeNextStatement = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void EmitGetCoreMethod()
|
private void EmitGetCoreMethod()
|
||||||
|
@ -96,16 +73,24 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
|
||||||
|
|
||||||
EmitIConfigurationHasValueOrChildrenCheck(voidReturn: false);
|
EmitIConfigurationHasValueOrChildrenCheck(voidReturn: false);
|
||||||
|
|
||||||
|
bool isFirstType = true;
|
||||||
foreach (TypeSpec type in types)
|
foreach (TypeSpec type in types)
|
||||||
{
|
{
|
||||||
TypeSpec effectiveType = type.EffectiveType;
|
TypeSpec effectiveType = type.EffectiveType;
|
||||||
TypeSpecKind kind = effectiveType.SpecKind;
|
TypeSpecKind kind = effectiveType.SpecKind;
|
||||||
|
string conditionKindExpr = GetConditionKindExpr(ref isFirstType);
|
||||||
|
|
||||||
EmitStartBlock($"if (type == typeof({type.MinimalDisplayString}))");
|
EmitStartBlock($"{conditionKindExpr} ({Identifier.type} == typeof({type.DisplayString}))");
|
||||||
|
|
||||||
if (effectiveType is ParsableFromStringSpec stringParsableType)
|
if (effectiveType is ParsableFromStringSpec stringParsableType)
|
||||||
{
|
{
|
||||||
EmitCastToIConfigurationSection();
|
_writer.WriteLine($$"""
|
||||||
|
if ({{Identifier.configuration}} is not {{Identifier.IConfigurationSection}} {{Identifier.section}})
|
||||||
|
{
|
||||||
|
throw new {{Identifier.InvalidOperationException}}();
|
||||||
|
}
|
||||||
|
""");
|
||||||
|
|
||||||
EmitBindLogicFromString(
|
EmitBindLogicFromString(
|
||||||
stringParsableType,
|
stringParsableType,
|
||||||
Expression.sectionValue,
|
Expression.sectionValue,
|
||||||
|
@ -121,9 +106,9 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
|
||||||
}
|
}
|
||||||
|
|
||||||
EmitEndBlock();
|
EmitEndBlock();
|
||||||
_writer.WriteLine();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_writer.WriteLine();
|
||||||
Emit_NotSupportedException_TypeNotDetectedAsInput();
|
Emit_NotSupportedException_TypeNotDetectedAsInput();
|
||||||
EmitEndBlock();
|
EmitEndBlock();
|
||||||
_emitBlankLineBeforeNextStatement = true;
|
_emitBlankLineBeforeNextStatement = true;
|
||||||
|
@ -152,9 +137,11 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
|
||||||
|
|
||||||
_writer.WriteLine();
|
_writer.WriteLine();
|
||||||
|
|
||||||
|
bool isFirstType = true;
|
||||||
foreach (TypeSpec type in targetTypes)
|
foreach (TypeSpec type in targetTypes)
|
||||||
{
|
{
|
||||||
EmitStartBlock($"if ({Identifier.type} == typeof({type.MinimalDisplayString}))");
|
string conditionKindExpr = GetConditionKindExpr(ref isFirstType);
|
||||||
|
EmitStartBlock($"{conditionKindExpr} ({Identifier.type} == typeof({type.DisplayString}))");
|
||||||
|
|
||||||
EmitBindLogicFromString(
|
EmitBindLogicFromString(
|
||||||
(ParsableFromStringSpec)type.EffectiveType,
|
(ParsableFromStringSpec)type.EffectiveType,
|
||||||
|
@ -165,51 +152,48 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
|
||||||
useIncrementalStringValueIdentifier: false);
|
useIncrementalStringValueIdentifier: false);
|
||||||
|
|
||||||
EmitEndBlock();
|
EmitEndBlock();
|
||||||
_writer.WriteLine();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_writer.WriteLine();
|
||||||
_writer.WriteLine("return null;");
|
_writer.WriteLine("return null;");
|
||||||
EmitEndBlock();
|
EmitEndBlock();
|
||||||
_emitBlankLineBeforeNextStatement = true;
|
_emitBlankLineBeforeNextStatement = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void EmitBindCoreUntypedMethod()
|
private void EmitBindCoreMainMethod()
|
||||||
{
|
{
|
||||||
if (!_sourceGenSpec.TypesForGen_CoreBindingHelper_Methods.TryGetValue(MethodsToGen_CoreBindingHelper.BindCoreUntyped, out HashSet<TypeSpec>? targetTypes))
|
if (!_sourceGenSpec.TypesForGen_CoreBindingHelper_Methods.TryGetValue(MethodsToGen_CoreBindingHelper.BindCoreMain, out HashSet<TypeSpec>? targetTypes))
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
EmitBlankLineIfRequired();
|
EmitBlankLineIfRequired();
|
||||||
|
EmitStartBlock($"public static void {nameof(MethodsToGen_CoreBindingHelper.BindCoreMain)}({Identifier.IConfiguration} {Identifier.configuration}, object {Identifier.obj}, Type {Identifier.type}, {TypeDisplayString.NullableActionOfBinderOptions} {Identifier.configureOptions})");
|
||||||
EmitStartBlock($"public static void {nameof(MethodsToGen_CoreBindingHelper.BindCoreUntyped)}(this {Identifier.IConfiguration} {Identifier.configuration}, object {Identifier.obj}, Type {Identifier.type}, {MinimalDisplayString.NullableActionOfBinderOptions} {Identifier.configureOptions})");
|
|
||||||
|
|
||||||
EmitCheckForNullArgument_WithBlankLine(Identifier.configuration);
|
EmitCheckForNullArgument_WithBlankLine(Identifier.configuration);
|
||||||
|
EmitCheckForNullArgument_WithBlankLine(Identifier.obj);
|
||||||
|
EmitIConfigurationHasValueOrChildrenCheck(voidReturn: true);
|
||||||
_writer.WriteLine($"{Identifier.BinderOptions}? {Identifier.binderOptions} = {Identifier.GetBinderOptions}({Identifier.configureOptions});");
|
_writer.WriteLine($"{Identifier.BinderOptions}? {Identifier.binderOptions} = {Identifier.GetBinderOptions}({Identifier.configureOptions});");
|
||||||
_writer.WriteLine();
|
_writer.WriteLine();
|
||||||
|
|
||||||
EmitIConfigurationHasValueOrChildrenCheck(voidReturn: true);
|
bool isFirstType = true;
|
||||||
|
|
||||||
foreach (TypeSpec type in targetTypes)
|
foreach (TypeSpec type in targetTypes)
|
||||||
{
|
{
|
||||||
EmitStartBlock($"if (type == typeof({type.MinimalDisplayString}))");
|
|
||||||
|
|
||||||
TypeSpec effectiveType = type.EffectiveType;
|
TypeSpec effectiveType = type.EffectiveType;
|
||||||
|
string conditionKindExpr = GetConditionKindExpr(ref isFirstType);
|
||||||
|
|
||||||
|
EmitStartBlock($"{conditionKindExpr} ({Identifier.type} == typeof({type.DisplayString}))");
|
||||||
if (!EmitInitException(effectiveType))
|
if (!EmitInitException(effectiveType))
|
||||||
{
|
{
|
||||||
_writer.WriteLine($"var {Identifier.temp} = ({effectiveType.MinimalDisplayString}){Identifier.obj};");
|
_writer.WriteLine($"var {Identifier.temp} = ({effectiveType.DisplayString}){Identifier.obj};");
|
||||||
EmitBindCoreCall(type, Identifier.temp, Identifier.configuration, InitializationKind.None);
|
EmitBindCoreCall(type, Identifier.temp, Identifier.configuration, InitializationKind.None);
|
||||||
_writer.WriteLine($"return;");
|
_writer.WriteLine($"return;");
|
||||||
}
|
}
|
||||||
|
|
||||||
EmitEndBlock();
|
EmitEndBlock();
|
||||||
_writer.WriteLine();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_writer.WriteLine();
|
||||||
Emit_NotSupportedException_TypeNotDetectedAsInput();
|
Emit_NotSupportedException_TypeNotDetectedAsInput();
|
||||||
EmitEndBlock();
|
EmitEndBlock();
|
||||||
_emitBlankLineBeforeNextStatement = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void EmitBindCoreMethods()
|
private void EmitBindCoreMethods()
|
||||||
|
@ -231,11 +215,9 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
|
||||||
{
|
{
|
||||||
Debug.Assert(type.CanInitialize);
|
Debug.Assert(type.CanInitialize);
|
||||||
|
|
||||||
string objParameterExpression = $"ref {type.MinimalDisplayString} {Identifier.obj}";
|
string objParameterExpression = $"ref {type.DisplayString} {Identifier.obj}";
|
||||||
EmitStartBlock(@$"public static void {nameof(MethodsToGen_CoreBindingHelper.BindCore)}({Identifier.IConfiguration} {Identifier.configuration}, {objParameterExpression}, {Identifier.BinderOptions}? {Identifier.binderOptions})");
|
EmitStartBlock(@$"public static void {nameof(MethodsToGen_CoreBindingHelper.BindCore)}({Identifier.IConfiguration} {Identifier.configuration}, {objParameterExpression}, {Identifier.BinderOptions}? {Identifier.binderOptions})");
|
||||||
|
|
||||||
EmitCheckForNullArgument_WithBlankLine_IfRequired(type.IsValueType);
|
|
||||||
|
|
||||||
TypeSpec effectiveType = type.EffectiveType;
|
TypeSpec effectiveType = type.EffectiveType;
|
||||||
if (effectiveType is EnumerableSpec enumerable)
|
if (effectiveType is EnumerableSpec enumerable)
|
||||||
{
|
{
|
||||||
|
@ -281,9 +263,9 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
|
||||||
List<ParameterSpec> ctorParams = type.ConstructorParameters;
|
List<ParameterSpec> ctorParams = type.ConstructorParameters;
|
||||||
IEnumerable<PropertySpec> initOnlyProps = type.Properties.Values.Where(prop => prop is { SetOnInit: true });
|
IEnumerable<PropertySpec> initOnlyProps = type.Properties.Values.Where(prop => prop is { SetOnInit: true });
|
||||||
List<string> ctorArgList = new();
|
List<string> ctorArgList = new();
|
||||||
string displayString = type.MinimalDisplayString;
|
string displayString = type.DisplayString;
|
||||||
|
|
||||||
EmitStartBlock($"public static {type.MinimalDisplayString} {GetInitalizeMethodDisplayString(type)}({Identifier.IConfiguration} {Identifier.configuration}, {Identifier.BinderOptions}? {Identifier.binderOptions})");
|
EmitStartBlock($"public static {type.DisplayString} {GetInitalizeMethodDisplayString(type)}({Identifier.IConfiguration} {Identifier.configuration}, {Identifier.BinderOptions}? {Identifier.binderOptions})");
|
||||||
_emitBlankLineBeforeNextStatement = false;
|
_emitBlankLineBeforeNextStatement = false;
|
||||||
|
|
||||||
foreach (ParameterSpec parameter in ctorParams)
|
foreach (ParameterSpec parameter in ctorParams)
|
||||||
|
@ -335,7 +317,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
|
||||||
TypeSpec memberType = member.Type;
|
TypeSpec memberType = member.Type;
|
||||||
bool errorOnFailedBinding = member.ErrorOnFailedBinding;
|
bool errorOnFailedBinding = member.ErrorOnFailedBinding;
|
||||||
|
|
||||||
string parsedMemberIdentifierDeclarationPrefix = $"{memberType.MinimalDisplayString} {member.Name}";
|
string parsedMemberIdentifierDeclarationPrefix = $"{memberType.DisplayString} {member.Name}";
|
||||||
string parsedMemberIdentifier;
|
string parsedMemberIdentifier;
|
||||||
|
|
||||||
if (memberType is ParsableFromStringSpec { StringParsableTypeKind: StringParsableTypeKind.AssignFromSectionValue })
|
if (memberType is ParsableFromStringSpec { StringParsableTypeKind: StringParsableTypeKind.AssignFromSectionValue })
|
||||||
|
@ -344,7 +326,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
|
||||||
|
|
||||||
if (errorOnFailedBinding)
|
if (errorOnFailedBinding)
|
||||||
{
|
{
|
||||||
string condition = $@" if ({Identifier.configuration}[""{member.ConfigurationKeyName}""] is not {memberType.MinimalDisplayString} {member.Name})";
|
string condition = $@" if ({Identifier.configuration}[""{member.ConfigurationKeyName}""] is not {memberType.DisplayString} {member.Name})";
|
||||||
EmitThrowBlock(condition);
|
EmitThrowBlock(condition);
|
||||||
_writer.WriteLine();
|
_writer.WriteLine();
|
||||||
return;
|
return;
|
||||||
|
@ -393,40 +375,42 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
|
||||||
_writer.WriteLine($$"""
|
_writer.WriteLine($$"""
|
||||||
{{condition}}
|
{{condition}}
|
||||||
{
|
{
|
||||||
throw new {{GetInvalidOperationDisplayName()}}("{{string.Format(ExceptionMessages.ParameterHasNoMatchingConfig, type.Name, member.Name)}}");
|
throw new {{Identifier.InvalidOperationException}}("{{string.Format(ExceptionMessages.ParameterHasNoMatchingConfig, type.Name, member.Name)}}");
|
||||||
}
|
}
|
||||||
""");
|
""");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void EmitHelperMethods()
|
private void EmitHelperMethods()
|
||||||
{
|
{
|
||||||
|
// Emitted if we are to bind objects with complex members, or if we're emitting BindCoreMain or GetCore methods.
|
||||||
|
bool emitAsConfigWithChildren = ShouldEmitMethods(MethodsToGen_CoreBindingHelper.AsConfigWithChildren);
|
||||||
|
|
||||||
if (ShouldEmitMethods(MethodsToGen_CoreBindingHelper.BindCore))
|
if (ShouldEmitMethods(MethodsToGen_CoreBindingHelper.BindCore))
|
||||||
{
|
{
|
||||||
|
EmitBlankLineIfRequired();
|
||||||
EmitValidateConfigurationKeysMethod();
|
EmitValidateConfigurationKeysMethod();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ShouldEmitMethods(MethodsToGen_CoreBindingHelper.BindCoreUntyped | MethodsToGen_CoreBindingHelper.GetCore))
|
if (ShouldEmitMethods(MethodsToGen_CoreBindingHelper.BindCoreMain | MethodsToGen_CoreBindingHelper.GetCore))
|
||||||
{
|
{
|
||||||
_writer.WriteLine();
|
// HasValueOrChildren references this method.
|
||||||
|
Debug.Assert(emitAsConfigWithChildren);
|
||||||
|
EmitBlankLineIfRequired();
|
||||||
EmitHasValueOrChildrenMethod();
|
EmitHasValueOrChildrenMethod();
|
||||||
_writer.WriteLine();
|
|
||||||
EmitAsConfigWithChildrenMethod();
|
|
||||||
_emitBlankLineBeforeNextStatement = true;
|
|
||||||
}
|
|
||||||
else if (ShouldEmitMethods(MethodsToGen_CoreBindingHelper.AsConfigWithChildren))
|
|
||||||
{
|
|
||||||
_writer.WriteLine();
|
|
||||||
EmitAsConfigWithChildrenMethod();
|
|
||||||
_emitBlankLineBeforeNextStatement = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ShouldEmitMethods(
|
if (emitAsConfigWithChildren)
|
||||||
MethodsToGen_CoreBindingHelper.BindCoreUntyped | MethodsToGen_CoreBindingHelper.GetCore) ||
|
{
|
||||||
|
EmitBlankLineIfRequired();
|
||||||
|
EmitAsConfigWithChildrenMethod();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ShouldEmitMethods(MethodsToGen_CoreBindingHelper.BindCoreMain | MethodsToGen_CoreBindingHelper.GetCore) ||
|
||||||
ShouldEmitMethods(MethodsToGen_ConfigurationBinder.Bind_instance_BinderOptions))
|
ShouldEmitMethods(MethodsToGen_ConfigurationBinder.Bind_instance_BinderOptions))
|
||||||
{
|
{
|
||||||
_writer.WriteLine();
|
EmitBlankLineIfRequired();
|
||||||
EmitGetBinderOptionsHelper();
|
EmitGetBinderOptionsHelper();
|
||||||
_emitBlankLineBeforeNextStatement = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool enumTypeExists = false;
|
bool enumTypeExists = false;
|
||||||
|
@ -458,17 +442,17 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
|
||||||
EmitBlankLineIfRequired();
|
EmitBlankLineIfRequired();
|
||||||
_writer.WriteLine($$"""
|
_writer.WriteLine($$"""
|
||||||
/// <summary>If required by the binder options, validates that there are no unknown keys in the input configuration object.</summary>
|
/// <summary>If required by the binder options, validates that there are no unknown keys in the input configuration object.</summary>
|
||||||
public static void {{Identifier.ValidateConfigurationKeys}}(Type {{Identifier.type}}, {{MinimalDisplayString.LazyHashSetOfString}} {{keysIdentifier}}, {{Identifier.IConfiguration}} {{Identifier.configuration}}, {{Identifier.BinderOptions}}? {{Identifier.binderOptions}})
|
public static void {{Identifier.ValidateConfigurationKeys}}(Type {{Identifier.type}}, {{TypeDisplayString.LazyHashSetOfString}} {{keysIdentifier}}, {{Identifier.IConfiguration}} {{Identifier.configuration}}, {{Identifier.BinderOptions}}? {{Identifier.binderOptions}})
|
||||||
{
|
{
|
||||||
if ({{Identifier.binderOptions}}?.{{Identifier.ErrorOnUnknownConfiguration}} is true)
|
if ({{Identifier.binderOptions}}?.{{Identifier.ErrorOnUnknownConfiguration}} is true)
|
||||||
{
|
{
|
||||||
{{MinimalDisplayString.ListOfString}}? {{Identifier.temp}} = null;
|
{{TypeDisplayString.ListOfString}}? {{Identifier.temp}} = null;
|
||||||
|
|
||||||
foreach ({{Identifier.IConfigurationSection}} {{Identifier.section}} in {{Identifier.configuration}}.{{Identifier.GetChildren}}())
|
foreach ({{Identifier.IConfigurationSection}} {{Identifier.section}} in {{Identifier.configuration}}.{{Identifier.GetChildren}}())
|
||||||
{
|
{
|
||||||
if (!{{keysIdentifier}}.Value.Contains({{Expression.sectionKey}}))
|
if (!{{keysIdentifier}}.Value.Contains({{Expression.sectionKey}}))
|
||||||
{
|
{
|
||||||
({{Identifier.temp}} ??= new {{MinimalDisplayString.ListOfString}}()).Add($"'{{{Expression.sectionKey}}}'");
|
({{Identifier.temp}} ??= new {{TypeDisplayString.ListOfString}}()).Add($"'{{{Expression.sectionKey}}}'");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -490,7 +474,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return {{Identifier.AsConfigWithChildren}}({{Identifier.configuration}}) is not null;
|
return {{MethodsToGen_CoreBindingHelper.AsConfigWithChildren}}({{Identifier.configuration}}) is not null;
|
||||||
}
|
}
|
||||||
""");
|
""");
|
||||||
}
|
}
|
||||||
|
@ -498,7 +482,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
|
||||||
private void EmitAsConfigWithChildrenMethod()
|
private void EmitAsConfigWithChildrenMethod()
|
||||||
{
|
{
|
||||||
_writer.WriteLine($$"""
|
_writer.WriteLine($$"""
|
||||||
public static {{Identifier.IConfiguration}}? {{Identifier.AsConfigWithChildren}}({{Identifier.IConfiguration}} {{Identifier.configuration}})
|
public static {{Identifier.IConfiguration}}? {{MethodsToGen_CoreBindingHelper.AsConfigWithChildren}}({{Identifier.IConfiguration}} {{Identifier.configuration}})
|
||||||
{
|
{
|
||||||
foreach ({{Identifier.IConfigurationSection}} _ in {{Identifier.configuration}}.{{Identifier.GetChildren}}())
|
foreach ({{Identifier.IConfigurationSection}} _ in {{Identifier.configuration}}.{{Identifier.GetChildren}}())
|
||||||
{
|
{
|
||||||
|
@ -512,7 +496,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
|
||||||
private void EmitGetBinderOptionsHelper()
|
private void EmitGetBinderOptionsHelper()
|
||||||
{
|
{
|
||||||
_writer.WriteLine($$"""
|
_writer.WriteLine($$"""
|
||||||
public static {{Identifier.BinderOptions}}? {{Identifier.GetBinderOptions}}({{MinimalDisplayString.NullableActionOfBinderOptions}} {{Identifier.configureOptions}})
|
public static {{Identifier.BinderOptions}}? {{Identifier.GetBinderOptions}}({{TypeDisplayString.NullableActionOfBinderOptions}} {{Identifier.configureOptions}})
|
||||||
{
|
{
|
||||||
if ({{Identifier.configureOptions}} is null)
|
if ({{Identifier.configureOptions}} is null)
|
||||||
{
|
{
|
||||||
|
@ -524,7 +508,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
|
||||||
|
|
||||||
if ({{Identifier.binderOptions}}.BindNonPublicProperties)
|
if ({{Identifier.binderOptions}}.BindNonPublicProperties)
|
||||||
{
|
{
|
||||||
throw new global::System.NotSupportedException($"{{string.Format(ExceptionMessages.CannotSpecifyBindNonPublicProperties)}}");
|
throw new NotSupportedException($"{{string.Format(ExceptionMessages.CannotSpecifyBindNonPublicProperties)}}");
|
||||||
}
|
}
|
||||||
|
|
||||||
return {{Identifier.binderOptions}};
|
return {{Identifier.binderOptions}};
|
||||||
|
@ -534,7 +518,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
|
||||||
|
|
||||||
private void EmitEnumParseMethod()
|
private void EmitEnumParseMethod()
|
||||||
{
|
{
|
||||||
string innerExceptionTypeDisplayString = _useFullyQualifiedNames ? "global::System.Exception" : "Exception";
|
|
||||||
string exceptionArg1 = string.Format(ExceptionMessages.FailedBinding, $"{{{Identifier.getPath}()}}", $"{{typeof(T)}}");
|
string exceptionArg1 = string.Format(ExceptionMessages.FailedBinding, $"{{{Identifier.getPath}()}}", $"{{typeof(T)}}");
|
||||||
|
|
||||||
_writer.WriteLine($$"""
|
_writer.WriteLine($$"""
|
||||||
|
@ -548,9 +531,9 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
|
||||||
return Enum.Parse<T>(value, ignoreCase: true);
|
return Enum.Parse<T>(value, ignoreCase: true);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
catch ({{innerExceptionTypeDisplayString}} {{Identifier.exception}})
|
catch ({{Identifier.Exception}} {{Identifier.exception}})
|
||||||
{
|
{
|
||||||
throw new {{GetInvalidOperationDisplayName()}}($"{{exceptionArg1}}", {{Identifier.exception}});
|
throw new {{Identifier.InvalidOperationException}}($"{{exceptionArg1}}", {{Identifier.exception}});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
""");
|
""");
|
||||||
|
@ -558,29 +541,12 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
|
||||||
|
|
||||||
private void EmitPrimitiveParseMethod(ParsableFromStringSpec type)
|
private void EmitPrimitiveParseMethod(ParsableFromStringSpec type)
|
||||||
{
|
{
|
||||||
string innerExceptionTypeDisplayString;
|
|
||||||
string cultureInfoTypeDisplayString;
|
|
||||||
string numberStylesTypeDisplayString;
|
|
||||||
|
|
||||||
if (_useFullyQualifiedNames)
|
|
||||||
{
|
|
||||||
innerExceptionTypeDisplayString = "global::System.Exception";
|
|
||||||
cultureInfoTypeDisplayString = "global::System.Globalization.CultureInfo";
|
|
||||||
numberStylesTypeDisplayString = "global::System.Globalization.NumberStyles";
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
innerExceptionTypeDisplayString = "Exception";
|
|
||||||
cultureInfoTypeDisplayString = "CultureInfo";
|
|
||||||
numberStylesTypeDisplayString = "NumberStyles";
|
|
||||||
}
|
|
||||||
|
|
||||||
StringParsableTypeKind typeKind = type.StringParsableTypeKind;
|
StringParsableTypeKind typeKind = type.StringParsableTypeKind;
|
||||||
string typeDisplayString = type.MinimalDisplayString;
|
string typeDisplayString = type.DisplayString;
|
||||||
|
|
||||||
string invariantCultureExpression = $"{cultureInfoTypeDisplayString}.InvariantCulture";
|
|
||||||
|
|
||||||
|
string invariantCultureExpression = $"{Identifier.CultureInfo}.InvariantCulture";
|
||||||
string parsedValueExpr;
|
string parsedValueExpr;
|
||||||
|
|
||||||
switch (typeKind)
|
switch (typeKind)
|
||||||
{
|
{
|
||||||
case StringParsableTypeKind.Enum:
|
case StringParsableTypeKind.Enum:
|
||||||
|
@ -592,12 +558,12 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
|
||||||
break;
|
break;
|
||||||
case StringParsableTypeKind.Integer:
|
case StringParsableTypeKind.Integer:
|
||||||
{
|
{
|
||||||
parsedValueExpr = $"{typeDisplayString}.{Identifier.Parse}({Identifier.value}, {numberStylesTypeDisplayString}.Integer, {invariantCultureExpression})";
|
parsedValueExpr = $"{typeDisplayString}.{Identifier.Parse}({Identifier.value}, {Identifier.NumberStyles}.Integer, {invariantCultureExpression})";
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case StringParsableTypeKind.Float:
|
case StringParsableTypeKind.Float:
|
||||||
{
|
{
|
||||||
parsedValueExpr = $"{typeDisplayString}.{Identifier.Parse}({Identifier.value}, {numberStylesTypeDisplayString}.Float, {invariantCultureExpression})";
|
parsedValueExpr = $"{typeDisplayString}.{Identifier.Parse}({Identifier.value}, {Identifier.NumberStyles}.Float, {invariantCultureExpression})";
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case StringParsableTypeKind.Parse:
|
case StringParsableTypeKind.Parse:
|
||||||
|
@ -612,7 +578,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
|
||||||
break;
|
break;
|
||||||
case StringParsableTypeKind.CultureInfo:
|
case StringParsableTypeKind.CultureInfo:
|
||||||
{
|
{
|
||||||
parsedValueExpr = $"{cultureInfoTypeDisplayString}.GetCultureInfo({Identifier.value})";
|
parsedValueExpr = $"{Identifier.CultureInfo}.GetCultureInfo({Identifier.value})";
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case StringParsableTypeKind.Uri:
|
case StringParsableTypeKind.Uri:
|
||||||
|
@ -635,9 +601,9 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
|
||||||
{
|
{
|
||||||
return {{parsedValueExpr}};
|
return {{parsedValueExpr}};
|
||||||
}
|
}
|
||||||
catch ({{innerExceptionTypeDisplayString}} {{Identifier.exception}})
|
catch ({{Identifier.Exception}} {{Identifier.exception}})
|
||||||
{
|
{
|
||||||
throw new {{GetInvalidOperationDisplayName()}}($"{{exceptionArg1}}", {{Identifier.exception}});
|
throw new {{Identifier.InvalidOperationException}}($"{{exceptionArg1}}", {{Identifier.exception}});
|
||||||
}
|
}
|
||||||
""");
|
""");
|
||||||
}
|
}
|
||||||
|
@ -722,13 +688,13 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
|
||||||
if (keyType.StringParsableTypeKind is not StringParsableTypeKind.AssignFromSectionValue)
|
if (keyType.StringParsableTypeKind is not StringParsableTypeKind.AssignFromSectionValue)
|
||||||
{
|
{
|
||||||
// Save value to local to avoid parsing twice - during look-up and during add.
|
// Save value to local to avoid parsing twice - during look-up and during add.
|
||||||
_writer.WriteLine($"{keyType.MinimalDisplayString} {Identifier.key} = {parsedKeyExpr};");
|
_writer.WriteLine($"{keyType.DisplayString} {Identifier.key} = {parsedKeyExpr};");
|
||||||
parsedKeyExpr = Identifier.key;
|
parsedKeyExpr = Identifier.key;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isValueType = elementType.IsValueType;
|
bool isValueType = elementType.IsValueType;
|
||||||
string expressionForElementIsNotNull = $"{Identifier.element} is not null";
|
string expressionForElementIsNotNull = $"{Identifier.element} is not null";
|
||||||
string elementTypeDisplayString = elementType.MinimalDisplayString + (elementType.IsValueType ? string.Empty : "?");
|
string elementTypeDisplayString = elementType.DisplayString + (elementType.IsValueType ? string.Empty : "?");
|
||||||
|
|
||||||
string expressionForElementExists = $"{objIdentifier}.{Identifier.TryGetValue}({parsedKeyExpr}, out {elementTypeDisplayString} {Identifier.element})";
|
string expressionForElementExists = $"{objIdentifier}.{Identifier.TryGetValue}({parsedKeyExpr}, out {elementTypeDisplayString} {Identifier.element})";
|
||||||
string conditionToUseExistingElement = expressionForElementExists;
|
string conditionToUseExistingElement = expressionForElementExists;
|
||||||
|
@ -749,7 +715,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
|
||||||
// we need to copy its contents into a new instance & then append/bind to that.
|
// we need to copy its contents into a new instance & then append/bind to that.
|
||||||
|
|
||||||
string initExpression = collectionSpec.InitializationStrategy is InitializationStrategy.ParameterizedConstructor
|
string initExpression = collectionSpec.InitializationStrategy is InitializationStrategy.ParameterizedConstructor
|
||||||
? $"new {collectionSpec.ConcreteType.MinimalDisplayString}({Identifier.element})"
|
? $"new {collectionSpec.ConcreteType.DisplayString}({Identifier.element})"
|
||||||
: $"{Identifier.element}.{collectionSpec.ToEnumerableMethodCall!}";
|
: $"{Identifier.element}.{collectionSpec.ToEnumerableMethodCall!}";
|
||||||
|
|
||||||
_writer.WriteLine($$"""
|
_writer.WriteLine($$"""
|
||||||
|
@ -773,7 +739,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
|
||||||
Debug.Assert(type.NeedsMemberBinding);
|
Debug.Assert(type.NeedsMemberBinding);
|
||||||
|
|
||||||
string keyCacheFieldName = GetConfigKeyCacheFieldName(type);
|
string keyCacheFieldName = GetConfigKeyCacheFieldName(type);
|
||||||
string validateMethodCallExpr = $"{Identifier.ValidateConfigurationKeys}(typeof({type.MinimalDisplayString}), {keyCacheFieldName}, {Identifier.configuration}, {Identifier.binderOptions});";
|
string validateMethodCallExpr = $"{Identifier.ValidateConfigurationKeys}(typeof({type.DisplayString}), {keyCacheFieldName}, {Identifier.configuration}, {Identifier.binderOptions});";
|
||||||
_writer.WriteLine(validateMethodCallExpr);
|
_writer.WriteLine(validateMethodCallExpr);
|
||||||
|
|
||||||
foreach (PropertySpec property in type.Properties.Values)
|
foreach (PropertySpec property in type.Properties.Values)
|
||||||
|
@ -781,7 +747,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
|
||||||
bool noSetter_And_IsReadonly = !property.CanSet && property.Type is CollectionSpec { InitializationStrategy: InitializationStrategy.ParameterizedConstructor };
|
bool noSetter_And_IsReadonly = !property.CanSet && property.Type is CollectionSpec { InitializationStrategy: InitializationStrategy.ParameterizedConstructor };
|
||||||
if (property.ShouldBind() && !noSetter_And_IsReadonly)
|
if (property.ShouldBind() && !noSetter_And_IsReadonly)
|
||||||
{
|
{
|
||||||
string containingTypeRef = property.IsStatic ? type.MinimalDisplayString : Identifier.obj;
|
string containingTypeRef = property.IsStatic ? type.DisplayString : Identifier.obj;
|
||||||
EmitBindImplForMember(
|
EmitBindImplForMember(
|
||||||
property,
|
property,
|
||||||
memberAccessExpr: $"{containingTypeRef}.{property.Name}",
|
memberAccessExpr: $"{containingTypeRef}.{property.Name}",
|
||||||
|
@ -832,7 +798,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
string sectionValidationCall = $"{Identifier.AsConfigWithChildren}({sectionParseExpr})";
|
string sectionValidationCall = $"{MethodsToGen_CoreBindingHelper.AsConfigWithChildren}({sectionParseExpr})";
|
||||||
string sectionIdentifier = GetIncrementalIdentifier(Identifier.section);
|
string sectionIdentifier = GetIncrementalIdentifier(Identifier.section);
|
||||||
|
|
||||||
EmitStartBlock($"if ({sectionValidationCall} is {Identifier.IConfigurationSection} {sectionIdentifier})");
|
EmitStartBlock($"if ({sectionValidationCall} is {Identifier.IConfigurationSection} {sectionIdentifier})");
|
||||||
|
@ -869,14 +835,14 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
|
||||||
}
|
}
|
||||||
|
|
||||||
Debug.Assert(canSet);
|
Debug.Assert(canSet);
|
||||||
string effectiveMemberTypeDisplayString = effectiveMemberType.MinimalDisplayString;
|
string effectiveMemberTypeDisplayString = effectiveMemberType.DisplayString;
|
||||||
initKind = InitializationKind.None;
|
initKind = InitializationKind.None;
|
||||||
|
|
||||||
if (memberType.SpecKind is TypeSpecKind.Nullable)
|
if (memberType.SpecKind is TypeSpecKind.Nullable)
|
||||||
{
|
{
|
||||||
string nullableTempIdentifier = GetIncrementalIdentifier(Identifier.temp);
|
string nullableTempIdentifier = GetIncrementalIdentifier(Identifier.temp);
|
||||||
|
|
||||||
_writer.WriteLine($"{memberType.MinimalDisplayString} {nullableTempIdentifier} = {memberAccessExpr};");
|
_writer.WriteLine($"{memberType.DisplayString} {nullableTempIdentifier} = {memberAccessExpr};");
|
||||||
|
|
||||||
_writer.WriteLine(
|
_writer.WriteLine(
|
||||||
$"{effectiveMemberTypeDisplayString} {tempIdentifier} = {nullableTempIdentifier}.{Identifier.HasValue} ? {nullableTempIdentifier}.{Identifier.Value} : new {effectiveMemberTypeDisplayString}();");
|
$"{effectiveMemberTypeDisplayString} {tempIdentifier} = {nullableTempIdentifier}.{Identifier.HasValue} ? {nullableTempIdentifier}.{Identifier.Value} : new {effectiveMemberTypeDisplayString}();");
|
||||||
|
@ -924,7 +890,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
|
||||||
{
|
{
|
||||||
objIdentifier = Identifier.temp;
|
objIdentifier = Identifier.temp;
|
||||||
_writer.WriteLine($$"""
|
_writer.WriteLine($$"""
|
||||||
if ({{Identifier.obj}} is not {{type.PopulationCastType!.MinimalDisplayString}} {{objIdentifier}})
|
if ({{Identifier.obj}} is not {{type.PopulationCastType!.DisplayString}} {{objIdentifier}})
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -936,20 +902,31 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
|
||||||
private void Emit_Foreach_Section_In_ConfigChildren_StartBlock() =>
|
private void Emit_Foreach_Section_In_ConfigChildren_StartBlock() =>
|
||||||
EmitStartBlock($"foreach ({Identifier.IConfigurationSection} {Identifier.section} in {Identifier.configuration}.{Identifier.GetChildren}())");
|
EmitStartBlock($"foreach ({Identifier.IConfigurationSection} {Identifier.section} in {Identifier.configuration}.{Identifier.GetChildren}())");
|
||||||
|
|
||||||
|
private void Emit_NotSupportedException_TypeNotDetectedAsInput() =>
|
||||||
|
_writer.WriteLine(@$"throw new NotSupportedException($""{string.Format(ExceptionMessages.TypeNotDetectedAsInput, "{type}")}"");");
|
||||||
|
|
||||||
private static string GetSectionPathFromConfigurationExpression(string configurationKeyName)
|
private static string GetSectionPathFromConfigurationExpression(string configurationKeyName)
|
||||||
=> $@"{GetSectionFromConfigurationExpression(configurationKeyName)}.{Identifier.Path}";
|
=> $@"{GetSectionFromConfigurationExpression(configurationKeyName)}.{Identifier.Path}";
|
||||||
|
|
||||||
private static string GetSectionFromConfigurationExpression(string configurationKeyName, bool addQuotes = true)
|
private static string GetSectionFromConfigurationExpression(string configurationKeyName, bool addQuotes = true)
|
||||||
{
|
{
|
||||||
string argExpr = addQuotes ? $@"""{configurationKeyName}""" : configurationKeyName;
|
string argExpr = addQuotes ? $@"""{configurationKeyName}""" : configurationKeyName;
|
||||||
return $@"{Expression.configurationGetSection}({argExpr})";
|
return $@"{Identifier.configuration}.{Identifier.GetSection}({argExpr})";
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string GetConditionKindExpr(ref bool isFirstType)
|
||||||
|
{
|
||||||
|
if (isFirstType)
|
||||||
|
{
|
||||||
|
isFirstType = false;
|
||||||
|
return "if";
|
||||||
|
}
|
||||||
|
|
||||||
|
return "else if";
|
||||||
}
|
}
|
||||||
|
|
||||||
private static string GetConfigKeyCacheFieldName(ObjectSpec type) =>
|
private static string GetConfigKeyCacheFieldName(ObjectSpec type) =>
|
||||||
$"s_configKeys_{type.DisplayStringWithoutSpecialCharacters}";
|
$"s_configKeys_{type.DisplayString.ToIdentifierSubstring()}";
|
||||||
|
|
||||||
private void Emit_NotSupportedException_TypeNotDetectedAsInput() =>
|
|
||||||
_writer.WriteLine(@$"throw new global::System.NotSupportedException($""{string.Format(ExceptionMessages.TypeNotDetectedAsInput, "{type}")}"");");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,6 +1,8 @@
|
||||||
// Licensed to the .NET Foundation under one or more agreements.
|
// Licensed to the .NET Foundation under one or more agreements.
|
||||||
// The .NET Foundation licenses this file to you under the MIT license.
|
// The .NET Foundation licenses this file to you under the MIT license.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
|
|
||||||
|
@ -10,7 +12,9 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
|
||||||
{
|
{
|
||||||
private sealed partial class Emitter
|
private sealed partial class Emitter
|
||||||
{
|
{
|
||||||
private static readonly AssemblyName s_assemblyName = typeof(Emitter).Assembly.GetName();
|
private string? _emittedExtsTargetType;
|
||||||
|
|
||||||
|
internal static readonly AssemblyName s_assemblyName = typeof(ConfigurationBindingGenerator).Assembly.GetName();
|
||||||
|
|
||||||
private enum InitializationKind
|
private enum InitializationKind
|
||||||
{
|
{
|
||||||
|
@ -26,29 +30,13 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
|
||||||
public const string sectionPath = "section.Path";
|
public const string sectionPath = "section.Path";
|
||||||
public const string sectionValue = "section.Value";
|
public const string sectionValue = "section.Value";
|
||||||
|
|
||||||
public const string GetBinderOptions = $"{FullyQualifiedDisplayString.CoreBindingHelper}.{Identifier.GetBinderOptions}";
|
public static string GeneratedCodeAnnotation = $@"[GeneratedCode(""{s_assemblyName.Name}"", ""{s_assemblyName.Version}"")]";
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class FullyQualifiedDisplayString
|
private static class TypeDisplayString
|
||||||
{
|
|
||||||
public const string ActionOfBinderOptions = $"global::System.Action<global::Microsoft.Extensions.Configuration.BinderOptions>";
|
|
||||||
public const string AddSingleton = $"{ServiceCollectionServiceExtensions}.AddSingleton";
|
|
||||||
public const string ConfigurationChangeTokenSource = "global::Microsoft.Extensions.Options.ConfigurationChangeTokenSource";
|
|
||||||
public const string CoreBindingHelper = $"global::{ProjectName}.{Identifier.CoreBindingHelper}";
|
|
||||||
public const string IConfiguration = "global::Microsoft.Extensions.Configuration.IConfiguration";
|
|
||||||
public const string IConfigurationSection = IConfiguration + "Section";
|
|
||||||
public const string IOptionsChangeTokenSource = "global::Microsoft.Extensions.Options.IOptionsChangeTokenSource";
|
|
||||||
public const string InvalidOperationException = "global::System.InvalidOperationException";
|
|
||||||
public const string IServiceCollection = "global::Microsoft.Extensions.DependencyInjection.IServiceCollection";
|
|
||||||
public const string NotSupportedException = "global::System.NotSupportedException";
|
|
||||||
public const string OptionsBuilderOfTOptions = $"global::Microsoft.Extensions.Options.OptionsBuilder<{Identifier.TOptions}>";
|
|
||||||
public const string ServiceCollectionServiceExtensions = "global::Microsoft.Extensions.DependencyInjection.ServiceCollectionServiceExtensions";
|
|
||||||
public const string Type = $"global::System.Type";
|
|
||||||
}
|
|
||||||
|
|
||||||
private static class MinimalDisplayString
|
|
||||||
{
|
{
|
||||||
public const string NullableActionOfBinderOptions = "Action<BinderOptions>?";
|
public const string NullableActionOfBinderOptions = "Action<BinderOptions>?";
|
||||||
|
public const string OptionsBuilderOfTOptions = $"OptionsBuilder<{Identifier.TOptions}>";
|
||||||
public const string HashSetOfString = "HashSet<string>";
|
public const string HashSetOfString = "HashSet<string>";
|
||||||
public const string LazyHashSetOfString = "Lazy<HashSet<string>>";
|
public const string LazyHashSetOfString = "Lazy<HashSet<string>>";
|
||||||
public const string ListOfString = "List<string>";
|
public const string ListOfString = "List<string>";
|
||||||
|
@ -75,6 +63,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
|
||||||
public const string services = nameof(services);
|
public const string services = nameof(services);
|
||||||
public const string temp = nameof(temp);
|
public const string temp = nameof(temp);
|
||||||
public const string type = nameof(type);
|
public const string type = nameof(type);
|
||||||
|
public const string typedObj = nameof(typedObj);
|
||||||
public const string validateKeys = nameof(validateKeys);
|
public const string validateKeys = nameof(validateKeys);
|
||||||
public const string value = nameof(value);
|
public const string value = nameof(value);
|
||||||
|
|
||||||
|
@ -82,21 +71,19 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
|
||||||
public const string AddSingleton = nameof(AddSingleton);
|
public const string AddSingleton = nameof(AddSingleton);
|
||||||
public const string Any = nameof(Any);
|
public const string Any = nameof(Any);
|
||||||
public const string Array = nameof(Array);
|
public const string Array = nameof(Array);
|
||||||
public const string AsConfigWithChildren = nameof(AsConfigWithChildren);
|
|
||||||
public const string Bind = nameof(Bind);
|
public const string Bind = nameof(Bind);
|
||||||
public const string BinderOptions = nameof(BinderOptions);
|
public const string BinderOptions = nameof(BinderOptions);
|
||||||
|
public const string BindingExtensions = nameof(BindingExtensions);
|
||||||
|
public const string ConfigurationChangeTokenSource = nameof(ConfigurationChangeTokenSource);
|
||||||
public const string Configure = nameof(Configure);
|
public const string Configure = nameof(Configure);
|
||||||
public const string CopyTo = nameof(CopyTo);
|
public const string CopyTo = nameof(CopyTo);
|
||||||
public const string ContainsKey = nameof(ContainsKey);
|
public const string ContainsKey = nameof(ContainsKey);
|
||||||
public const string CoreBindingHelper = nameof(CoreBindingHelper);
|
|
||||||
public const string Count = nameof(Count);
|
public const string Count = nameof(Count);
|
||||||
public const string CultureInfo = nameof(CultureInfo);
|
public const string CultureInfo = nameof(CultureInfo);
|
||||||
public const string CultureNotFoundException = nameof(CultureNotFoundException);
|
public const string CultureNotFoundException = nameof(CultureNotFoundException);
|
||||||
public const string Enum = nameof(Enum);
|
public const string Enum = nameof(Enum);
|
||||||
public const string ErrorOnUnknownConfiguration = nameof(ErrorOnUnknownConfiguration);
|
public const string ErrorOnUnknownConfiguration = nameof(ErrorOnUnknownConfiguration);
|
||||||
public const string GeneratedConfigurationBinder = nameof(GeneratedConfigurationBinder);
|
public const string Exception = nameof(Exception);
|
||||||
public const string GeneratedOptionsBuilderBinder = nameof(GeneratedOptionsBuilderBinder);
|
|
||||||
public const string GeneratedServiceCollectionBinder = nameof(GeneratedServiceCollectionBinder);
|
|
||||||
public const string Get = nameof(Get);
|
public const string Get = nameof(Get);
|
||||||
public const string GetBinderOptions = nameof(GetBinderOptions);
|
public const string GetBinderOptions = nameof(GetBinderOptions);
|
||||||
public const string GetChildren = nameof(GetChildren);
|
public const string GetChildren = nameof(GetChildren);
|
||||||
|
@ -108,9 +95,13 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
|
||||||
public const string IConfiguration = nameof(IConfiguration);
|
public const string IConfiguration = nameof(IConfiguration);
|
||||||
public const string IConfigurationSection = nameof(IConfigurationSection);
|
public const string IConfigurationSection = nameof(IConfigurationSection);
|
||||||
public const string Int32 = "int";
|
public const string Int32 = "int";
|
||||||
|
public const string InterceptsLocation = nameof(InterceptsLocation);
|
||||||
public const string InvalidOperationException = nameof(InvalidOperationException);
|
public const string InvalidOperationException = nameof(InvalidOperationException);
|
||||||
public const string InvariantCulture = nameof(InvariantCulture);
|
public const string InvariantCulture = nameof(InvariantCulture);
|
||||||
|
public const string IOptionsChangeTokenSource = nameof(IOptionsChangeTokenSource);
|
||||||
|
public const string IServiceCollection = nameof(IServiceCollection);
|
||||||
public const string Length = nameof(Length);
|
public const string Length = nameof(Length);
|
||||||
|
public const string NumberStyles = nameof(NumberStyles);
|
||||||
public const string Parse = nameof(Parse);
|
public const string Parse = nameof(Parse);
|
||||||
public const string Path = nameof(Path);
|
public const string Path = nameof(Path);
|
||||||
public const string Resize = nameof(Resize);
|
public const string Resize = nameof(Resize);
|
||||||
|
@ -118,17 +109,66 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
|
||||||
public const string TOptions = nameof(TOptions);
|
public const string TOptions = nameof(TOptions);
|
||||||
public const string TryCreate = nameof(TryCreate);
|
public const string TryCreate = nameof(TryCreate);
|
||||||
public const string TryGetValue = nameof(TryGetValue);
|
public const string TryGetValue = nameof(TryGetValue);
|
||||||
public const string TryParse = nameof(TryParse);
|
public const string Type = nameof(Type);
|
||||||
public const string Uri = nameof(Uri);
|
public const string Uri = nameof(Uri);
|
||||||
public const string ValidateConfigurationKeys = nameof(ValidateConfigurationKeys);
|
public const string ValidateConfigurationKeys = nameof(ValidateConfigurationKeys);
|
||||||
public const string Value = nameof(Value);
|
public const string Value = nameof(Value);
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool ShouldEmitBinders() =>
|
private bool ShouldEmitBindingExtensions() =>
|
||||||
ShouldEmitMethods(MethodsToGen_ConfigurationBinder.Any) ||
|
ShouldEmitMethods(MethodsToGen_ConfigurationBinder.Any) ||
|
||||||
ShouldEmitMethods(MethodsToGen_Extensions_OptionsBuilder.Any) ||
|
ShouldEmitMethods(MethodsToGen_Extensions_OptionsBuilder.Any) ||
|
||||||
ShouldEmitMethods(MethodsToGen_Extensions_ServiceCollection.Any);
|
ShouldEmitMethods(MethodsToGen_Extensions_ServiceCollection.Any);
|
||||||
|
|
||||||
|
private void EmitInterceptsLocationAnnotations(Enum generatedBindingOverload)
|
||||||
|
{
|
||||||
|
// The only time a generated binding method won't have any locations to
|
||||||
|
// intercept is when either of these methods are used as helpers for
|
||||||
|
// other generated OptionsBuilder or ServiceCollection binding extensions.
|
||||||
|
bool interceptsCalls = _sourceGenSpec.InterceptionInfo.TryGetValue(generatedBindingOverload, out List<InterceptorLocationInfo>? infoList);
|
||||||
|
Debug.Assert(interceptsCalls ||
|
||||||
|
generatedBindingOverload is MethodsToGen_Extensions_ServiceCollection.Configure_T_name_BinderOptions ||
|
||||||
|
generatedBindingOverload is MethodsToGen_Extensions_OptionsBuilder.Bind_T_BinderOptions);
|
||||||
|
|
||||||
|
if (interceptsCalls)
|
||||||
|
{
|
||||||
|
EmitInterceptsLocationAnnotations(infoList);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void EmitInterceptsLocationAnnotations(List<InterceptorLocationInfo> infoList)
|
||||||
|
{
|
||||||
|
foreach (InterceptorLocationInfo info in infoList)
|
||||||
|
{
|
||||||
|
_writer.WriteLine($@"[{Identifier.InterceptsLocation}Attribute(@""{info.FilePath}"", {info.LineNumber}, {info.CharacterNumber})]");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void EmitBindingExtStartRegion(string targetType)
|
||||||
|
{
|
||||||
|
Debug.Assert(_emittedExtsTargetType is null);
|
||||||
|
|
||||||
|
EmitBlankLineIfRequired();
|
||||||
|
_emittedExtsTargetType = targetType;
|
||||||
|
EmitBindingExtRegionText(isStart: true);
|
||||||
|
_emitBlankLineBeforeNextStatement = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void EmitBindingExtEndRegion()
|
||||||
|
{
|
||||||
|
Debug.Assert(_emittedExtsTargetType is not null);
|
||||||
|
|
||||||
|
EmitBindingExtRegionText(isStart: false);
|
||||||
|
_emittedExtsTargetType = null;
|
||||||
|
_emitBlankLineBeforeNextStatement = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void EmitBindingExtRegionText(bool isStart)
|
||||||
|
{
|
||||||
|
string endSource = isStart ? string.Empty : "end";
|
||||||
|
_writer.WriteLine($"#{endSource}region {_emittedExtsTargetType} extensions.");
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Starts a block of source code.
|
/// Starts a block of source code.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -171,24 +211,12 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
|
||||||
_emitBlankLineBeforeNextStatement = true;
|
_emitBlankLineBeforeNextStatement = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void EmitCheckForNullArgument_WithBlankLine_IfRequired(bool isValueType)
|
|
||||||
{
|
|
||||||
if (!isValueType)
|
|
||||||
{
|
|
||||||
EmitCheckForNullArgument_WithBlankLine(Identifier.obj);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void EmitCheckForNullArgument_WithBlankLine(string paramName)
|
private void EmitCheckForNullArgument_WithBlankLine(string paramName)
|
||||||
{
|
{
|
||||||
string exceptionTypeDisplayString = _useFullyQualifiedNames
|
|
||||||
? "global::System.ArgumentNullException"
|
|
||||||
: "ArgumentNullException";
|
|
||||||
|
|
||||||
_writer.WriteLine($$"""
|
_writer.WriteLine($$"""
|
||||||
if ({{paramName}} is null)
|
if ({{paramName}} is null)
|
||||||
{
|
{
|
||||||
throw new {{exceptionTypeDisplayString}}(nameof({{paramName}}));
|
throw new ArgumentNullException(nameof({{paramName}}));
|
||||||
}
|
}
|
||||||
""");
|
""");
|
||||||
|
|
||||||
|
@ -201,51 +229,28 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
|
||||||
|
|
||||||
if (!type.CanInitialize)
|
if (!type.CanInitialize)
|
||||||
{
|
{
|
||||||
_writer.WriteLine(GetInitException(type.InitExceptionMessage) + ";");
|
_writer.WriteLine($@"throw new {Identifier.InvalidOperationException}(""{type.InitExceptionMessage}"");");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void EmitRootBindingClassStartBlock(string className)
|
|
||||||
{
|
|
||||||
EmitBlankLineIfRequired();
|
|
||||||
EmitStartBlock($$"""
|
|
||||||
/// <summary>Generated helper providing an AOT and linking compatible implementation for configuration binding.</summary>
|
|
||||||
{{GetGeneratedCodeAttributeSrc()}}
|
|
||||||
internal static class {{className}}
|
|
||||||
""");
|
|
||||||
|
|
||||||
_emitBlankLineBeforeNextStatement = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
private string GetGeneratedCodeAttributeSrc()
|
|
||||||
{
|
|
||||||
string attributeRefExpr = _useFullyQualifiedNames ? $"global::System.CodeDom.Compiler.GeneratedCodeAttribute" : "GeneratedCode";
|
|
||||||
return $@"[{attributeRefExpr}(""{s_assemblyName.Name}"", ""{s_assemblyName.Version}"")]";
|
|
||||||
}
|
|
||||||
|
|
||||||
private string GetInitException(string message) => $@"throw new {GetInvalidOperationDisplayName()}(""{message}"")";
|
|
||||||
|
|
||||||
private string GetIncrementalIdentifier(string prefix) => $"{prefix}{_valueSuffixIndex++}";
|
private string GetIncrementalIdentifier(string prefix) => $"{prefix}{_valueSuffixIndex++}";
|
||||||
|
|
||||||
private string GetInitalizeMethodDisplayString(ObjectSpec type) =>
|
private static string GetInitalizeMethodDisplayString(ObjectSpec type) =>
|
||||||
GetHelperMethodDisplayString($"{nameof(MethodsToGen_CoreBindingHelper.Initialize)}{type.DisplayStringWithoutSpecialCharacters}");
|
$"{nameof(MethodsToGen_CoreBindingHelper.Initialize)}{type.DisplayString.ToIdentifierSubstring()}";
|
||||||
|
|
||||||
private string GetTypeDisplayString(TypeSpec type) => _useFullyQualifiedNames ? type.FullyQualifiedDisplayString : type.MinimalDisplayString;
|
|
||||||
|
|
||||||
private string GetHelperMethodDisplayString(string methodName)
|
|
||||||
{
|
|
||||||
if (_useFullyQualifiedNames)
|
|
||||||
{
|
|
||||||
methodName = FullyQualifiedDisplayString.CoreBindingHelper + "." + methodName;
|
|
||||||
}
|
|
||||||
|
|
||||||
return methodName;
|
|
||||||
}
|
|
||||||
|
|
||||||
private string GetInvalidOperationDisplayName() => _useFullyQualifiedNames ? FullyQualifiedDisplayString.InvalidOperationException : Identifier.InvalidOperationException;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal static class EmitterExtensions
|
||||||
|
{
|
||||||
|
public static string ToIdentifierSubstring(this string typeDisplayName) =>
|
||||||
|
typeDisplayName
|
||||||
|
.Replace("[]", nameof(Array))
|
||||||
|
.Replace(", ", string.Empty)
|
||||||
|
.Replace(".", string.Empty)
|
||||||
|
.Replace("<", string.Empty)
|
||||||
|
.Replace(">", string.Empty);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,19 +9,17 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
|
||||||
{
|
{
|
||||||
private bool ShouldEmitMethods(MethodsToGen_Extensions_OptionsBuilder methods) => (_sourceGenSpec.MethodsToGen_OptionsBuilderExt & methods) != 0;
|
private bool ShouldEmitMethods(MethodsToGen_Extensions_OptionsBuilder methods) => (_sourceGenSpec.MethodsToGen_OptionsBuilderExt & methods) != 0;
|
||||||
|
|
||||||
private void EmitBinder_Extensions_OptionsBuilder()
|
private void EmitBindingExtensions_OptionsBuilder()
|
||||||
{
|
{
|
||||||
if (!ShouldEmitMethods(MethodsToGen_Extensions_OptionsBuilder.Any))
|
if (!ShouldEmitMethods(MethodsToGen_Extensions_OptionsBuilder.Any))
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
EmitRootBindingClassStartBlock(Identifier.GeneratedOptionsBuilderBinder);
|
EmitBindingExtStartRegion(TypeDisplayString.OptionsBuilderOfTOptions);
|
||||||
|
|
||||||
EmitBindMethods_Extensions_OptionsBuilder();
|
EmitBindMethods_Extensions_OptionsBuilder();
|
||||||
EmitBindConfigurationMethod();
|
EmitBindConfigurationMethod();
|
||||||
|
EmitBindingExtEndRegion();
|
||||||
EmitEndBlock();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void EmitBindMethods_Extensions_OptionsBuilder()
|
private void EmitBindMethods_Extensions_OptionsBuilder()
|
||||||
|
@ -32,24 +30,25 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
|
||||||
}
|
}
|
||||||
|
|
||||||
const string documentation = @"/// <summary>Registers a configuration instance which <typeparamref name=""TOptions""/> will bind against.</summary>";
|
const string documentation = @"/// <summary>Registers a configuration instance which <typeparamref name=""TOptions""/> will bind against.</summary>";
|
||||||
const string paramList = $"{FullyQualifiedDisplayString.IConfiguration} {Identifier.configuration}";
|
const string paramList = $"{Identifier.IConfiguration} {Identifier.configuration}";
|
||||||
|
|
||||||
if (ShouldEmitMethods(MethodsToGen_Extensions_OptionsBuilder.Bind_T))
|
if (ShouldEmitMethods(MethodsToGen_Extensions_OptionsBuilder.Bind_T))
|
||||||
{
|
{
|
||||||
EmitMethodStartBlock("Bind", paramList, documentation);
|
EmitMethodStartBlock(MethodsToGen_Extensions_OptionsBuilder.Bind_T, "Bind", paramList, documentation);
|
||||||
_writer.WriteLine($"return global::{Identifier.GeneratedOptionsBuilderBinder}.Bind({Identifier.optionsBuilder}, {Identifier.configuration}, {Identifier.configureOptions}: null);");
|
_writer.WriteLine($"return Bind({Identifier.optionsBuilder}, {Identifier.configuration}, {Identifier.configureOptions}: null);");
|
||||||
EmitEndBlock();
|
EmitEndBlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
EmitMethodStartBlock(
|
EmitMethodStartBlock(
|
||||||
|
MethodsToGen_Extensions_OptionsBuilder.Bind_T_BinderOptions,
|
||||||
"Bind",
|
"Bind",
|
||||||
paramList + $", {FullyQualifiedDisplayString.ActionOfBinderOptions}? {Identifier.configureOptions}",
|
paramList + $", {TypeDisplayString.NullableActionOfBinderOptions} {Identifier.configureOptions}",
|
||||||
documentation);
|
documentation);
|
||||||
|
|
||||||
EmitCheckForNullArgument_WithBlankLine(Identifier.optionsBuilder);
|
EmitCheckForNullArgument_WithBlankLine(Identifier.optionsBuilder);
|
||||||
|
|
||||||
_writer.WriteLine($$"""
|
_writer.WriteLine($$"""
|
||||||
global::{{Identifier.GeneratedServiceCollectionBinder}}.{{Identifier.Configure}}<{{Identifier.TOptions}}>({{Identifier.optionsBuilder}}.{{Identifier.Services}}, {{Identifier.optionsBuilder}}.Name, {{Identifier.configuration}}, {{Identifier.configureOptions}});
|
{{Identifier.Configure}}<{{Identifier.TOptions}}>({{Identifier.optionsBuilder}}.{{Identifier.Services}}, {{Identifier.optionsBuilder}}.Name, {{Identifier.configuration}}, {{Identifier.configureOptions}});
|
||||||
return {{Identifier.optionsBuilder}};
|
return {{Identifier.optionsBuilder}};
|
||||||
""");
|
""");
|
||||||
|
|
||||||
|
@ -63,19 +62,20 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const string documentation = $@"/// <summary>Registers the dependency injection container to bind <typeparamref name=""TOptions""/> against the <see cref=""{FullyQualifiedDisplayString.IConfiguration}""/> obtained from the DI service provider.</summary>";
|
const string documentation = $@"/// <summary>Registers the dependency injection container to bind <typeparamref name=""TOptions""/> against the <see cref=""{Identifier.IConfiguration}""/> obtained from the DI service provider.</summary>";
|
||||||
string paramList = $"string {Identifier.configSectionPath}, {FullyQualifiedDisplayString.ActionOfBinderOptions}? {Identifier.configureOptions} = null";
|
string paramList = $"string {Identifier.configSectionPath}, {TypeDisplayString.NullableActionOfBinderOptions} {Identifier.configureOptions} = null";
|
||||||
|
|
||||||
EmitMethodStartBlock("BindConfiguration", paramList, documentation);
|
EmitMethodStartBlock(MethodsToGen_Extensions_OptionsBuilder.BindConfiguration, "BindConfiguration", paramList, documentation);
|
||||||
|
|
||||||
EmitCheckForNullArgument_WithBlankLine(Identifier.optionsBuilder);
|
EmitCheckForNullArgument_WithBlankLine(Identifier.optionsBuilder);
|
||||||
EmitCheckForNullArgument_WithBlankLine(Identifier.configSectionPath);
|
EmitCheckForNullArgument_WithBlankLine(Identifier.configSectionPath);
|
||||||
|
|
||||||
EmitStartBlock($"{Identifier.optionsBuilder}.{Identifier.Configure}<{FullyQualifiedDisplayString.IConfiguration}>(({Identifier.obj}, {Identifier.configuration}) =>");
|
EmitStartBlock($"{Identifier.optionsBuilder}.{Identifier.Configure}<{Identifier.IConfiguration}>(({Identifier.obj}, {Identifier.configuration}) =>");
|
||||||
|
EmitCheckForNullArgument_WithBlankLine(Identifier.obj);
|
||||||
|
EmitCheckForNullArgument_WithBlankLine(Identifier.configuration);
|
||||||
_writer.WriteLine($$"""
|
_writer.WriteLine($$"""
|
||||||
{{FullyQualifiedDisplayString.IConfiguration}} {{Identifier.section}} = string.Equals(string.Empty, {{Identifier.configSectionPath}}, global::System.StringComparison.OrdinalIgnoreCase) ? {{Identifier.configuration}} : {{Identifier.configuration}}.{{Identifier.GetSection}}({{Identifier.configSectionPath}});
|
{{Identifier.IConfiguration}} {{Identifier.section}} = string.Equals(string.Empty, {{Identifier.configSectionPath}}, StringComparison.OrdinalIgnoreCase) ? {{Identifier.configuration}} : {{Identifier.configuration}}.{{Identifier.GetSection}}({{Identifier.configSectionPath}});
|
||||||
{{FullyQualifiedDisplayString.CoreBindingHelper}}.{{nameof(MethodsToGen_CoreBindingHelper.BindCoreUntyped)}}({{Identifier.section}}, {{Identifier.obj}}, typeof({{Identifier.TOptions}}), {{Identifier.configureOptions}});
|
{{nameof(MethodsToGen_CoreBindingHelper.BindCoreMain)}}({{Identifier.section}}, {{Identifier.obj}}, typeof({{Identifier.TOptions}}), {{Identifier.configureOptions}});
|
||||||
""");
|
""");
|
||||||
|
|
||||||
EmitEndBlock(endBraceTrailingSource: ");");
|
EmitEndBlock(endBraceTrailingSource: ");");
|
||||||
|
@ -83,20 +83,20 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
|
||||||
_writer.WriteLine();
|
_writer.WriteLine();
|
||||||
|
|
||||||
_writer.WriteLine($$"""
|
_writer.WriteLine($$"""
|
||||||
{{FullyQualifiedDisplayString.AddSingleton}}<{{FullyQualifiedDisplayString.IOptionsChangeTokenSource}}<{{Identifier.TOptions}}>, {{FullyQualifiedDisplayString.ConfigurationChangeTokenSource}}<{{Identifier.TOptions}}>>({{Identifier.optionsBuilder}}.{{Identifier.Services}});
|
{{Identifier.optionsBuilder}}.{{Identifier.Services}}.{{Identifier.AddSingleton}}<{{Identifier.IOptionsChangeTokenSource}}<{{Identifier.TOptions}}>, {{Identifier.ConfigurationChangeTokenSource}}<{{Identifier.TOptions}}>>();
|
||||||
return {{Identifier.optionsBuilder}};
|
return {{Identifier.optionsBuilder}};
|
||||||
""");
|
""");
|
||||||
|
|
||||||
EmitEndBlock();
|
EmitEndBlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void EmitMethodStartBlock(string methodName, string paramList, string documentation)
|
private void EmitMethodStartBlock(MethodsToGen_Extensions_OptionsBuilder method, string methodName, string paramList, string documentation)
|
||||||
{
|
{
|
||||||
paramList = $"this {FullyQualifiedDisplayString.OptionsBuilderOfTOptions} {Identifier.optionsBuilder}, {paramList}";
|
paramList = $"this {TypeDisplayString.OptionsBuilderOfTOptions} {Identifier.optionsBuilder}, {paramList}";
|
||||||
|
|
||||||
EmitBlankLineIfRequired();
|
EmitBlankLineIfRequired();
|
||||||
_writer.WriteLine(documentation);
|
_writer.WriteLine(documentation);
|
||||||
EmitStartBlock($"public static {FullyQualifiedDisplayString.OptionsBuilderOfTOptions} {methodName}<{Identifier.TOptions}>({paramList}) where {Identifier.TOptions} : class");
|
EmitInterceptsLocationAnnotations(method);
|
||||||
|
EmitStartBlock($"public static {TypeDisplayString.OptionsBuilderOfTOptions} {methodName}<{Identifier.TOptions}>({paramList}) where {Identifier.TOptions} : class");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,71 +9,72 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
|
||||||
{
|
{
|
||||||
private bool ShouldEmitMethods(MethodsToGen_Extensions_ServiceCollection methods) => (_sourceGenSpec.MethodsToGen_ServiceCollectionExt & methods) != 0;
|
private bool ShouldEmitMethods(MethodsToGen_Extensions_ServiceCollection methods) => (_sourceGenSpec.MethodsToGen_ServiceCollectionExt & methods) != 0;
|
||||||
|
|
||||||
private void EmitBinder_Extensions_IServiceCollection()
|
private void EmitBindingExtensions_IServiceCollection()
|
||||||
{
|
{
|
||||||
if (!ShouldEmitMethods(MethodsToGen_Extensions_ServiceCollection.Any))
|
if (!ShouldEmitMethods(MethodsToGen_Extensions_ServiceCollection.Any))
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
EmitRootBindingClassStartBlock(Identifier.GeneratedServiceCollectionBinder);
|
EmitBindingExtStartRegion(Identifier.IServiceCollection);
|
||||||
|
EmitConfigureMethods();
|
||||||
|
EmitBindingExtEndRegion();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void EmitConfigureMethods()
|
||||||
|
{
|
||||||
const string defaultNameExpr = "string.Empty";
|
const string defaultNameExpr = "string.Empty";
|
||||||
const string configureMethodString = $"global::{Identifier.GeneratedServiceCollectionBinder}.{Identifier.Configure}";
|
string configParam = $"{Identifier.IConfiguration} {Identifier.configuration}";
|
||||||
string configParam = $"{FullyQualifiedDisplayString.IConfiguration} {Identifier.configuration}";
|
|
||||||
|
|
||||||
if (ShouldEmitMethods(MethodsToGen_Extensions_ServiceCollection.Configure_T))
|
if (ShouldEmitMethods(MethodsToGen_Extensions_ServiceCollection.Configure_T))
|
||||||
{
|
{
|
||||||
EmitStartMethod(configParam);
|
EmitStartMethod(MethodsToGen_Extensions_ServiceCollection.Configure_T, configParam);
|
||||||
_writer.WriteLine($"return {configureMethodString}<{Identifier.TOptions}>({Identifier.services}, {defaultNameExpr}, {Identifier.configuration}, {Identifier.configureOptions}: null);");
|
_writer.WriteLine($"return {Identifier.Configure}<{Identifier.TOptions}>({Identifier.services}, {defaultNameExpr}, {Identifier.configuration}, {Identifier.configureOptions}: null);");
|
||||||
EmitEndBlock();
|
EmitEndBlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ShouldEmitMethods(MethodsToGen_Extensions_ServiceCollection.Configure_T_name))
|
if (ShouldEmitMethods(MethodsToGen_Extensions_ServiceCollection.Configure_T_name))
|
||||||
{
|
{
|
||||||
EmitStartMethod(
|
EmitStartMethod(
|
||||||
|
MethodsToGen_Extensions_ServiceCollection.Configure_T_name,
|
||||||
paramList: $"string? {Identifier.name}, " + configParam);
|
paramList: $"string? {Identifier.name}, " + configParam);
|
||||||
_writer.WriteLine($"return {configureMethodString}<{Identifier.TOptions}>({Identifier.services}, {Identifier.name}, {Identifier.configuration}, {Identifier.configureOptions}: null);");
|
_writer.WriteLine($"return {Identifier.Configure}<{Identifier.TOptions}>({Identifier.services}, {Identifier.name}, {Identifier.configuration}, {Identifier.configureOptions}: null);");
|
||||||
EmitEndBlock();
|
EmitEndBlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ShouldEmitMethods(MethodsToGen_Extensions_ServiceCollection.Configure_T_BinderOptions))
|
if (ShouldEmitMethods(MethodsToGen_Extensions_ServiceCollection.Configure_T_BinderOptions))
|
||||||
{
|
{
|
||||||
EmitStartMethod(
|
EmitStartMethod(
|
||||||
paramList: configParam + $", {FullyQualifiedDisplayString.ActionOfBinderOptions}? {Identifier.configureOptions}");
|
MethodsToGen_Extensions_ServiceCollection.Configure_T_BinderOptions,
|
||||||
_writer.WriteLine($"return {configureMethodString}<{Identifier.TOptions}>({Identifier.services}, {defaultNameExpr}, {Identifier.configuration}, {Identifier.configureOptions});");
|
paramList: configParam + $", {TypeDisplayString.NullableActionOfBinderOptions} {Identifier.configureOptions}");
|
||||||
|
_writer.WriteLine($"return {Identifier.Configure}<{Identifier.TOptions}>({Identifier.services}, {defaultNameExpr}, {Identifier.configuration}, {Identifier.configureOptions});");
|
||||||
EmitEndBlock();
|
EmitEndBlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Core Configure method that the other overloads call.
|
// Core Configure method that the other overloads call.
|
||||||
// Like the others, it is public API that could be called directly by users.
|
// 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.
|
// So, it is always generated whenever a Configure overload is called.
|
||||||
string optionsNamespaceName = "global::Microsoft.Extensions.Options";
|
string optionsNamespaceName = "Microsoft.Extensions.Options";
|
||||||
string bindCoreUntypedDisplayString = GetHelperMethodDisplayString(nameof(MethodsToGen_CoreBindingHelper.BindCoreUntyped));
|
|
||||||
|
|
||||||
EmitStartMethod(paramList: $"string? {Identifier.name}, " + configParam + $", {FullyQualifiedDisplayString.ActionOfBinderOptions}? {Identifier.configureOptions}");
|
EmitStartMethod(MethodsToGen_Extensions_ServiceCollection.Configure_T_name_BinderOptions, paramList: $"string? {Identifier.name}, " + configParam + $", {TypeDisplayString.NullableActionOfBinderOptions} {Identifier.configureOptions}");
|
||||||
EmitCheckForNullArgument_WithBlankLine(Identifier.services);
|
EmitCheckForNullArgument_WithBlankLine(Identifier.services);
|
||||||
EmitCheckForNullArgument_WithBlankLine(Identifier.configuration);
|
EmitCheckForNullArgument_WithBlankLine(Identifier.configuration);
|
||||||
_writer.WriteLine($$"""
|
_writer.WriteLine($$"""
|
||||||
global::Microsoft.Extensions.DependencyInjection.OptionsServiceCollectionExtensions.AddOptions({{Identifier.services}});
|
OptionsServiceCollectionExtensions.AddOptions({{Identifier.services}});
|
||||||
{{FullyQualifiedDisplayString.AddSingleton}}<{{FullyQualifiedDisplayString.IOptionsChangeTokenSource}}<{{Identifier.TOptions}}>>({{Identifier.services}}, new {{FullyQualifiedDisplayString.ConfigurationChangeTokenSource}}<{{Identifier.TOptions}}>({{Identifier.name}}, {{Identifier.configuration}}));
|
{{Identifier.services}}.{{Identifier.AddSingleton}}<{{Identifier.IOptionsChangeTokenSource}}<{{Identifier.TOptions}}>>(new {{Identifier.ConfigurationChangeTokenSource}}<{{Identifier.TOptions}}>({{Identifier.name}}, {{Identifier.configuration}}));
|
||||||
return {{FullyQualifiedDisplayString.AddSingleton}}<{{optionsNamespaceName}}.IConfigureOptions<{{Identifier.TOptions}}>>({{Identifier.services}}, new {{optionsNamespaceName}}.ConfigureNamedOptions<{{Identifier.TOptions}}>({{Identifier.name}}, {{Identifier.obj}} => {{bindCoreUntypedDisplayString}}({{Identifier.configuration}}, {{Identifier.obj}}, typeof({{Identifier.TOptions}}), {{Identifier.configureOptions}})));
|
return {{Identifier.services}}.{{Identifier.AddSingleton}}<{{optionsNamespaceName}}.IConfigureOptions<{{Identifier.TOptions}}>>(new {{optionsNamespaceName}}.ConfigureNamedOptions<{{Identifier.TOptions}}>({{Identifier.name}}, {{Identifier.obj}} => {{nameof(MethodsToGen_CoreBindingHelper.BindCoreMain)}}({{Identifier.configuration}}, {{Identifier.obj}}, typeof({{Identifier.TOptions}}){{Identifier.configureOptions}})));
|
||||||
""");
|
""");
|
||||||
EmitEndBlock();
|
EmitEndBlock();
|
||||||
|
|
||||||
EmitEndBlock();
|
|
||||||
_emitBlankLineBeforeNextStatement = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void EmitStartMethod(string paramList)
|
private void EmitStartMethod(MethodsToGen_Extensions_ServiceCollection overload, string paramList)
|
||||||
{
|
{
|
||||||
paramList = $"this {FullyQualifiedDisplayString.IServiceCollection} {Identifier.services}, {paramList}";
|
paramList = $"this {Identifier.IServiceCollection} {Identifier.services}, {paramList}";
|
||||||
|
|
||||||
EmitBlankLineIfRequired();
|
EmitBlankLineIfRequired();
|
||||||
EmitStartBlock($$"""
|
_writer.WriteLine("/// <summary>Registers a configuration instance which TOptions will bind against.</summary>");
|
||||||
/// <summary>Registers a configuration instance which TOptions will bind against.</summary>
|
EmitInterceptsLocationAnnotations(overload);
|
||||||
public static {{FullyQualifiedDisplayString.IServiceCollection}} {{Identifier.Configure}}<{{Identifier.TOptions}}>({{paramList}}) where {{Identifier.TOptions}} : class
|
EmitStartBlock($"public static {Identifier.IServiceCollection} {Identifier.Configure}<{Identifier.TOptions}>({paramList}) where {Identifier.TOptions} : class");
|
||||||
""");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,90 @@
|
||||||
|
// 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.Collections;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Microsoft.CodeAnalysis;
|
||||||
|
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
||||||
|
using Microsoft.CodeAnalysis.Operations;
|
||||||
|
using Microsoft.CodeAnalysis.Text;
|
||||||
|
|
||||||
|
namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
|
||||||
|
{
|
||||||
|
internal sealed record InterceptorLocationInfo
|
||||||
|
{
|
||||||
|
public InterceptorLocationInfo(IInvocationOperation operation)
|
||||||
|
{
|
||||||
|
SyntaxNode operationSyntax = operation.Syntax;
|
||||||
|
TextSpan operationSpan = operationSyntax.Span;
|
||||||
|
SyntaxTree operationSyntaxTree = operationSyntax.SyntaxTree;
|
||||||
|
|
||||||
|
FilePath = GetInterceptorFilePath(operationSyntaxTree, operation.SemanticModel?.Compilation.Options.SourceReferenceResolver);
|
||||||
|
|
||||||
|
FileLinePositionSpan span = operationSyntaxTree.GetLineSpan(operationSpan);
|
||||||
|
LineNumber = span.StartLinePosition.Line + 1;
|
||||||
|
|
||||||
|
// Calculate the character offset to the end of the binding invocation detected.
|
||||||
|
int invocationLength = ((MemberAccessExpressionSyntax)((InvocationExpressionSyntax)operationSyntax).Expression).Expression.Span.Length;
|
||||||
|
CharacterNumber = span.StartLinePosition.Character + invocationLength + 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
public string FilePath { get; }
|
||||||
|
public int LineNumber { get; }
|
||||||
|
public int CharacterNumber { get; }
|
||||||
|
|
||||||
|
// Utilize the same logic used by the interceptors API for resolving the source mapped value of a path.
|
||||||
|
// https://github.com/dotnet/roslyn/blob/f290437fcc75dad50a38c09e0977cce13a64f5ba/src/Compilers/CSharp/Portable/Compilation/CSharpCompilation.cs#L1063-L1064
|
||||||
|
private static string GetInterceptorFilePath(SyntaxTree tree, SourceReferenceResolver? resolver) =>
|
||||||
|
resolver?.NormalizePath(tree.FilePath, baseFilePath: null) ?? tree.FilePath;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal sealed record ConfigurationBinderInterceptorInfo
|
||||||
|
{
|
||||||
|
private OverloadInterceptorInfo? _bind_Instance;
|
||||||
|
private OverloadInterceptorInfo? _bind_instance_BinderOptions;
|
||||||
|
private OverloadInterceptorInfo? _bind_key_instance;
|
||||||
|
|
||||||
|
public void RegisterOverloadInfo(MethodsToGen_ConfigurationBinder overload, TypeSpec type, IInvocationOperation operation)
|
||||||
|
{
|
||||||
|
OverloadInterceptorInfo overloadInfo = DetermineOverload(overload, initIfNull: true);
|
||||||
|
overloadInfo.RegisterLocationInfo(type, operation);
|
||||||
|
}
|
||||||
|
|
||||||
|
public OverloadInterceptorInfo GetOverloadInfo(MethodsToGen_ConfigurationBinder overload) =>
|
||||||
|
DetermineOverload(overload, initIfNull: false) ?? throw new ArgumentNullException(nameof(overload));
|
||||||
|
|
||||||
|
private OverloadInterceptorInfo? DetermineOverload(MethodsToGen_ConfigurationBinder overload, bool initIfNull)
|
||||||
|
{
|
||||||
|
return overload switch
|
||||||
|
{
|
||||||
|
MethodsToGen_ConfigurationBinder.Bind_instance => InitIfNull(ref _bind_Instance),
|
||||||
|
MethodsToGen_ConfigurationBinder.Bind_instance_BinderOptions => InitIfNull(ref _bind_instance_BinderOptions),
|
||||||
|
MethodsToGen_ConfigurationBinder.Bind_key_instance => InitIfNull(ref _bind_key_instance),
|
||||||
|
_ => throw new InvalidOperationException(nameof(overload)),
|
||||||
|
};
|
||||||
|
|
||||||
|
OverloadInterceptorInfo InitIfNull(ref OverloadInterceptorInfo? info)
|
||||||
|
{
|
||||||
|
if (initIfNull)
|
||||||
|
{
|
||||||
|
info ??= new OverloadInterceptorInfo();
|
||||||
|
}
|
||||||
|
|
||||||
|
return info;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal sealed record OverloadInterceptorInfo : IEnumerable<KeyValuePair<TypeSpec, List<InterceptorLocationInfo>>>
|
||||||
|
{
|
||||||
|
private readonly Dictionary<TypeSpec, List<InterceptorLocationInfo>> _typeInterceptionInfo = new();
|
||||||
|
|
||||||
|
public void RegisterLocationInfo(TypeSpec type, IInvocationOperation operation) =>
|
||||||
|
_typeInterceptionInfo.RegisterCacheEntry(type, new InterceptorLocationInfo(operation));
|
||||||
|
|
||||||
|
public IEnumerator<KeyValuePair<TypeSpec, List<InterceptorLocationInfo>>> GetEnumerator() => _typeInterceptionInfo.GetEnumerator();
|
||||||
|
|
||||||
|
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
|
||||||
|
}
|
||||||
|
}
|
|
@ -10,11 +10,12 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
|
||||||
{
|
{
|
||||||
None = 0x0,
|
None = 0x0,
|
||||||
BindCore = 0x1,
|
BindCore = 0x1,
|
||||||
BindCoreUntyped = 0x2,
|
GetCore = 0x2,
|
||||||
GetCore = 0x4,
|
GetValueCore = 0x4,
|
||||||
GetValueCore = 0x8,
|
BindCoreMain = 0x8,
|
||||||
Initialize = 0x10,
|
Initialize = 0x10,
|
||||||
AsConfigWithChildren = 0x20,
|
HasValueOrChildren = 0x20,
|
||||||
|
AsConfigWithChildren = 0x40,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
|
@ -40,7 +40,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
|
||||||
IsValidMethodName_OptionsConfigurationServiceCollectionExtensions(name);
|
IsValidMethodName_OptionsConfigurationServiceCollectionExtensions(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static bool IsBindingOperation(IInvocationOperation operation)
|
public static bool IsBindingOperation(IInvocationOperation operation)
|
||||||
{
|
{
|
||||||
if (operation.TargetMethod is not IMethodSymbol
|
if (operation.TargetMethod is not IMethodSymbol
|
||||||
{
|
{
|
||||||
|
|
|
@ -102,15 +102,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
|
||||||
|
|
||||||
if (GetTargetTypeForRootInvocationCore(type, invocation.Location) is TypeSpec typeSpec)
|
if (GetTargetTypeForRootInvocationCore(type, invocation.Location) is TypeSpec typeSpec)
|
||||||
{
|
{
|
||||||
Dictionary<MethodsToGen_ConfigurationBinder, HashSet<TypeSpec>> types = _sourceGenSpec.TypesForGen_ConfigurationBinder_BindMethods;
|
RegisterAsInterceptor_ConfigBinder_BindMethod(overload, typeSpec, invocation.Operation);
|
||||||
|
|
||||||
if (!types.TryGetValue(overload, out HashSet<TypeSpec>? typeSpecs))
|
|
||||||
{
|
|
||||||
types[overload] = typeSpecs = new HashSet<TypeSpec>();
|
|
||||||
}
|
|
||||||
|
|
||||||
_sourceGenSpec.MethodsToGen_ConfigurationBinder |= overload;
|
|
||||||
typeSpecs.Add(typeSpec);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static ITypeSymbol? ResolveType(IOperation conversionOperation) =>
|
static ITypeSymbol? ResolveType(IOperation conversionOperation) =>
|
||||||
|
@ -184,8 +176,8 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
|
||||||
|
|
||||||
if (GetTargetTypeForRootInvocation(type, invocation.Location) is TypeSpec typeSpec)
|
if (GetTargetTypeForRootInvocation(type, invocation.Location) is TypeSpec typeSpec)
|
||||||
{
|
{
|
||||||
_sourceGenSpec.MethodsToGen_ConfigurationBinder |= overload;
|
RegisterAsInterceptor_ConfigBinder(overload, invocation.Operation);
|
||||||
RegisterTypeForMethodGen(MethodsToGen_CoreBindingHelper.GetCore, typeSpec);
|
RegisterTypeForGetCoreGen(typeSpec);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -253,10 +245,27 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
|
||||||
if (IsParsableFromString(effectiveType, out _) &&
|
if (IsParsableFromString(effectiveType, out _) &&
|
||||||
GetTargetTypeForRootInvocationCore(type, invocation.Location) is TypeSpec typeSpec)
|
GetTargetTypeForRootInvocationCore(type, invocation.Location) is TypeSpec typeSpec)
|
||||||
{
|
{
|
||||||
_sourceGenSpec.MethodsToGen_ConfigurationBinder |= overload;
|
RegisterAsInterceptor_ConfigBinder(overload, invocation.Operation);
|
||||||
RegisterTypeForMethodGen(MethodsToGen_CoreBindingHelper.GetValueCore, typeSpec);
|
RegisterTypeForMethodGen(MethodsToGen_CoreBindingHelper.GetValueCore, typeSpec);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void RegisterAsInterceptor_ConfigBinder(MethodsToGen_ConfigurationBinder overload, IInvocationOperation operation)
|
||||||
|
{
|
||||||
|
_sourceGenSpec.MethodsToGen_ConfigurationBinder |= overload;
|
||||||
|
RegisterAsInterceptor(overload, operation);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Registers generated Bind methods as interceptors. This is done differently from other root
|
||||||
|
/// methods <see cref="RegisterAsInterceptor(Enum, IInvocationOperation)"/> because we need to
|
||||||
|
/// explicitly account for the type to bind, to avoid type-check issues for polymorphic objects.
|
||||||
|
/// </summary>
|
||||||
|
private void RegisterAsInterceptor_ConfigBinder_BindMethod(MethodsToGen_ConfigurationBinder overload, TypeSpec typeSpec, IInvocationOperation operation)
|
||||||
|
{
|
||||||
|
_sourceGenSpec.MethodsToGen_ConfigurationBinder |= overload;
|
||||||
|
_sourceGenSpec.InterceptionInfo_ConfigBinder.RegisterOverloadInfo(overload, typeSpec, operation);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,9 +34,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// We are going to emit calls to APIs on IServiceCollection.
|
|
||||||
_sourceGenSpec.TypeNamespaces.Add("Microsoft.Extensions.DependencyInjection");
|
|
||||||
|
|
||||||
if (targetMethod.Name is "Bind")
|
if (targetMethod.Name is "Bind")
|
||||||
{
|
{
|
||||||
RegisterBindInvocation(invocation, typeSpec);
|
RegisterBindInvocation(invocation, typeSpec);
|
||||||
|
@ -61,20 +58,19 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (paramCount is 2)
|
MethodsToGen_Extensions_OptionsBuilder overload = paramCount switch
|
||||||
{
|
{
|
||||||
_sourceGenSpec.MethodsToGen_OptionsBuilderExt |= MethodsToGen_Extensions_OptionsBuilder.Bind_T;
|
2 => MethodsToGen_Extensions_OptionsBuilder.Bind_T,
|
||||||
}
|
3 when SymbolEqualityComparer.Default.Equals(_typeSymbols.ActionOfBinderOptions, @params[2].Type) =>
|
||||||
else if (paramCount is 3 && SymbolEqualityComparer.Default.Equals(_typeSymbols.ActionOfBinderOptions, @params[2].Type))
|
MethodsToGen_Extensions_OptionsBuilder.Bind_T_BinderOptions,
|
||||||
{
|
_ => MethodsToGen_Extensions_OptionsBuilder.None
|
||||||
_sourceGenSpec.MethodsToGen_OptionsBuilderExt |= MethodsToGen_Extensions_OptionsBuilder.Bind_T_BinderOptions;
|
};
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
RegisterTypeForMethodGen(MethodsToGen_Extensions_ServiceCollection.Configure_T_name_BinderOptions, typeSpec);
|
if (overload is not MethodsToGen_Extensions_OptionsBuilder.None)
|
||||||
|
{
|
||||||
|
RegisterAsInterceptor_OptionsBuilder(overload, operation);
|
||||||
|
RegisterTypeForMethodGen(MethodsToGen_Extensions_ServiceCollection.Configure_T_name_BinderOptions, typeSpec);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ParseBindConfigurationInvocation(BinderInvocation invocation, TypeSpec typeSpec)
|
private void ParseBindConfigurationInvocation(BinderInvocation invocation, TypeSpec typeSpec)
|
||||||
|
@ -85,12 +81,26 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
|
||||||
int paramCount = @params.Length;
|
int paramCount = @params.Length;
|
||||||
Debug.Assert(paramCount >= 2);
|
Debug.Assert(paramCount >= 2);
|
||||||
|
|
||||||
if (paramCount is 3 && @params[1].Type.SpecialType is SpecialType.System_String && SymbolEqualityComparer.Default.Equals(_typeSymbols.ActionOfBinderOptions, @params[2].Type))
|
if (paramCount is 3 &&
|
||||||
|
@params[1].Type.SpecialType is SpecialType.System_String &&
|
||||||
|
SymbolEqualityComparer.Default.Equals(_typeSymbols.ActionOfBinderOptions, @params[2].Type))
|
||||||
{
|
{
|
||||||
_sourceGenSpec.MethodsToGen_OptionsBuilderExt |= MethodsToGen_Extensions_OptionsBuilder.BindConfiguration_T_path_BinderOptions;
|
RegisterAsInterceptor_OptionsBuilder(MethodsToGen_Extensions_OptionsBuilder.BindConfiguration_T_path_BinderOptions, invocation.Operation);
|
||||||
RegisterTypeForBindCoreUntypedGen(typeSpec);
|
RegisterTypeForBindCoreMainGen(typeSpec);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void RegisterAsInterceptor_OptionsBuilder(MethodsToGen_Extensions_OptionsBuilder overload, IInvocationOperation operation)
|
||||||
|
{
|
||||||
|
_sourceGenSpec.MethodsToGen_OptionsBuilderExt |= overload;
|
||||||
|
RegisterAsInterceptor(overload, operation);
|
||||||
|
|
||||||
|
// Emitting refs to IOptionsChangeTokenSource, ConfigurationChangeTokenSource.
|
||||||
|
_sourceGenSpec.Namespaces.Add("Microsoft.Extensions.Options");
|
||||||
|
|
||||||
|
// Emitting refs to OptionsBuilder<T>.
|
||||||
|
_sourceGenSpec.Namespaces.Add("Microsoft.Extensions.DependencyInjection");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -79,12 +79,14 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
|
||||||
}
|
}
|
||||||
|
|
||||||
RegisterTypeForMethodGen(overload, typeSpec);
|
RegisterTypeForMethodGen(overload, typeSpec);
|
||||||
|
RegisterAsInterceptor(overload, operation);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void RegisterTypeForMethodGen(MethodsToGen_Extensions_ServiceCollection overload, TypeSpec typeSpec)
|
private void RegisterTypeForMethodGen(MethodsToGen_Extensions_ServiceCollection overload, TypeSpec typeSpec)
|
||||||
{
|
{
|
||||||
_sourceGenSpec.MethodsToGen_ServiceCollectionExt |= overload;
|
_sourceGenSpec.MethodsToGen_ServiceCollectionExt |= overload;
|
||||||
RegisterTypeForBindCoreUntypedGen(typeSpec);
|
_sourceGenSpec.Namespaces.Add("Microsoft.Extensions.DependencyInjection");
|
||||||
|
RegisterTypeForBindCoreMainGen(typeSpec);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Workspaces" Version="$(MicrosoftCodeAnalysisVersion_LatestVS)" PrivateAssets="all" />
|
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Workspaces" Version="4.7.0-3.23314.3" PrivateAssets="all" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
@ -26,12 +26,14 @@
|
||||||
<Compile Include="ConfigurationBindingGenerator.cs" />
|
<Compile Include="ConfigurationBindingGenerator.cs" />
|
||||||
<Compile Include="ConfigurationBindingGenerator.Emitter.cs" />
|
<Compile Include="ConfigurationBindingGenerator.Emitter.cs" />
|
||||||
<Compile Include="ConfigurationBindingGenerator.Parser.cs" />
|
<Compile Include="ConfigurationBindingGenerator.Parser.cs" />
|
||||||
|
<Compile Include="ConfigurationBindingGenerator.Suppressor.cs" />
|
||||||
<Compile Include="Helpers\Emitter\ConfigurationBinder.cs" />
|
<Compile Include="Helpers\Emitter\ConfigurationBinder.cs" />
|
||||||
<Compile Include="Helpers\Emitter\CoreBindingHelper.cs" />
|
<Compile Include="Helpers\Emitter\CoreBindingHelpers.cs" />
|
||||||
<Compile Include="Helpers\Emitter\ExceptionMessages.cs" />
|
<Compile Include="Helpers\Emitter\ExceptionMessages.cs" />
|
||||||
<Compile Include="Helpers\Emitter\Helpers.cs" />
|
<Compile Include="Helpers\Emitter\Helpers.cs" />
|
||||||
<Compile Include="Helpers\Emitter\OptionsBuilderConfigurationExtensions.cs" />
|
<Compile Include="Helpers\Emitter\OptionsBuilderConfigurationExtensions.cs" />
|
||||||
<Compile Include="Helpers\Emitter\OptionsConfigurationServiceCollectionExtensions.cs" />
|
<Compile Include="Helpers\Emitter\OptionsConfigurationServiceCollectionExtensions.cs" />
|
||||||
|
<Compile Include="Helpers\InterceptorLocationInfo.cs" />
|
||||||
<Compile Include="Helpers\MethodsToGen.cs" />
|
<Compile Include="Helpers\MethodsToGen.cs" />
|
||||||
<Compile Include="Helpers\Parser\BinderInvocation.cs" />
|
<Compile Include="Helpers\Parser\BinderInvocation.cs" />
|
||||||
<Compile Include="Helpers\Parser\ConfigurationBinder.cs" />
|
<Compile Include="Helpers\Parser\ConfigurationBinder.cs" />
|
||||||
|
|
|
@ -22,10 +22,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
|
||||||
|
|
||||||
public List<ParameterSpec> ConstructorParameters { get; } = new();
|
public List<ParameterSpec> ConstructorParameters { get; } = new();
|
||||||
|
|
||||||
private string _displayStringWithoutSpecialCharacters;
|
|
||||||
public string DisplayStringWithoutSpecialCharacters =>
|
|
||||||
_displayStringWithoutSpecialCharacters ??= $"{MinimalDisplayString.Replace(".", string.Empty).Replace("<", string.Empty).Replace(">", string.Empty)}";
|
|
||||||
|
|
||||||
public override bool NeedsMemberBinding => CanInitialize &&
|
public override bool NeedsMemberBinding => CanInitialize &&
|
||||||
Properties.Values.Count > 0 &&
|
Properties.Values.Count > 0 &&
|
||||||
Properties.Values.Any(p => p.ShouldBind());
|
Properties.Values.Any(p => p.ShouldBind());
|
||||||
|
|
|
@ -24,7 +24,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
|
||||||
_parseMethodName ??= StringParsableTypeKind is StringParsableTypeKind.ByteArray
|
_parseMethodName ??= StringParsableTypeKind is StringParsableTypeKind.ByteArray
|
||||||
? "ParseByteArray"
|
? "ParseByteArray"
|
||||||
// MinimalDisplayString.Length is certainly > 2.
|
// MinimalDisplayString.Length is certainly > 2.
|
||||||
: $"Parse{(char.ToUpper(MinimalDisplayString[0]) + MinimalDisplayString.Substring(1)).Replace(".", "")}";
|
: $"Parse{(char.ToUpper(DisplayString[0]) + DisplayString.Substring(1)).Replace(".", "")}";
|
||||||
|
|
||||||
return _parseMethodName;
|
return _parseMethodName;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,21 +1,25 @@
|
||||||
// Licensed to the .NET Foundation under one or more agreements.
|
// Licensed to the .NET Foundation under one or more agreements.
|
||||||
// The .NET Foundation licenses this file to you under the MIT license.
|
// The .NET Foundation licenses this file to you under the MIT license.
|
||||||
|
|
||||||
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
|
||||||
namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
|
namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
|
||||||
{
|
{
|
||||||
internal sealed record SourceGenerationSpec
|
internal sealed record SourceGenerationSpec
|
||||||
{
|
{
|
||||||
|
public Dictionary<Enum, List<InterceptorLocationInfo>> InterceptionInfo { get; } = new();
|
||||||
|
public ConfigurationBinderInterceptorInfo InterceptionInfo_ConfigBinder { get; } = new();
|
||||||
|
|
||||||
public Dictionary<MethodsToGen_CoreBindingHelper, HashSet<TypeSpec>> TypesForGen_CoreBindingHelper_Methods { get; } = new();
|
public Dictionary<MethodsToGen_CoreBindingHelper, HashSet<TypeSpec>> TypesForGen_CoreBindingHelper_Methods { get; } = new();
|
||||||
public Dictionary<MethodsToGen_ConfigurationBinder, HashSet<TypeSpec>> TypesForGen_ConfigurationBinder_BindMethods { get; } = new();
|
|
||||||
|
|
||||||
public HashSet<ParsableFromStringSpec> PrimitivesForHelperGen { get; } = new();
|
public HashSet<ParsableFromStringSpec> PrimitivesForHelperGen { get; } = new();
|
||||||
public HashSet<string> TypeNamespaces { get; } = new()
|
public HashSet<string> Namespaces { get; } = new()
|
||||||
{
|
{
|
||||||
"System",
|
"System",
|
||||||
"System.CodeDom.Compiler",
|
"System.CodeDom.Compiler",
|
||||||
"System.Globalization",
|
"System.Globalization",
|
||||||
|
"System.Runtime.CompilerServices",
|
||||||
"Microsoft.Extensions.Configuration",
|
"Microsoft.Extensions.Configuration",
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -17,17 +17,14 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
|
||||||
{
|
{
|
||||||
IsValueType = type.IsValueType;
|
IsValueType = type.IsValueType;
|
||||||
Namespace = type.ContainingNamespace?.ToDisplayString();
|
Namespace = type.ContainingNamespace?.ToDisplayString();
|
||||||
FullyQualifiedDisplayString = type.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat);
|
DisplayString = type.ToDisplayString(s_minimalDisplayFormat);
|
||||||
MinimalDisplayString = type.ToDisplayString(s_minimalDisplayFormat);
|
Name = Namespace + "." + DisplayString.Replace(".", "+");
|
||||||
Name = Namespace + "." + MinimalDisplayString.Replace(".", "+");
|
|
||||||
IsInterface = type.TypeKind is TypeKind.Interface;
|
IsInterface = type.TypeKind is TypeKind.Interface;
|
||||||
}
|
}
|
||||||
|
|
||||||
public string Name { get; }
|
public string Name { get; }
|
||||||
|
|
||||||
public string FullyQualifiedDisplayString { get; }
|
public string DisplayString { get; }
|
||||||
|
|
||||||
public string MinimalDisplayString { get; }
|
|
||||||
|
|
||||||
public string? Namespace { get; }
|
public string? Namespace { get; }
|
||||||
|
|
||||||
|
|
|
@ -133,10 +133,10 @@
|
||||||
<value>The collection element type is not supported: '{0}'.</value>
|
<value>The collection element type is not supported: '{0}'.</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="Language VersionIsNotSupportedMessageFormat" xml:space="preserve">
|
<data name="Language VersionIsNotSupportedMessageFormat" xml:space="preserve">
|
||||||
<value>The project's language version has to be at least 'C# 11'.</value>
|
<value>The project's language version has to be at least 'C# 12'.</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="LanguageVersionIsNotSupportedTitle" xml:space="preserve">
|
<data name="LanguageVersionIsNotSupportedTitle" xml:space="preserve">
|
||||||
<value>Language version is required to be at least C# 11</value>
|
<value>Language version is required to be at least C# 12</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="MissingPublicInstanceConstructor" xml:space="preserve">
|
<data name="MissingPublicInstanceConstructor" xml:space="preserve">
|
||||||
<value>Cannot create instance of type '{0}' because it is missing a public instance constructor.</value>
|
<value>Cannot create instance of type '{0}' because it is missing a public instance constructor.</value>
|
||||||
|
|
|
@ -28,13 +28,13 @@
|
||||||
<note />
|
<note />
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="Language VersionIsNotSupportedMessageFormat">
|
<trans-unit id="Language VersionIsNotSupportedMessageFormat">
|
||||||
<source>The project's language version has to be at least 'C# 11'.</source>
|
<source>The project's language version has to be at least 'C# 12'.</source>
|
||||||
<target state="translated">Jazyková verze projektu musí být alespoň C# 11</target>
|
<target state="needs-review-translation">Jazyková verze projektu musí být alespoň C# 11</target>
|
||||||
<note />
|
<note />
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="LanguageVersionIsNotSupportedTitle">
|
<trans-unit id="LanguageVersionIsNotSupportedTitle">
|
||||||
<source>Language version is required to be at least C# 11</source>
|
<source>Language version is required to be at least C# 12</source>
|
||||||
<target state="translated">Verze jazyka musí být alespoň C# 11</target>
|
<target state="needs-review-translation">Verze jazyka musí být alespoň C# 11</target>
|
||||||
<note />
|
<note />
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="MissingPublicInstanceConstructor">
|
<trans-unit id="MissingPublicInstanceConstructor">
|
||||||
|
|
|
@ -28,13 +28,13 @@
|
||||||
<note />
|
<note />
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="Language VersionIsNotSupportedMessageFormat">
|
<trans-unit id="Language VersionIsNotSupportedMessageFormat">
|
||||||
<source>The project's language version has to be at least 'C# 11'.</source>
|
<source>The project's language version has to be at least 'C# 12'.</source>
|
||||||
<target state="translated">Die Sprachversion des Projekts muss mindestens „C# 11“ sein</target>
|
<target state="needs-review-translation">Die Sprachversion des Projekts muss mindestens „C# 11“ sein</target>
|
||||||
<note />
|
<note />
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="LanguageVersionIsNotSupportedTitle">
|
<trans-unit id="LanguageVersionIsNotSupportedTitle">
|
||||||
<source>Language version is required to be at least C# 11</source>
|
<source>Language version is required to be at least C# 12</source>
|
||||||
<target state="translated">Die Sprachversion muss mindestens C# 11 sein</target>
|
<target state="needs-review-translation">Die Sprachversion muss mindestens C# 11 sein</target>
|
||||||
<note />
|
<note />
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="MissingPublicInstanceConstructor">
|
<trans-unit id="MissingPublicInstanceConstructor">
|
||||||
|
|
|
@ -28,13 +28,13 @@
|
||||||
<note />
|
<note />
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="Language VersionIsNotSupportedMessageFormat">
|
<trans-unit id="Language VersionIsNotSupportedMessageFormat">
|
||||||
<source>The project's language version has to be at least 'C# 11'.</source>
|
<source>The project's language version has to be at least 'C# 12'.</source>
|
||||||
<target state="translated">La versión del lenguaje del proyecto debe ser al menos "C# 11".</target>
|
<target state="needs-review-translation">La versión del lenguaje del proyecto debe ser al menos "C# 11".</target>
|
||||||
<note />
|
<note />
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="LanguageVersionIsNotSupportedTitle">
|
<trans-unit id="LanguageVersionIsNotSupportedTitle">
|
||||||
<source>Language version is required to be at least C# 11</source>
|
<source>Language version is required to be at least C# 12</source>
|
||||||
<target state="translated">La versión del lenguaje debe ser al menos C# 11</target>
|
<target state="needs-review-translation">La versión del lenguaje debe ser al menos C# 11</target>
|
||||||
<note />
|
<note />
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="MissingPublicInstanceConstructor">
|
<trans-unit id="MissingPublicInstanceConstructor">
|
||||||
|
|
|
@ -28,13 +28,13 @@
|
||||||
<note />
|
<note />
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="Language VersionIsNotSupportedMessageFormat">
|
<trans-unit id="Language VersionIsNotSupportedMessageFormat">
|
||||||
<source>The project's language version has to be at least 'C# 11'.</source>
|
<source>The project's language version has to be at least 'C# 12'.</source>
|
||||||
<target state="translated">La version de langage du projet doit être au moins « C# 11 ».</target>
|
<target state="needs-review-translation">La version de langage du projet doit être au moins « C# 11 ».</target>
|
||||||
<note />
|
<note />
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="LanguageVersionIsNotSupportedTitle">
|
<trans-unit id="LanguageVersionIsNotSupportedTitle">
|
||||||
<source>Language version is required to be at least C# 11</source>
|
<source>Language version is required to be at least C# 12</source>
|
||||||
<target state="translated">La version du langage doit être au moins C# 11</target>
|
<target state="needs-review-translation">La version du langage doit être au moins C# 11</target>
|
||||||
<note />
|
<note />
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="MissingPublicInstanceConstructor">
|
<trans-unit id="MissingPublicInstanceConstructor">
|
||||||
|
|
|
@ -28,13 +28,13 @@
|
||||||
<note />
|
<note />
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="Language VersionIsNotSupportedMessageFormat">
|
<trans-unit id="Language VersionIsNotSupportedMessageFormat">
|
||||||
<source>The project's language version has to be at least 'C# 11'.</source>
|
<source>The project's language version has to be at least 'C# 12'.</source>
|
||||||
<target state="translated">La versione del linguaggio del progetto deve essere almeno 'C# 11'.</target>
|
<target state="needs-review-translation">La versione del linguaggio del progetto deve essere almeno 'C# 11'.</target>
|
||||||
<note />
|
<note />
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="LanguageVersionIsNotSupportedTitle">
|
<trans-unit id="LanguageVersionIsNotSupportedTitle">
|
||||||
<source>Language version is required to be at least C# 11</source>
|
<source>Language version is required to be at least C# 12</source>
|
||||||
<target state="translated">La versione del linguaggio deve essere almeno C# 11</target>
|
<target state="needs-review-translation">La versione del linguaggio deve essere almeno C# 11</target>
|
||||||
<note />
|
<note />
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="MissingPublicInstanceConstructor">
|
<trans-unit id="MissingPublicInstanceConstructor">
|
||||||
|
|
|
@ -28,13 +28,13 @@
|
||||||
<note />
|
<note />
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="Language VersionIsNotSupportedMessageFormat">
|
<trans-unit id="Language VersionIsNotSupportedMessageFormat">
|
||||||
<source>The project's language version has to be at least 'C# 11'.</source>
|
<source>The project's language version has to be at least 'C# 12'.</source>
|
||||||
<target state="translated">プロジェクトの言語バージョンは少なくとも 'C# 11' である必要があります。</target>
|
<target state="needs-review-translation">プロジェクトの言語バージョンは少なくとも 'C# 11' である必要があります。</target>
|
||||||
<note />
|
<note />
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="LanguageVersionIsNotSupportedTitle">
|
<trans-unit id="LanguageVersionIsNotSupportedTitle">
|
||||||
<source>Language version is required to be at least C# 11</source>
|
<source>Language version is required to be at least C# 12</source>
|
||||||
<target state="translated">言語バージョンは少なくとも C# 11 である必要があります</target>
|
<target state="needs-review-translation">言語バージョンは少なくとも C# 11 である必要があります</target>
|
||||||
<note />
|
<note />
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="MissingPublicInstanceConstructor">
|
<trans-unit id="MissingPublicInstanceConstructor">
|
||||||
|
|
|
@ -28,13 +28,13 @@
|
||||||
<note />
|
<note />
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="Language VersionIsNotSupportedMessageFormat">
|
<trans-unit id="Language VersionIsNotSupportedMessageFormat">
|
||||||
<source>The project's language version has to be at least 'C# 11'.</source>
|
<source>The project's language version has to be at least 'C# 12'.</source>
|
||||||
<target state="translated">프로젝트의 언어 버전은 'C# 11' 이상이어야 합니다.</target>
|
<target state="needs-review-translation">프로젝트의 언어 버전은 'C# 11' 이상이어야 합니다.</target>
|
||||||
<note />
|
<note />
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="LanguageVersionIsNotSupportedTitle">
|
<trans-unit id="LanguageVersionIsNotSupportedTitle">
|
||||||
<source>Language version is required to be at least C# 11</source>
|
<source>Language version is required to be at least C# 12</source>
|
||||||
<target state="translated">언어 버전은 C# 11 이상이어야 합니다.</target>
|
<target state="needs-review-translation">언어 버전은 C# 11 이상이어야 합니다.</target>
|
||||||
<note />
|
<note />
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="MissingPublicInstanceConstructor">
|
<trans-unit id="MissingPublicInstanceConstructor">
|
||||||
|
|
|
@ -28,13 +28,13 @@
|
||||||
<note />
|
<note />
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="Language VersionIsNotSupportedMessageFormat">
|
<trans-unit id="Language VersionIsNotSupportedMessageFormat">
|
||||||
<source>The project's language version has to be at least 'C# 11'.</source>
|
<source>The project's language version has to be at least 'C# 12'.</source>
|
||||||
<target state="translated">Wersja językowa projektu musi mieć wartość co najmniej „C# 11”.</target>
|
<target state="needs-review-translation">Wersja językowa projektu musi mieć wartość co najmniej „C# 11”.</target>
|
||||||
<note />
|
<note />
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="LanguageVersionIsNotSupportedTitle">
|
<trans-unit id="LanguageVersionIsNotSupportedTitle">
|
||||||
<source>Language version is required to be at least C# 11</source>
|
<source>Language version is required to be at least C# 12</source>
|
||||||
<target state="translated">Wymagana jest wersja językowa co najmniej C# 11</target>
|
<target state="needs-review-translation">Wymagana jest wersja językowa co najmniej C# 11</target>
|
||||||
<note />
|
<note />
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="MissingPublicInstanceConstructor">
|
<trans-unit id="MissingPublicInstanceConstructor">
|
||||||
|
|
|
@ -28,13 +28,13 @@
|
||||||
<note />
|
<note />
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="Language VersionIsNotSupportedMessageFormat">
|
<trans-unit id="Language VersionIsNotSupportedMessageFormat">
|
||||||
<source>The project's language version has to be at least 'C# 11'.</source>
|
<source>The project's language version has to be at least 'C# 12'.</source>
|
||||||
<target state="translated">A versão do idioma do projeto deve ser no mínimo 'C# 11'.</target>
|
<target state="needs-review-translation">A versão do idioma do projeto deve ser no mínimo 'C# 11'.</target>
|
||||||
<note />
|
<note />
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="LanguageVersionIsNotSupportedTitle">
|
<trans-unit id="LanguageVersionIsNotSupportedTitle">
|
||||||
<source>Language version is required to be at least C# 11</source>
|
<source>Language version is required to be at least C# 12</source>
|
||||||
<target state="translated">A versão do idioma deve ser pelo menos C# 11</target>
|
<target state="needs-review-translation">A versão do idioma deve ser pelo menos C# 11</target>
|
||||||
<note />
|
<note />
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="MissingPublicInstanceConstructor">
|
<trans-unit id="MissingPublicInstanceConstructor">
|
||||||
|
|
|
@ -28,13 +28,13 @@
|
||||||
<note />
|
<note />
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="Language VersionIsNotSupportedMessageFormat">
|
<trans-unit id="Language VersionIsNotSupportedMessageFormat">
|
||||||
<source>The project's language version has to be at least 'C# 11'.</source>
|
<source>The project's language version has to be at least 'C# 12'.</source>
|
||||||
<target state="translated">Версия языка проекта должна быть не ниже "C# 11".</target>
|
<target state="needs-review-translation">Версия языка проекта должна быть не ниже "C# 11".</target>
|
||||||
<note />
|
<note />
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="LanguageVersionIsNotSupportedTitle">
|
<trans-unit id="LanguageVersionIsNotSupportedTitle">
|
||||||
<source>Language version is required to be at least C# 11</source>
|
<source>Language version is required to be at least C# 12</source>
|
||||||
<target state="translated">Версия языка должна быть не ниже C# 11</target>
|
<target state="needs-review-translation">Версия языка должна быть не ниже C# 11</target>
|
||||||
<note />
|
<note />
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="MissingPublicInstanceConstructor">
|
<trans-unit id="MissingPublicInstanceConstructor">
|
||||||
|
|
|
@ -28,13 +28,13 @@
|
||||||
<note />
|
<note />
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="Language VersionIsNotSupportedMessageFormat">
|
<trans-unit id="Language VersionIsNotSupportedMessageFormat">
|
||||||
<source>The project's language version has to be at least 'C# 11'.</source>
|
<source>The project's language version has to be at least 'C# 12'.</source>
|
||||||
<target state="translated">Projenin dil sürümü en az 'C# 11' olmalıdır.</target>
|
<target state="needs-review-translation">Projenin dil sürümü en az 'C# 11' olmalıdır.</target>
|
||||||
<note />
|
<note />
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="LanguageVersionIsNotSupportedTitle">
|
<trans-unit id="LanguageVersionIsNotSupportedTitle">
|
||||||
<source>Language version is required to be at least C# 11</source>
|
<source>Language version is required to be at least C# 12</source>
|
||||||
<target state="translated">Dil sürümünün en az C# 11 olması gerekir</target>
|
<target state="needs-review-translation">Dil sürümünün en az C# 11 olması gerekir</target>
|
||||||
<note />
|
<note />
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="MissingPublicInstanceConstructor">
|
<trans-unit id="MissingPublicInstanceConstructor">
|
||||||
|
|
|
@ -28,13 +28,13 @@
|
||||||
<note />
|
<note />
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="Language VersionIsNotSupportedMessageFormat">
|
<trans-unit id="Language VersionIsNotSupportedMessageFormat">
|
||||||
<source>The project's language version has to be at least 'C# 11'.</source>
|
<source>The project's language version has to be at least 'C# 12'.</source>
|
||||||
<target state="translated">项目的语言版本必须至少为 "C# 11"。</target>
|
<target state="needs-review-translation">项目的语言版本必须至少为 "C# 11"。</target>
|
||||||
<note />
|
<note />
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="LanguageVersionIsNotSupportedTitle">
|
<trans-unit id="LanguageVersionIsNotSupportedTitle">
|
||||||
<source>Language version is required to be at least C# 11</source>
|
<source>Language version is required to be at least C# 12</source>
|
||||||
<target state="translated">语言版本必须至少为 C# 11</target>
|
<target state="needs-review-translation">语言版本必须至少为 C# 11</target>
|
||||||
<note />
|
<note />
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="MissingPublicInstanceConstructor">
|
<trans-unit id="MissingPublicInstanceConstructor">
|
||||||
|
|
|
@ -28,13 +28,13 @@
|
||||||
<note />
|
<note />
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="Language VersionIsNotSupportedMessageFormat">
|
<trans-unit id="Language VersionIsNotSupportedMessageFormat">
|
||||||
<source>The project's language version has to be at least 'C# 11'.</source>
|
<source>The project's language version has to be at least 'C# 12'.</source>
|
||||||
<target state="translated">專案的語言版本必須至少為 'C# 11'。</target>
|
<target state="needs-review-translation">專案的語言版本必須至少為 'C# 11'。</target>
|
||||||
<note />
|
<note />
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="LanguageVersionIsNotSupportedTitle">
|
<trans-unit id="LanguageVersionIsNotSupportedTitle">
|
||||||
<source>Language version is required to be at least C# 11</source>
|
<source>Language version is required to be at least C# 12</source>
|
||||||
<target state="translated">語言版本要求至少為 C#11</target>
|
<target state="needs-review-translation">語言版本要求至少為 C#11</target>
|
||||||
<note />
|
<note />
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="MissingPublicInstanceConstructor">
|
<trans-unit id="MissingPublicInstanceConstructor">
|
||||||
|
|
|
@ -8,7 +8,6 @@ using System.Diagnostics;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Text;
|
|
||||||
#if BUILDING_SOURCE_GENERATOR_TESTS
|
#if BUILDING_SOURCE_GENERATOR_TESTS
|
||||||
using Microsoft.Extensions.Configuration;
|
using Microsoft.Extensions.Configuration;
|
||||||
#endif
|
#endif
|
||||||
|
@ -2037,6 +2036,7 @@ if (!System.Diagnostics.Debugger.IsAttached) { System.Diagnostics.Debugger.Launc
|
||||||
ValidateGeolocation(obj);
|
ValidateGeolocation(obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if !BUILDING_SOURCE_GENERATOR_TESTS
|
||||||
[ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))]
|
[ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser))]
|
||||||
public void TraceSwitchTest()
|
public void TraceSwitchTest()
|
||||||
{
|
{
|
||||||
|
@ -2056,6 +2056,7 @@ if (!System.Diagnostics.Debugger.IsAttached) { System.Diagnostics.Debugger.Launc
|
||||||
Assert.Equal("Info", ts.Value);
|
Assert.Equal("Info", ts.Value);
|
||||||
#endif // NETCOREAPP
|
#endif // NETCOREAPP
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
private void ValidateGeolocation(IGeolocation location)
|
private void ValidateGeolocation(IGeolocation location)
|
||||||
{
|
{
|
||||||
|
|
|
@ -2,12 +2,19 @@
|
||||||
#nullable enable
|
#nullable enable
|
||||||
#pragma warning disable CS0612, CS0618 // Suppress warnings about [Obsolete] member usage in generated code.
|
#pragma warning disable CS0612, CS0618 // Suppress warnings about [Obsolete] member usage in generated code.
|
||||||
|
|
||||||
/// <summary>Generated helper providing an AOT and linking compatible implementation for configuration binding.</summary>
|
namespace System.Runtime.CompilerServices
|
||||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
|
|
||||||
internal static class GeneratedConfigurationBinder
|
|
||||||
{
|
{
|
||||||
/// <summary>Attempts to bind the configuration instance to a new instance of type T.</summary>
|
using System;
|
||||||
public static T? Get<T>(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.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
|
namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
|
||||||
|
@ -18,11 +25,18 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
|
||||||
/// <summary>Provide core binding logic.</summary>
|
|
||||||
[GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
|
[GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
|
||||||
file static class CoreBindingHelper
|
file static class BindingExtensions
|
||||||
{
|
{
|
||||||
|
#region IConfiguration extensions.
|
||||||
|
/// <summary>Attempts to bind the configuration instance to a new instance of type T.</summary>
|
||||||
|
[InterceptsLocationAttribute(@"src-0.cs", 12, 17)]
|
||||||
|
public static T? Get<T>(this IConfiguration configuration) => (T?)(GetCore(configuration, typeof(T), configureOptions: null) ?? default(T));
|
||||||
|
#endregion IConfiguration extensions.
|
||||||
|
|
||||||
|
#region Core binding extensions.
|
||||||
private readonly static Lazy<HashSet<string>> s_configKeys_ProgramMyClassWithCustomCollections = new(() => new HashSet<string>(StringComparer.OrdinalIgnoreCase) { "CustomDictionary", "CustomList", "IReadOnlyList", "IReadOnlyDictionary" });
|
private readonly static Lazy<HashSet<string>> s_configKeys_ProgramMyClassWithCustomCollections = new(() => new HashSet<string>(StringComparer.OrdinalIgnoreCase) { "CustomDictionary", "CustomList", "IReadOnlyList", "IReadOnlyDictionary" });
|
||||||
|
|
||||||
public static object? GetCore(this IConfiguration configuration, Type type, Action<BinderOptions>? configureOptions)
|
public static object? GetCore(this IConfiguration configuration, Type type, Action<BinderOptions>? configureOptions)
|
||||||
|
@ -46,16 +60,11 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
|
||||||
return obj;
|
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<string, int> obj, BinderOptions? binderOptions)
|
public static void BindCore(IConfiguration configuration, ref Program.CustomDictionary<string, int> obj, BinderOptions? binderOptions)
|
||||||
{
|
{
|
||||||
if (obj is null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(obj));
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (IConfigurationSection section in configuration.GetChildren())
|
foreach (IConfigurationSection section in configuration.GetChildren())
|
||||||
{
|
{
|
||||||
if (section.Value is string value)
|
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)
|
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())
|
foreach (IConfigurationSection section in configuration.GetChildren())
|
||||||
{
|
{
|
||||||
if (section.Value is string value)
|
if (section.Value is string value)
|
||||||
|
@ -83,11 +87,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
|
||||||
|
|
||||||
public static void BindCore(IConfiguration configuration, ref List<int> obj, BinderOptions? binderOptions)
|
public static void BindCore(IConfiguration configuration, ref List<int> obj, BinderOptions? binderOptions)
|
||||||
{
|
{
|
||||||
if (obj is null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(obj));
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (IConfigurationSection section in configuration.GetChildren())
|
foreach (IConfigurationSection section in configuration.GetChildren())
|
||||||
{
|
{
|
||||||
if (section.Value is string value)
|
if (section.Value is string value)
|
||||||
|
@ -99,11 +98,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
|
||||||
|
|
||||||
public static void BindCore(IConfiguration configuration, ref ICollection<int> obj, BinderOptions? binderOptions)
|
public static void BindCore(IConfiguration configuration, ref ICollection<int> obj, BinderOptions? binderOptions)
|
||||||
{
|
{
|
||||||
if (obj is null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(obj));
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (IConfigurationSection section in configuration.GetChildren())
|
foreach (IConfigurationSection section in configuration.GetChildren())
|
||||||
{
|
{
|
||||||
if (section.Value is string value)
|
if (section.Value is string value)
|
||||||
|
@ -115,11 +109,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
|
||||||
|
|
||||||
public static void BindCore(IConfiguration configuration, ref IReadOnlyList<int> obj, BinderOptions? binderOptions)
|
public static void BindCore(IConfiguration configuration, ref IReadOnlyList<int> obj, BinderOptions? binderOptions)
|
||||||
{
|
{
|
||||||
if (obj is null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(obj));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (obj is not ICollection<int> temp)
|
if (obj is not ICollection<int> temp)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
|
@ -136,11 +125,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
|
||||||
|
|
||||||
public static void BindCore(IConfiguration configuration, ref Dictionary<string, int> obj, BinderOptions? binderOptions)
|
public static void BindCore(IConfiguration configuration, ref Dictionary<string, int> obj, BinderOptions? binderOptions)
|
||||||
{
|
{
|
||||||
if (obj is null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(obj));
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (IConfigurationSection section in configuration.GetChildren())
|
foreach (IConfigurationSection section in configuration.GetChildren())
|
||||||
{
|
{
|
||||||
if (section.Value is string value)
|
if (section.Value is string value)
|
||||||
|
@ -152,11 +136,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
|
||||||
|
|
||||||
public static void BindCore(IConfiguration configuration, ref IDictionary<string, int> obj, BinderOptions? binderOptions)
|
public static void BindCore(IConfiguration configuration, ref IDictionary<string, int> obj, BinderOptions? binderOptions)
|
||||||
{
|
{
|
||||||
if (obj is null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(obj));
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (IConfigurationSection section in configuration.GetChildren())
|
foreach (IConfigurationSection section in configuration.GetChildren())
|
||||||
{
|
{
|
||||||
if (section.Value is string value)
|
if (section.Value is string value)
|
||||||
|
@ -168,11 +147,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
|
||||||
|
|
||||||
public static void BindCore(IConfiguration configuration, ref IReadOnlyDictionary<string, int> obj, BinderOptions? binderOptions)
|
public static void BindCore(IConfiguration configuration, ref IReadOnlyDictionary<string, int> obj, BinderOptions? binderOptions)
|
||||||
{
|
{
|
||||||
if (obj is null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(obj));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (obj is not IDictionary<string, int> temp)
|
if (obj is not IDictionary<string, int> temp)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
|
@ -189,11 +163,6 @@ 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 obj, BinderOptions? binderOptions)
|
||||||
{
|
{
|
||||||
if (obj is null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(obj));
|
|
||||||
}
|
|
||||||
|
|
||||||
ValidateConfigurationKeys(typeof(Program.MyClassWithCustomCollections), s_configKeys_ProgramMyClassWithCustomCollections, configuration, binderOptions);
|
ValidateConfigurationKeys(typeof(Program.MyClassWithCustomCollections), s_configKeys_ProgramMyClassWithCustomCollections, configuration, binderOptions);
|
||||||
|
|
||||||
if (AsConfigWithChildren(configuration.GetSection("CustomDictionary")) is IConfigurationSection section1)
|
if (AsConfigWithChildren(configuration.GetSection("CustomDictionary")) is IConfigurationSection section1)
|
||||||
|
@ -229,6 +198,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// <summary>If required by the binder options, validates that there are no unknown keys in the input configuration object.</summary>
|
/// <summary>If required by the binder options, validates that there are no unknown keys in the input configuration object.</summary>
|
||||||
public static void ValidateConfigurationKeys(Type type, Lazy<HashSet<string>> keys, IConfiguration configuration, BinderOptions? binderOptions)
|
public static void ValidateConfigurationKeys(Type type, Lazy<HashSet<string>> keys, IConfiguration configuration, BinderOptions? binderOptions)
|
||||||
{
|
{
|
||||||
|
@ -281,7 +251,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
|
||||||
|
|
||||||
if (binderOptions.BindNonPublicProperties)
|
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;
|
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);
|
throw new InvalidOperationException($"Failed to convert configuration value at '{getPath()}' to type '{typeof(int)}'.", exception);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endregion Core binding extensions.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,18 +2,19 @@
|
||||||
#nullable enable
|
#nullable enable
|
||||||
#pragma warning disable CS0612, CS0618 // Suppress warnings about [Obsolete] member usage in generated code.
|
#pragma warning disable CS0612, CS0618 // Suppress warnings about [Obsolete] member usage in generated code.
|
||||||
|
|
||||||
/// <summary>Generated helper providing an AOT and linking compatible implementation for configuration binding.</summary>
|
namespace System.Runtime.CompilerServices
|
||||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
|
|
||||||
internal static class GeneratedConfigurationBinder
|
|
||||||
{
|
{
|
||||||
/// <summary>Attempts to bind the given object instance to configuration values by matching property names against configuration keys recursively.</summary>
|
using System;
|
||||||
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.CodeDom.Compiler;
|
||||||
|
|
||||||
/// <summary>Attempts to bind the given object instance to configuration values by matching property names against configuration keys recursively.</summary>
|
[GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
|
||||||
public static void Bind(this global::Microsoft.Extensions.Configuration.IConfiguration configuration, global::Program.MyClass obj, global::System.Action<global::Microsoft.Extensions.Configuration.BinderOptions>? configureOptions) => global::Microsoft.Extensions.Configuration.Binder.SourceGeneration.CoreBindingHelper.BindCore(configuration, ref obj, global::Microsoft.Extensions.Configuration.Binder.SourceGeneration.CoreBindingHelper.GetBinderOptions(configureOptions));
|
[AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]
|
||||||
|
file sealed class InterceptsLocationAttribute : Attribute
|
||||||
/// <summary>Attempts to bind the given object instance to configuration values by matching property names against configuration keys recursively.</summary>
|
{
|
||||||
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);
|
public InterceptsLocationAttribute(string filePath, int line, int column)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
|
namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
|
||||||
|
@ -23,20 +24,72 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
|
||||||
using System.CodeDom.Compiler;
|
using System.CodeDom.Compiler;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
|
||||||
/// <summary>Provide core binding logic.</summary>
|
|
||||||
[GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
|
[GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
|
||||||
file static class CoreBindingHelper
|
file static class BindingExtensions
|
||||||
{
|
{
|
||||||
private readonly static Lazy<HashSet<string>> s_configKeys_ProgramMyClass = new(() => new HashSet<string>(StringComparer.OrdinalIgnoreCase) { "MyString", "MyInt", "MyList", "MyDictionary", "MyComplexDictionary" });
|
#region IConfiguration extensions.
|
||||||
|
/// <summary>Attempts to bind the given object instance to configuration values by matching property names against configuration keys recursively.</summary>
|
||||||
public static void BindCore(IConfiguration configuration, ref List<int> obj, BinderOptions? binderOptions)
|
[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)
|
if (obj is null)
|
||||||
{
|
{
|
||||||
throw new ArgumentNullException(nameof(obj));
|
throw new ArgumentNullException(nameof(obj));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var typedObj = (Program.MyClass)obj;
|
||||||
|
BindCore(configuration, ref typedObj, binderOptions: null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Attempts to bind the given object instance to configuration values by matching property names against configuration keys recursively.</summary>
|
||||||
|
[InterceptsLocationAttribute(@"src-0.cs", 14, 24)]
|
||||||
|
public static void Bind_ProgramMyClass(this IConfiguration configuration, object? obj, Action<BinderOptions>? 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));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Attempts to bind the given object instance to configuration values by matching property names against configuration keys recursively.</summary>
|
||||||
|
[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<HashSet<string>> s_configKeys_ProgramMyClass = new(() => new HashSet<string>(StringComparer.OrdinalIgnoreCase) { "MyString", "MyInt", "MyList", "MyDictionary", "MyComplexDictionary" });
|
||||||
|
|
||||||
|
public static void BindCore(IConfiguration configuration, ref List<int> obj, BinderOptions? binderOptions)
|
||||||
|
{
|
||||||
foreach (IConfigurationSection section in configuration.GetChildren())
|
foreach (IConfigurationSection section in configuration.GetChildren())
|
||||||
{
|
{
|
||||||
if (section.Value is string value)
|
if (section.Value is string value)
|
||||||
|
@ -48,11 +101,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
|
||||||
|
|
||||||
public static void BindCore(IConfiguration configuration, ref Dictionary<string, string> obj, BinderOptions? binderOptions)
|
public static void BindCore(IConfiguration configuration, ref Dictionary<string, string> obj, BinderOptions? binderOptions)
|
||||||
{
|
{
|
||||||
if (obj is null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(obj));
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (IConfigurationSection section in configuration.GetChildren())
|
foreach (IConfigurationSection section in configuration.GetChildren())
|
||||||
{
|
{
|
||||||
if (section.Value is string value)
|
if (section.Value is string value)
|
||||||
|
@ -64,11 +112,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
|
||||||
|
|
||||||
public static void BindCore(IConfiguration configuration, ref Dictionary<string, Program.MyClass2> obj, BinderOptions? binderOptions)
|
public static void BindCore(IConfiguration configuration, ref Dictionary<string, Program.MyClass2> obj, BinderOptions? binderOptions)
|
||||||
{
|
{
|
||||||
if (obj is null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(obj));
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (IConfigurationSection section in configuration.GetChildren())
|
foreach (IConfigurationSection section in configuration.GetChildren())
|
||||||
{
|
{
|
||||||
if (!(obj.TryGetValue(section.Key, out Program.MyClass2? element) && element is not null))
|
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)
|
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);
|
ValidateConfigurationKeys(typeof(Program.MyClass), s_configKeys_ProgramMyClass, configuration, binderOptions);
|
||||||
|
|
||||||
obj.MyString = configuration["MyString"]!;
|
obj.MyString = configuration["MyString"]!;
|
||||||
|
@ -120,6 +158,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// <summary>If required by the binder options, validates that there are no unknown keys in the input configuration object.</summary>
|
/// <summary>If required by the binder options, validates that there are no unknown keys in the input configuration object.</summary>
|
||||||
public static void ValidateConfigurationKeys(Type type, Lazy<HashSet<string>> keys, IConfiguration configuration, BinderOptions? binderOptions)
|
public static void ValidateConfigurationKeys(Type type, Lazy<HashSet<string>> keys, IConfiguration configuration, BinderOptions? binderOptions)
|
||||||
{
|
{
|
||||||
|
@ -163,7 +202,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
|
||||||
|
|
||||||
if (binderOptions.BindNonPublicProperties)
|
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;
|
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);
|
throw new InvalidOperationException($"Failed to convert configuration value at '{getPath()}' to type '{typeof(int)}'.", exception);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endregion Core binding extensions.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,12 +2,19 @@
|
||||||
#nullable enable
|
#nullable enable
|
||||||
#pragma warning disable CS0612, CS0618 // Suppress warnings about [Obsolete] member usage in generated code.
|
#pragma warning disable CS0612, CS0618 // Suppress warnings about [Obsolete] member usage in generated code.
|
||||||
|
|
||||||
/// <summary>Generated helper providing an AOT and linking compatible implementation for configuration binding.</summary>
|
namespace System.Runtime.CompilerServices
|
||||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
|
|
||||||
internal static class GeneratedConfigurationBinder
|
|
||||||
{
|
{
|
||||||
/// <summary>Attempts to bind the given object instance to configuration values by matching property names against configuration keys recursively.</summary>
|
using System;
|
||||||
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.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
|
namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
|
||||||
|
@ -17,20 +24,36 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
|
||||||
using System.CodeDom.Compiler;
|
using System.CodeDom.Compiler;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
|
||||||
/// <summary>Provide core binding logic.</summary>
|
|
||||||
[GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
|
[GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
|
||||||
file static class CoreBindingHelper
|
file static class BindingExtensions
|
||||||
{
|
{
|
||||||
private readonly static Lazy<HashSet<string>> s_configKeys_ProgramMyClass = new(() => new HashSet<string>(StringComparer.OrdinalIgnoreCase) { "MyString", "MyInt", "MyList", "MyDictionary", "MyComplexDictionary" });
|
#region IConfiguration extensions.
|
||||||
|
/// <summary>Attempts to bind the given object instance to configuration values by matching property names against configuration keys recursively.</summary>
|
||||||
public static void BindCore(IConfiguration configuration, ref List<int> obj, BinderOptions? binderOptions)
|
[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)
|
if (obj is null)
|
||||||
{
|
{
|
||||||
throw new ArgumentNullException(nameof(obj));
|
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<HashSet<string>> s_configKeys_ProgramMyClass = new(() => new HashSet<string>(StringComparer.OrdinalIgnoreCase) { "MyString", "MyInt", "MyList", "MyDictionary", "MyComplexDictionary" });
|
||||||
|
|
||||||
|
public static void BindCore(IConfiguration configuration, ref List<int> obj, BinderOptions? binderOptions)
|
||||||
|
{
|
||||||
foreach (IConfigurationSection section in configuration.GetChildren())
|
foreach (IConfigurationSection section in configuration.GetChildren())
|
||||||
{
|
{
|
||||||
if (section.Value is string value)
|
if (section.Value is string value)
|
||||||
|
@ -42,11 +65,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
|
||||||
|
|
||||||
public static void BindCore(IConfiguration configuration, ref Dictionary<string, string> obj, BinderOptions? binderOptions)
|
public static void BindCore(IConfiguration configuration, ref Dictionary<string, string> obj, BinderOptions? binderOptions)
|
||||||
{
|
{
|
||||||
if (obj is null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(obj));
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (IConfigurationSection section in configuration.GetChildren())
|
foreach (IConfigurationSection section in configuration.GetChildren())
|
||||||
{
|
{
|
||||||
if (section.Value is string value)
|
if (section.Value is string value)
|
||||||
|
@ -58,11 +76,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
|
||||||
|
|
||||||
public static void BindCore(IConfiguration configuration, ref Dictionary<string, Program.MyClass2> obj, BinderOptions? binderOptions)
|
public static void BindCore(IConfiguration configuration, ref Dictionary<string, Program.MyClass2> obj, BinderOptions? binderOptions)
|
||||||
{
|
{
|
||||||
if (obj is null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(obj));
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (IConfigurationSection section in configuration.GetChildren())
|
foreach (IConfigurationSection section in configuration.GetChildren())
|
||||||
{
|
{
|
||||||
if (!(obj.TryGetValue(section.Key, out Program.MyClass2? element) && element is not null))
|
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)
|
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);
|
ValidateConfigurationKeys(typeof(Program.MyClass), s_configKeys_ProgramMyClass, configuration, binderOptions);
|
||||||
|
|
||||||
obj.MyString = configuration["MyString"]!;
|
obj.MyString = configuration["MyString"]!;
|
||||||
|
@ -114,6 +122,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// <summary>If required by the binder options, validates that there are no unknown keys in the input configuration object.</summary>
|
/// <summary>If required by the binder options, validates that there are no unknown keys in the input configuration object.</summary>
|
||||||
public static void ValidateConfigurationKeys(Type type, Lazy<HashSet<string>> keys, IConfiguration configuration, BinderOptions? binderOptions)
|
public static void ValidateConfigurationKeys(Type type, Lazy<HashSet<string>> 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);
|
throw new InvalidOperationException($"Failed to convert configuration value at '{getPath()}' to type '{typeof(int)}'.", exception);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endregion Core binding extensions.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,12 +2,19 @@
|
||||||
#nullable enable
|
#nullable enable
|
||||||
#pragma warning disable CS0612, CS0618 // Suppress warnings about [Obsolete] member usage in generated code.
|
#pragma warning disable CS0612, CS0618 // Suppress warnings about [Obsolete] member usage in generated code.
|
||||||
|
|
||||||
/// <summary>Generated helper providing an AOT and linking compatible implementation for configuration binding.</summary>
|
namespace System.Runtime.CompilerServices
|
||||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
|
|
||||||
internal static class GeneratedConfigurationBinder
|
|
||||||
{
|
{
|
||||||
/// <summary>Attempts to bind the given object instance to configuration values by matching property names against configuration keys recursively.</summary>
|
using System;
|
||||||
public static void Bind(this global::Microsoft.Extensions.Configuration.IConfiguration configuration, global::Program.MyClass obj, global::System.Action<global::Microsoft.Extensions.Configuration.BinderOptions>? configureOptions) => global::Microsoft.Extensions.Configuration.Binder.SourceGeneration.CoreBindingHelper.BindCore(configuration, ref obj, global::Microsoft.Extensions.Configuration.Binder.SourceGeneration.CoreBindingHelper.GetBinderOptions(configureOptions));
|
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
|
namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
|
||||||
|
@ -17,20 +24,36 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
|
||||||
using System.CodeDom.Compiler;
|
using System.CodeDom.Compiler;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
|
||||||
/// <summary>Provide core binding logic.</summary>
|
|
||||||
[GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
|
[GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
|
||||||
file static class CoreBindingHelper
|
file static class BindingExtensions
|
||||||
{
|
{
|
||||||
private readonly static Lazy<HashSet<string>> s_configKeys_ProgramMyClass = new(() => new HashSet<string>(StringComparer.OrdinalIgnoreCase) { "MyString", "MyInt", "MyList", "MyDictionary", "MyComplexDictionary" });
|
#region IConfiguration extensions.
|
||||||
|
/// <summary>Attempts to bind the given object instance to configuration values by matching property names against configuration keys recursively.</summary>
|
||||||
public static void BindCore(IConfiguration configuration, ref List<int> obj, BinderOptions? binderOptions)
|
[InterceptsLocationAttribute(@"src-0.cs", 12, 20)]
|
||||||
|
public static void Bind_ProgramMyClass(this IConfiguration configuration, object? obj, Action<BinderOptions>? configureOptions)
|
||||||
{
|
{
|
||||||
|
if (configuration is null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(configuration));
|
||||||
|
}
|
||||||
|
|
||||||
if (obj is null)
|
if (obj is null)
|
||||||
{
|
{
|
||||||
throw new ArgumentNullException(nameof(obj));
|
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<HashSet<string>> s_configKeys_ProgramMyClass = new(() => new HashSet<string>(StringComparer.OrdinalIgnoreCase) { "MyString", "MyInt", "MyList", "MyDictionary", "MyComplexDictionary" });
|
||||||
|
|
||||||
|
public static void BindCore(IConfiguration configuration, ref List<int> obj, BinderOptions? binderOptions)
|
||||||
|
{
|
||||||
foreach (IConfigurationSection section in configuration.GetChildren())
|
foreach (IConfigurationSection section in configuration.GetChildren())
|
||||||
{
|
{
|
||||||
if (section.Value is string value)
|
if (section.Value is string value)
|
||||||
|
@ -42,11 +65,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
|
||||||
|
|
||||||
public static void BindCore(IConfiguration configuration, ref Dictionary<string, string> obj, BinderOptions? binderOptions)
|
public static void BindCore(IConfiguration configuration, ref Dictionary<string, string> obj, BinderOptions? binderOptions)
|
||||||
{
|
{
|
||||||
if (obj is null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(obj));
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (IConfigurationSection section in configuration.GetChildren())
|
foreach (IConfigurationSection section in configuration.GetChildren())
|
||||||
{
|
{
|
||||||
if (section.Value is string value)
|
if (section.Value is string value)
|
||||||
|
@ -58,11 +76,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
|
||||||
|
|
||||||
public static void BindCore(IConfiguration configuration, ref Dictionary<string, Program.MyClass2> obj, BinderOptions? binderOptions)
|
public static void BindCore(IConfiguration configuration, ref Dictionary<string, Program.MyClass2> obj, BinderOptions? binderOptions)
|
||||||
{
|
{
|
||||||
if (obj is null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(obj));
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (IConfigurationSection section in configuration.GetChildren())
|
foreach (IConfigurationSection section in configuration.GetChildren())
|
||||||
{
|
{
|
||||||
if (!(obj.TryGetValue(section.Key, out Program.MyClass2? element) && element is not null))
|
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)
|
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);
|
ValidateConfigurationKeys(typeof(Program.MyClass), s_configKeys_ProgramMyClass, configuration, binderOptions);
|
||||||
|
|
||||||
obj.MyString = configuration["MyString"]!;
|
obj.MyString = configuration["MyString"]!;
|
||||||
|
@ -114,6 +122,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// <summary>If required by the binder options, validates that there are no unknown keys in the input configuration object.</summary>
|
/// <summary>If required by the binder options, validates that there are no unknown keys in the input configuration object.</summary>
|
||||||
public static void ValidateConfigurationKeys(Type type, Lazy<HashSet<string>> keys, IConfiguration configuration, BinderOptions? binderOptions)
|
public static void ValidateConfigurationKeys(Type type, Lazy<HashSet<string>> keys, IConfiguration configuration, BinderOptions? binderOptions)
|
||||||
{
|
{
|
||||||
|
@ -157,7 +166,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
|
||||||
|
|
||||||
if (binderOptions.BindNonPublicProperties)
|
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;
|
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);
|
throw new InvalidOperationException($"Failed to convert configuration value at '{getPath()}' to type '{typeof(int)}'.", exception);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endregion Core binding extensions.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,12 +2,19 @@
|
||||||
#nullable enable
|
#nullable enable
|
||||||
#pragma warning disable CS0612, CS0618 // Suppress warnings about [Obsolete] member usage in generated code.
|
#pragma warning disable CS0612, CS0618 // Suppress warnings about [Obsolete] member usage in generated code.
|
||||||
|
|
||||||
/// <summary>Generated helper providing an AOT and linking compatible implementation for configuration binding.</summary>
|
namespace System.Runtime.CompilerServices
|
||||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
|
|
||||||
internal static class GeneratedConfigurationBinder
|
|
||||||
{
|
{
|
||||||
/// <summary>Attempts to bind the given object instance to configuration values by matching property names against configuration keys recursively.</summary>
|
using System;
|
||||||
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.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
|
namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
|
||||||
|
@ -17,20 +24,36 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
|
||||||
using System.CodeDom.Compiler;
|
using System.CodeDom.Compiler;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
|
||||||
/// <summary>Provide core binding logic.</summary>
|
|
||||||
[GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
|
[GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
|
||||||
file static class CoreBindingHelper
|
file static class BindingExtensions
|
||||||
{
|
{
|
||||||
private readonly static Lazy<HashSet<string>> s_configKeys_ProgramMyClass = new(() => new HashSet<string>(StringComparer.OrdinalIgnoreCase) { "MyString", "MyInt", "MyList", "MyDictionary", "MyComplexDictionary" });
|
#region IConfiguration extensions.
|
||||||
|
/// <summary>Attempts to bind the given object instance to configuration values by matching property names against configuration keys recursively.</summary>
|
||||||
public static void BindCore(IConfiguration configuration, ref List<int> obj, BinderOptions? binderOptions)
|
[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)
|
if (obj is null)
|
||||||
{
|
{
|
||||||
throw new ArgumentNullException(nameof(obj));
|
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<HashSet<string>> s_configKeys_ProgramMyClass = new(() => new HashSet<string>(StringComparer.OrdinalIgnoreCase) { "MyString", "MyInt", "MyList", "MyDictionary", "MyComplexDictionary" });
|
||||||
|
|
||||||
|
public static void BindCore(IConfiguration configuration, ref List<int> obj, BinderOptions? binderOptions)
|
||||||
|
{
|
||||||
foreach (IConfigurationSection section in configuration.GetChildren())
|
foreach (IConfigurationSection section in configuration.GetChildren())
|
||||||
{
|
{
|
||||||
if (section.Value is string value)
|
if (section.Value is string value)
|
||||||
|
@ -42,11 +65,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
|
||||||
|
|
||||||
public static void BindCore(IConfiguration configuration, ref Dictionary<string, string> obj, BinderOptions? binderOptions)
|
public static void BindCore(IConfiguration configuration, ref Dictionary<string, string> obj, BinderOptions? binderOptions)
|
||||||
{
|
{
|
||||||
if (obj is null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(obj));
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (IConfigurationSection section in configuration.GetChildren())
|
foreach (IConfigurationSection section in configuration.GetChildren())
|
||||||
{
|
{
|
||||||
if (section.Value is string value)
|
if (section.Value is string value)
|
||||||
|
@ -58,11 +76,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
|
||||||
|
|
||||||
public static void BindCore(IConfiguration configuration, ref Dictionary<string, Program.MyClass2> obj, BinderOptions? binderOptions)
|
public static void BindCore(IConfiguration configuration, ref Dictionary<string, Program.MyClass2> obj, BinderOptions? binderOptions)
|
||||||
{
|
{
|
||||||
if (obj is null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(obj));
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (IConfigurationSection section in configuration.GetChildren())
|
foreach (IConfigurationSection section in configuration.GetChildren())
|
||||||
{
|
{
|
||||||
if (!(obj.TryGetValue(section.Key, out Program.MyClass2? element) && element is not null))
|
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)
|
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);
|
ValidateConfigurationKeys(typeof(Program.MyClass), s_configKeys_ProgramMyClass, configuration, binderOptions);
|
||||||
|
|
||||||
obj.MyString = configuration["MyString"]!;
|
obj.MyString = configuration["MyString"]!;
|
||||||
|
@ -114,6 +122,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// <summary>If required by the binder options, validates that there are no unknown keys in the input configuration object.</summary>
|
/// <summary>If required by the binder options, validates that there are no unknown keys in the input configuration object.</summary>
|
||||||
public static void ValidateConfigurationKeys(Type type, Lazy<HashSet<string>> keys, IConfiguration configuration, BinderOptions? binderOptions)
|
public static void ValidateConfigurationKeys(Type type, Lazy<HashSet<string>> 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);
|
throw new InvalidOperationException($"Failed to convert configuration value at '{getPath()}' to type '{typeof(int)}'.", exception);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endregion Core binding extensions.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,21 +2,19 @@
|
||||||
#nullable enable
|
#nullable enable
|
||||||
#pragma warning disable CS0612, CS0618 // Suppress warnings about [Obsolete] member usage in generated code.
|
#pragma warning disable CS0612, CS0618 // Suppress warnings about [Obsolete] member usage in generated code.
|
||||||
|
|
||||||
/// <summary>Generated helper providing an AOT and linking compatible implementation for configuration binding.</summary>
|
namespace System.Runtime.CompilerServices
|
||||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
|
|
||||||
internal static class GeneratedConfigurationBinder
|
|
||||||
{
|
{
|
||||||
/// <summary>Attempts to bind the configuration instance to a new instance of type T.</summary>
|
using System;
|
||||||
public static T? Get<T>(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.CodeDom.Compiler;
|
||||||
|
|
||||||
/// <summary>Attempts to bind the configuration instance to a new instance of type T.</summary>
|
[GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
|
||||||
public static T? Get<T>(this global::Microsoft.Extensions.Configuration.IConfiguration configuration, global::System.Action<global::Microsoft.Extensions.Configuration.BinderOptions>? configureOptions) => (T?)(global::Microsoft.Extensions.Configuration.Binder.SourceGeneration.CoreBindingHelper.GetCore(configuration, typeof(T), configureOptions) ?? default(T));
|
[AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]
|
||||||
|
file sealed class InterceptsLocationAttribute : Attribute
|
||||||
/// <summary>Attempts to bind the configuration instance to a new instance of type T.</summary>
|
{
|
||||||
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);
|
public InterceptsLocationAttribute(string filePath, int line, int column)
|
||||||
|
{
|
||||||
/// <summary>Attempts to bind the configuration instance to a new instance of type T.</summary>
|
}
|
||||||
public static object? Get(this global::Microsoft.Extensions.Configuration.IConfiguration configuration, global::System.Type type, global::System.Action<global::Microsoft.Extensions.Configuration.BinderOptions>? configureOptions) => global::Microsoft.Extensions.Configuration.Binder.SourceGeneration.CoreBindingHelper.GetCore(configuration, type, configureOptions);
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
|
namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
|
||||||
|
@ -26,11 +24,30 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
|
||||||
using System.CodeDom.Compiler;
|
using System.CodeDom.Compiler;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
|
||||||
/// <summary>Provide core binding logic.</summary>
|
|
||||||
[GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
|
[GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
|
||||||
file static class CoreBindingHelper
|
file static class BindingExtensions
|
||||||
{
|
{
|
||||||
|
#region IConfiguration extensions.
|
||||||
|
/// <summary>Attempts to bind the configuration instance to a new instance of type T.</summary>
|
||||||
|
[InterceptsLocationAttribute(@"src-0.cs", 12, 38)]
|
||||||
|
public static T? Get<T>(this IConfiguration configuration) => (T?)(GetCore(configuration, typeof(T), configureOptions: null) ?? default(T));
|
||||||
|
|
||||||
|
/// <summary>Attempts to bind the configuration instance to a new instance of type T.</summary>
|
||||||
|
[InterceptsLocationAttribute(@"src-0.cs", 14, 36)]
|
||||||
|
public static T? Get<T>(this IConfiguration configuration, Action<BinderOptions>? configureOptions) => (T?)(GetCore(configuration, typeof(T), configureOptions) ?? default(T));
|
||||||
|
|
||||||
|
/// <summary>Attempts to bind the configuration instance to a new instance of type T.</summary>
|
||||||
|
[InterceptsLocationAttribute(@"src-0.cs", 13, 36)]
|
||||||
|
public static object? Get(this IConfiguration configuration, Type type) => GetCore(configuration, type, configureOptions: null);
|
||||||
|
|
||||||
|
/// <summary>Attempts to bind the configuration instance to a new instance of type T.</summary>
|
||||||
|
[InterceptsLocationAttribute(@"src-0.cs", 15, 36)]
|
||||||
|
public static object? Get(this IConfiguration configuration, Type type, Action<BinderOptions>? configureOptions) => GetCore(configuration, type, configureOptions);
|
||||||
|
#endregion IConfiguration extensions.
|
||||||
|
|
||||||
|
#region Core binding extensions.
|
||||||
private readonly static Lazy<HashSet<string>> s_configKeys_ProgramMyClass = new(() => new HashSet<string>(StringComparer.OrdinalIgnoreCase) { "MyString", "MyInt", "MyList", "MyArray", "MyDictionary" });
|
private readonly static Lazy<HashSet<string>> s_configKeys_ProgramMyClass = new(() => new HashSet<string>(StringComparer.OrdinalIgnoreCase) { "MyString", "MyInt", "MyList", "MyArray", "MyDictionary" });
|
||||||
private readonly static Lazy<HashSet<string>> s_configKeys_ProgramMyClass2 = new(() => new HashSet<string>(StringComparer.OrdinalIgnoreCase) { "MyInt" });
|
private readonly static Lazy<HashSet<string>> s_configKeys_ProgramMyClass2 = new(() => new HashSet<string>(StringComparer.OrdinalIgnoreCase) { "MyInt" });
|
||||||
|
|
||||||
|
@ -54,24 +71,18 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
|
||||||
BindCore(configuration, ref obj, binderOptions);
|
BindCore(configuration, ref obj, binderOptions);
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
|
else if (type == typeof(Program.MyClass2))
|
||||||
if (type == typeof(Program.MyClass2))
|
|
||||||
{
|
{
|
||||||
var obj = new Program.MyClass2();
|
var obj = new Program.MyClass2();
|
||||||
BindCore(configuration, ref obj, binderOptions);
|
BindCore(configuration, ref obj, binderOptions);
|
||||||
return obj;
|
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<int> obj, BinderOptions? binderOptions)
|
public static void BindCore(IConfiguration configuration, ref List<int> obj, BinderOptions? binderOptions)
|
||||||
{
|
{
|
||||||
if (obj is null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(obj));
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (IConfigurationSection section in configuration.GetChildren())
|
foreach (IConfigurationSection section in configuration.GetChildren())
|
||||||
{
|
{
|
||||||
if (section.Value is string value)
|
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)
|
public static void BindCore(IConfiguration configuration, ref int[] obj, BinderOptions? binderOptions)
|
||||||
{
|
{
|
||||||
if (obj is null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(obj));
|
|
||||||
}
|
|
||||||
|
|
||||||
var temp2 = new List<int>();
|
var temp2 = new List<int>();
|
||||||
BindCore(configuration, ref temp2, binderOptions);
|
BindCore(configuration, ref temp2, binderOptions);
|
||||||
int originalCount = obj.Length;
|
int originalCount = obj.Length;
|
||||||
|
@ -97,11 +103,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
|
||||||
|
|
||||||
public static void BindCore(IConfiguration configuration, ref Dictionary<string, string> obj, BinderOptions? binderOptions)
|
public static void BindCore(IConfiguration configuration, ref Dictionary<string, string> obj, BinderOptions? binderOptions)
|
||||||
{
|
{
|
||||||
if (obj is null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(obj));
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (IConfigurationSection section in configuration.GetChildren())
|
foreach (IConfigurationSection section in configuration.GetChildren())
|
||||||
{
|
{
|
||||||
if (section.Value is string value)
|
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)
|
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);
|
ValidateConfigurationKeys(typeof(Program.MyClass), s_configKeys_ProgramMyClass, configuration, binderOptions);
|
||||||
|
|
||||||
obj.MyString = configuration["MyString"]!;
|
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)
|
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);
|
ValidateConfigurationKeys(typeof(Program.MyClass2), s_configKeys_ProgramMyClass2, configuration, binderOptions);
|
||||||
|
|
||||||
if (configuration["MyInt"] is string value15)
|
if (configuration["MyInt"] is string value15)
|
||||||
|
@ -167,6 +158,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// <summary>If required by the binder options, validates that there are no unknown keys in the input configuration object.</summary>
|
/// <summary>If required by the binder options, validates that there are no unknown keys in the input configuration object.</summary>
|
||||||
public static void ValidateConfigurationKeys(Type type, Lazy<HashSet<string>> keys, IConfiguration configuration, BinderOptions? binderOptions)
|
public static void ValidateConfigurationKeys(Type type, Lazy<HashSet<string>> keys, IConfiguration configuration, BinderOptions? binderOptions)
|
||||||
{
|
{
|
||||||
|
@ -219,7 +211,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
|
||||||
|
|
||||||
if (binderOptions.BindNonPublicProperties)
|
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;
|
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);
|
throw new InvalidOperationException($"Failed to convert configuration value at '{getPath()}' to type '{typeof(int)}'.", exception);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endregion Core binding extensions.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,21 +2,19 @@
|
||||||
#nullable enable
|
#nullable enable
|
||||||
#pragma warning disable CS0612, CS0618 // Suppress warnings about [Obsolete] member usage in generated code.
|
#pragma warning disable CS0612, CS0618 // Suppress warnings about [Obsolete] member usage in generated code.
|
||||||
|
|
||||||
/// <summary>Generated helper providing an AOT and linking compatible implementation for configuration binding.</summary>
|
namespace System.Runtime.CompilerServices
|
||||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
|
|
||||||
internal static class GeneratedConfigurationBinder
|
|
||||||
{
|
{
|
||||||
/// <summary>Extracts the value with the specified key and converts it to the specified type.</summary>
|
using System;
|
||||||
public static T? GetValue<T>(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.CodeDom.Compiler;
|
||||||
|
|
||||||
/// <summary>Extracts the value with the specified key and converts it to the specified type.</summary>
|
[GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
|
||||||
public static T? GetValue<T>(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);
|
[AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]
|
||||||
|
file sealed class InterceptsLocationAttribute : Attribute
|
||||||
/// <summary>Extracts the value with the specified key and converts it to the specified type.</summary>
|
{
|
||||||
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);
|
public InterceptsLocationAttribute(string filePath, int line, int column)
|
||||||
|
{
|
||||||
/// <summary>Extracts the value with the specified key and converts it to the specified type.</summary>
|
}
|
||||||
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
|
namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
|
||||||
|
@ -25,11 +23,30 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
|
||||||
using System;
|
using System;
|
||||||
using System.CodeDom.Compiler;
|
using System.CodeDom.Compiler;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
|
||||||
/// <summary>Provide core binding logic.</summary>
|
|
||||||
[GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
|
[GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
|
||||||
file static class CoreBindingHelper
|
file static class BindingExtensions
|
||||||
{
|
{
|
||||||
|
#region IConfiguration extensions.
|
||||||
|
/// <summary>Extracts the value with the specified key and converts it to the specified type.</summary>
|
||||||
|
[InterceptsLocationAttribute(@"src-0.cs", 13, 18)]
|
||||||
|
public static T? GetValue<T>(this IConfiguration configuration, string key) => (T?)(BindingExtensions.GetValueCore(configuration, typeof(T), key) ?? default(T));
|
||||||
|
|
||||||
|
/// <summary>Extracts the value with the specified key and converts it to the specified type.</summary>
|
||||||
|
[InterceptsLocationAttribute(@"src-0.cs", 16, 24)]
|
||||||
|
public static T? GetValue<T>(this IConfiguration configuration, string key, T defaultValue) => (T?)(BindingExtensions.GetValueCore(configuration, typeof(T), key) ?? defaultValue);
|
||||||
|
|
||||||
|
/// <summary>Extracts the value with the specified key and converts it to the specified type.</summary>
|
||||||
|
[InterceptsLocationAttribute(@"src-0.cs", 14, 24)]
|
||||||
|
public static object? GetValue(this IConfiguration configuration, Type type, string key) => BindingExtensions.GetValueCore(configuration, type, key);
|
||||||
|
|
||||||
|
/// <summary>Extracts the value with the specified key and converts it to the specified type.</summary>
|
||||||
|
[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)
|
public static object? GetValueCore(this IConfiguration configuration, Type type, string key)
|
||||||
{
|
{
|
||||||
if (configuration is null)
|
if (configuration is null)
|
||||||
|
@ -48,18 +65,15 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
|
||||||
{
|
{
|
||||||
return ParseInt(value, () => section.Path);
|
return ParseInt(value, () => section.Path);
|
||||||
}
|
}
|
||||||
|
else if (type == typeof(bool?))
|
||||||
if (type == typeof(bool?))
|
|
||||||
{
|
{
|
||||||
return ParseBool(value, () => section.Path);
|
return ParseBool(value, () => section.Path);
|
||||||
}
|
}
|
||||||
|
else if (type == typeof(byte[]))
|
||||||
if (type == typeof(byte[]))
|
|
||||||
{
|
{
|
||||||
return ParseByteArray(value, () => section.Path);
|
return ParseByteArray(value, () => section.Path);
|
||||||
}
|
}
|
||||||
|
else if (type == typeof(CultureInfo))
|
||||||
if (type == typeof(CultureInfo))
|
|
||||||
{
|
{
|
||||||
return ParseCultureInfo(value, () => section.Path);
|
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);
|
throw new InvalidOperationException($"Failed to convert configuration value at '{getPath()}' to type '{typeof(CultureInfo)}'.", exception);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endregion Core binding extensions.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,12 +2,19 @@
|
||||||
#nullable enable
|
#nullable enable
|
||||||
#pragma warning disable CS0612, CS0618 // Suppress warnings about [Obsolete] member usage in generated code.
|
#pragma warning disable CS0612, CS0618 // Suppress warnings about [Obsolete] member usage in generated code.
|
||||||
|
|
||||||
/// <summary>Generated helper providing an AOT and linking compatible implementation for configuration binding.</summary>
|
namespace System.Runtime.CompilerServices
|
||||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
|
|
||||||
internal static class GeneratedConfigurationBinder
|
|
||||||
{
|
{
|
||||||
/// <summary>Extracts the value with the specified key and converts it to the specified type.</summary>
|
using System;
|
||||||
public static T? GetValue<T>(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.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
|
namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
|
||||||
|
@ -16,11 +23,18 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
|
||||||
using System;
|
using System;
|
||||||
using System.CodeDom.Compiler;
|
using System.CodeDom.Compiler;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
|
||||||
/// <summary>Provide core binding logic.</summary>
|
|
||||||
[GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
|
[GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
|
||||||
file static class CoreBindingHelper
|
file static class BindingExtensions
|
||||||
{
|
{
|
||||||
|
#region IConfiguration extensions.
|
||||||
|
/// <summary>Extracts the value with the specified key and converts it to the specified type.</summary>
|
||||||
|
[InterceptsLocationAttribute(@"src-0.cs", 10, 20)]
|
||||||
|
public static T? GetValue<T>(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)
|
public static object? GetValueCore(this IConfiguration configuration, Type type, string key)
|
||||||
{
|
{
|
||||||
if (configuration is null)
|
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);
|
throw new InvalidOperationException($"Failed to convert configuration value at '{getPath()}' to type '{typeof(int)}'.", exception);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endregion Core binding extensions.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,12 +2,19 @@
|
||||||
#nullable enable
|
#nullable enable
|
||||||
#pragma warning disable CS0612, CS0618 // Suppress warnings about [Obsolete] member usage in generated code.
|
#pragma warning disable CS0612, CS0618 // Suppress warnings about [Obsolete] member usage in generated code.
|
||||||
|
|
||||||
/// <summary>Generated helper providing an AOT and linking compatible implementation for configuration binding.</summary>
|
namespace System.Runtime.CompilerServices
|
||||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
|
|
||||||
internal static class GeneratedConfigurationBinder
|
|
||||||
{
|
{
|
||||||
/// <summary>Extracts the value with the specified key and converts it to the specified type.</summary>
|
using System;
|
||||||
public static T? GetValue<T>(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.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
|
namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
|
||||||
|
@ -16,11 +23,18 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
|
||||||
using System;
|
using System;
|
||||||
using System.CodeDom.Compiler;
|
using System.CodeDom.Compiler;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
|
||||||
/// <summary>Provide core binding logic.</summary>
|
|
||||||
[GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
|
[GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
|
||||||
file static class CoreBindingHelper
|
file static class BindingExtensions
|
||||||
{
|
{
|
||||||
|
#region IConfiguration extensions.
|
||||||
|
/// <summary>Extracts the value with the specified key and converts it to the specified type.</summary>
|
||||||
|
[InterceptsLocationAttribute(@"src-0.cs", 12, 20)]
|
||||||
|
public static T? GetValue<T>(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)
|
public static object? GetValueCore(this IConfiguration configuration, Type type, string key)
|
||||||
{
|
{
|
||||||
if (configuration is null)
|
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);
|
throw new InvalidOperationException($"Failed to convert configuration value at '{getPath()}' to type '{typeof(int)}'.", exception);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endregion Core binding extensions.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,12 +2,19 @@
|
||||||
#nullable enable
|
#nullable enable
|
||||||
#pragma warning disable CS0612, CS0618 // Suppress warnings about [Obsolete] member usage in generated code.
|
#pragma warning disable CS0612, CS0618 // Suppress warnings about [Obsolete] member usage in generated code.
|
||||||
|
|
||||||
/// <summary>Generated helper providing an AOT and linking compatible implementation for configuration binding.</summary>
|
namespace System.Runtime.CompilerServices
|
||||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
|
|
||||||
internal static class GeneratedConfigurationBinder
|
|
||||||
{
|
{
|
||||||
/// <summary>Extracts the value with the specified key and converts it to the specified type.</summary>
|
using System;
|
||||||
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.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
|
namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
|
||||||
|
@ -16,11 +23,18 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
|
||||||
using System;
|
using System;
|
||||||
using System.CodeDom.Compiler;
|
using System.CodeDom.Compiler;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
|
||||||
/// <summary>Provide core binding logic.</summary>
|
|
||||||
[GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
|
[GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
|
||||||
file static class CoreBindingHelper
|
file static class BindingExtensions
|
||||||
{
|
{
|
||||||
|
#region IConfiguration extensions.
|
||||||
|
/// <summary>Extracts the value with the specified key and converts it to the specified type.</summary>
|
||||||
|
[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)
|
public static object? GetValueCore(this IConfiguration configuration, Type type, string key)
|
||||||
{
|
{
|
||||||
if (configuration is null)
|
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);
|
throw new InvalidOperationException($"Failed to convert configuration value at '{getPath()}' to type '{typeof(bool)}'.", exception);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endregion Core binding extensions.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,12 +2,19 @@
|
||||||
#nullable enable
|
#nullable enable
|
||||||
#pragma warning disable CS0612, CS0618 // Suppress warnings about [Obsolete] member usage in generated code.
|
#pragma warning disable CS0612, CS0618 // Suppress warnings about [Obsolete] member usage in generated code.
|
||||||
|
|
||||||
/// <summary>Generated helper providing an AOT and linking compatible implementation for configuration binding.</summary>
|
namespace System.Runtime.CompilerServices
|
||||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
|
|
||||||
internal static class GeneratedConfigurationBinder
|
|
||||||
{
|
{
|
||||||
/// <summary>Extracts the value with the specified key and converts it to the specified type.</summary>
|
using System;
|
||||||
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.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
|
namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
|
||||||
|
@ -16,11 +23,18 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
|
||||||
using System;
|
using System;
|
||||||
using System.CodeDom.Compiler;
|
using System.CodeDom.Compiler;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
|
||||||
/// <summary>Provide core binding logic.</summary>
|
|
||||||
[GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
|
[GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
|
||||||
file static class CoreBindingHelper
|
file static class BindingExtensions
|
||||||
{
|
{
|
||||||
|
#region IConfiguration extensions.
|
||||||
|
/// <summary>Extracts the value with the specified key and converts it to the specified type.</summary>
|
||||||
|
[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)
|
public static object? GetValueCore(this IConfiguration configuration, Type type, string key)
|
||||||
{
|
{
|
||||||
if (configuration is null)
|
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);
|
throw new InvalidOperationException($"Failed to convert configuration value at '{getPath()}' to type '{typeof(CultureInfo)}'.", exception);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endregion Core binding extensions.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,12 +2,19 @@
|
||||||
#nullable enable
|
#nullable enable
|
||||||
#pragma warning disable CS0612, CS0618 // Suppress warnings about [Obsolete] member usage in generated code.
|
#pragma warning disable CS0612, CS0618 // Suppress warnings about [Obsolete] member usage in generated code.
|
||||||
|
|
||||||
/// <summary>Generated helper providing an AOT and linking compatible implementation for configuration binding.</summary>
|
namespace System.Runtime.CompilerServices
|
||||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
|
|
||||||
internal static class GeneratedConfigurationBinder
|
|
||||||
{
|
{
|
||||||
/// <summary>Attempts to bind the configuration instance to a new instance of type T.</summary>
|
using System;
|
||||||
public static T? Get<T>(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.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
|
namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
|
||||||
|
@ -17,11 +24,18 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
|
||||||
using System.CodeDom.Compiler;
|
using System.CodeDom.Compiler;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
|
||||||
/// <summary>Provide core binding logic.</summary>
|
|
||||||
[GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
|
[GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
|
||||||
file static class CoreBindingHelper
|
file static class BindingExtensions
|
||||||
{
|
{
|
||||||
|
#region IConfiguration extensions.
|
||||||
|
/// <summary>Attempts to bind the configuration instance to a new instance of type T.</summary>
|
||||||
|
[InterceptsLocationAttribute(@"src-0.cs", 11, 40)]
|
||||||
|
public static T? Get<T>(this IConfiguration configuration) => (T?)(GetCore(configuration, typeof(T), configureOptions: null) ?? default(T));
|
||||||
|
#endregion IConfiguration extensions.
|
||||||
|
|
||||||
|
#region Core binding extensions.
|
||||||
private readonly static Lazy<HashSet<string>> s_configKeys_ProgramMyClass = new(() => new HashSet<string>(StringComparer.OrdinalIgnoreCase) { "MyString", "MyInt", "MyList", "MyArray", "MyDictionary" });
|
private readonly static Lazy<HashSet<string>> s_configKeys_ProgramMyClass = new(() => new HashSet<string>(StringComparer.OrdinalIgnoreCase) { "MyString", "MyInt", "MyList", "MyArray", "MyDictionary" });
|
||||||
|
|
||||||
public static object? GetCore(this IConfiguration configuration, Type type, Action<BinderOptions>? configureOptions)
|
public static object? GetCore(this IConfiguration configuration, Type type, Action<BinderOptions>? configureOptions)
|
||||||
|
@ -45,16 +59,11 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
|
||||||
return obj;
|
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<int> obj, BinderOptions? binderOptions)
|
public static void BindCore(IConfiguration configuration, ref List<int> obj, BinderOptions? binderOptions)
|
||||||
{
|
{
|
||||||
if (obj is null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(obj));
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (IConfigurationSection section in configuration.GetChildren())
|
foreach (IConfigurationSection section in configuration.GetChildren())
|
||||||
{
|
{
|
||||||
if (section.Value is string value)
|
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)
|
public static void BindCore(IConfiguration configuration, ref int[] obj, BinderOptions? binderOptions)
|
||||||
{
|
{
|
||||||
if (obj is null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(obj));
|
|
||||||
}
|
|
||||||
|
|
||||||
var temp1 = new List<int>();
|
var temp1 = new List<int>();
|
||||||
BindCore(configuration, ref temp1, binderOptions);
|
BindCore(configuration, ref temp1, binderOptions);
|
||||||
int originalCount = obj.Length;
|
int originalCount = obj.Length;
|
||||||
|
@ -80,11 +84,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
|
||||||
|
|
||||||
public static void BindCore(IConfiguration configuration, ref Dictionary<string, string> obj, BinderOptions? binderOptions)
|
public static void BindCore(IConfiguration configuration, ref Dictionary<string, string> obj, BinderOptions? binderOptions)
|
||||||
{
|
{
|
||||||
if (obj is null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(obj));
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (IConfigurationSection section in configuration.GetChildren())
|
foreach (IConfigurationSection section in configuration.GetChildren())
|
||||||
{
|
{
|
||||||
if (section.Value is string value)
|
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)
|
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);
|
ValidateConfigurationKeys(typeof(Program.MyClass), s_configKeys_ProgramMyClass, configuration, binderOptions);
|
||||||
|
|
||||||
obj.MyString = configuration["MyString"]!;
|
obj.MyString = configuration["MyString"]!;
|
||||||
|
@ -135,6 +129,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// <summary>If required by the binder options, validates that there are no unknown keys in the input configuration object.</summary>
|
/// <summary>If required by the binder options, validates that there are no unknown keys in the input configuration object.</summary>
|
||||||
public static void ValidateConfigurationKeys(Type type, Lazy<HashSet<string>> keys, IConfiguration configuration, BinderOptions? binderOptions)
|
public static void ValidateConfigurationKeys(Type type, Lazy<HashSet<string>> keys, IConfiguration configuration, BinderOptions? binderOptions)
|
||||||
{
|
{
|
||||||
|
@ -187,7 +182,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
|
||||||
|
|
||||||
if (binderOptions.BindNonPublicProperties)
|
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;
|
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);
|
throw new InvalidOperationException($"Failed to convert configuration value at '{getPath()}' to type '{typeof(int)}'.", exception);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endregion Core binding extensions.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,12 +2,19 @@
|
||||||
#nullable enable
|
#nullable enable
|
||||||
#pragma warning disable CS0612, CS0618 // Suppress warnings about [Obsolete] member usage in generated code.
|
#pragma warning disable CS0612, CS0618 // Suppress warnings about [Obsolete] member usage in generated code.
|
||||||
|
|
||||||
/// <summary>Generated helper providing an AOT and linking compatible implementation for configuration binding.</summary>
|
namespace System.Runtime.CompilerServices
|
||||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
|
|
||||||
internal static class GeneratedConfigurationBinder
|
|
||||||
{
|
{
|
||||||
/// <summary>Attempts to bind the configuration instance to a new instance of type T.</summary>
|
using System;
|
||||||
public static T? Get<T>(this global::Microsoft.Extensions.Configuration.IConfiguration configuration, global::System.Action<global::Microsoft.Extensions.Configuration.BinderOptions>? configureOptions) => (T?)(global::Microsoft.Extensions.Configuration.Binder.SourceGeneration.CoreBindingHelper.GetCore(configuration, typeof(T), configureOptions) ?? default(T));
|
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
|
namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
|
||||||
|
@ -17,11 +24,18 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
|
||||||
using System.CodeDom.Compiler;
|
using System.CodeDom.Compiler;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
|
||||||
/// <summary>Provide core binding logic.</summary>
|
|
||||||
[GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
|
[GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
|
||||||
file static class CoreBindingHelper
|
file static class BindingExtensions
|
||||||
{
|
{
|
||||||
|
#region IConfiguration extensions.
|
||||||
|
/// <summary>Attempts to bind the configuration instance to a new instance of type T.</summary>
|
||||||
|
[InterceptsLocationAttribute(@"src-0.cs", 11, 40)]
|
||||||
|
public static T? Get<T>(this IConfiguration configuration, Action<BinderOptions>? configureOptions) => (T?)(GetCore(configuration, typeof(T), configureOptions) ?? default(T));
|
||||||
|
#endregion IConfiguration extensions.
|
||||||
|
|
||||||
|
#region Core binding extensions.
|
||||||
private readonly static Lazy<HashSet<string>> s_configKeys_ProgramMyClass = new(() => new HashSet<string>(StringComparer.OrdinalIgnoreCase) { "MyString", "MyInt", "MyList", "MyArray", "MyDictionary" });
|
private readonly static Lazy<HashSet<string>> s_configKeys_ProgramMyClass = new(() => new HashSet<string>(StringComparer.OrdinalIgnoreCase) { "MyString", "MyInt", "MyList", "MyArray", "MyDictionary" });
|
||||||
|
|
||||||
public static object? GetCore(this IConfiguration configuration, Type type, Action<BinderOptions>? configureOptions)
|
public static object? GetCore(this IConfiguration configuration, Type type, Action<BinderOptions>? configureOptions)
|
||||||
|
@ -45,16 +59,11 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
|
||||||
return obj;
|
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<int> obj, BinderOptions? binderOptions)
|
public static void BindCore(IConfiguration configuration, ref List<int> obj, BinderOptions? binderOptions)
|
||||||
{
|
{
|
||||||
if (obj is null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(obj));
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (IConfigurationSection section in configuration.GetChildren())
|
foreach (IConfigurationSection section in configuration.GetChildren())
|
||||||
{
|
{
|
||||||
if (section.Value is string value)
|
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)
|
public static void BindCore(IConfiguration configuration, ref int[] obj, BinderOptions? binderOptions)
|
||||||
{
|
{
|
||||||
if (obj is null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(obj));
|
|
||||||
}
|
|
||||||
|
|
||||||
var temp1 = new List<int>();
|
var temp1 = new List<int>();
|
||||||
BindCore(configuration, ref temp1, binderOptions);
|
BindCore(configuration, ref temp1, binderOptions);
|
||||||
int originalCount = obj.Length;
|
int originalCount = obj.Length;
|
||||||
|
@ -80,11 +84,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
|
||||||
|
|
||||||
public static void BindCore(IConfiguration configuration, ref Dictionary<string, string> obj, BinderOptions? binderOptions)
|
public static void BindCore(IConfiguration configuration, ref Dictionary<string, string> obj, BinderOptions? binderOptions)
|
||||||
{
|
{
|
||||||
if (obj is null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(obj));
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (IConfigurationSection section in configuration.GetChildren())
|
foreach (IConfigurationSection section in configuration.GetChildren())
|
||||||
{
|
{
|
||||||
if (section.Value is string value)
|
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)
|
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);
|
ValidateConfigurationKeys(typeof(Program.MyClass), s_configKeys_ProgramMyClass, configuration, binderOptions);
|
||||||
|
|
||||||
obj.MyString = configuration["MyString"]!;
|
obj.MyString = configuration["MyString"]!;
|
||||||
|
@ -135,6 +129,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// <summary>If required by the binder options, validates that there are no unknown keys in the input configuration object.</summary>
|
/// <summary>If required by the binder options, validates that there are no unknown keys in the input configuration object.</summary>
|
||||||
public static void ValidateConfigurationKeys(Type type, Lazy<HashSet<string>> keys, IConfiguration configuration, BinderOptions? binderOptions)
|
public static void ValidateConfigurationKeys(Type type, Lazy<HashSet<string>> keys, IConfiguration configuration, BinderOptions? binderOptions)
|
||||||
{
|
{
|
||||||
|
@ -187,7 +182,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
|
||||||
|
|
||||||
if (binderOptions.BindNonPublicProperties)
|
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;
|
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);
|
throw new InvalidOperationException($"Failed to convert configuration value at '{getPath()}' to type '{typeof(int)}'.", exception);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endregion Core binding extensions.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,12 +2,19 @@
|
||||||
#nullable enable
|
#nullable enable
|
||||||
#pragma warning disable CS0612, CS0618 // Suppress warnings about [Obsolete] member usage in generated code.
|
#pragma warning disable CS0612, CS0618 // Suppress warnings about [Obsolete] member usage in generated code.
|
||||||
|
|
||||||
/// <summary>Generated helper providing an AOT and linking compatible implementation for configuration binding.</summary>
|
namespace System.Runtime.CompilerServices
|
||||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
|
|
||||||
internal static class GeneratedConfigurationBinder
|
|
||||||
{
|
{
|
||||||
/// <summary>Attempts to bind the configuration instance to a new instance of type T.</summary>
|
using System;
|
||||||
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.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
|
namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
|
||||||
|
@ -17,11 +24,18 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
|
||||||
using System.CodeDom.Compiler;
|
using System.CodeDom.Compiler;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
|
||||||
/// <summary>Provide core binding logic.</summary>
|
|
||||||
[GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
|
[GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
|
||||||
file static class CoreBindingHelper
|
file static class BindingExtensions
|
||||||
{
|
{
|
||||||
|
#region IConfiguration extensions.
|
||||||
|
/// <summary>Attempts to bind the configuration instance to a new instance of type T.</summary>
|
||||||
|
[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<HashSet<string>> s_configKeys_ProgramMyClass2 = new(() => new HashSet<string>(StringComparer.OrdinalIgnoreCase) { "MyInt" });
|
private readonly static Lazy<HashSet<string>> s_configKeys_ProgramMyClass2 = new(() => new HashSet<string>(StringComparer.OrdinalIgnoreCase) { "MyInt" });
|
||||||
|
|
||||||
public static object? GetCore(this IConfiguration configuration, Type type, Action<BinderOptions>? configureOptions)
|
public static object? GetCore(this IConfiguration configuration, Type type, Action<BinderOptions>? configureOptions)
|
||||||
|
@ -45,16 +59,11 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
|
||||||
return obj;
|
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)
|
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);
|
ValidateConfigurationKeys(typeof(Program.MyClass2), s_configKeys_ProgramMyClass2, configuration, binderOptions);
|
||||||
|
|
||||||
if (configuration["MyInt"] is string value1)
|
if (configuration["MyInt"] is string value1)
|
||||||
|
@ -63,6 +72,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// <summary>If required by the binder options, validates that there are no unknown keys in the input configuration object.</summary>
|
/// <summary>If required by the binder options, validates that there are no unknown keys in the input configuration object.</summary>
|
||||||
public static void ValidateConfigurationKeys(Type type, Lazy<HashSet<string>> keys, IConfiguration configuration, BinderOptions? binderOptions)
|
public static void ValidateConfigurationKeys(Type type, Lazy<HashSet<string>> keys, IConfiguration configuration, BinderOptions? binderOptions)
|
||||||
{
|
{
|
||||||
|
@ -115,7 +125,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
|
||||||
|
|
||||||
if (binderOptions.BindNonPublicProperties)
|
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;
|
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);
|
throw new InvalidOperationException($"Failed to convert configuration value at '{getPath()}' to type '{typeof(int)}'.", exception);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endregion Core binding extensions.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,12 +2,19 @@
|
||||||
#nullable enable
|
#nullable enable
|
||||||
#pragma warning disable CS0612, CS0618 // Suppress warnings about [Obsolete] member usage in generated code.
|
#pragma warning disable CS0612, CS0618 // Suppress warnings about [Obsolete] member usage in generated code.
|
||||||
|
|
||||||
/// <summary>Generated helper providing an AOT and linking compatible implementation for configuration binding.</summary>
|
namespace System.Runtime.CompilerServices
|
||||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
|
|
||||||
internal static class GeneratedConfigurationBinder
|
|
||||||
{
|
{
|
||||||
/// <summary>Attempts to bind the configuration instance to a new instance of type T.</summary>
|
using System;
|
||||||
public static object? Get(this global::Microsoft.Extensions.Configuration.IConfiguration configuration, global::System.Type type, global::System.Action<global::Microsoft.Extensions.Configuration.BinderOptions>? configureOptions) => global::Microsoft.Extensions.Configuration.Binder.SourceGeneration.CoreBindingHelper.GetCore(configuration, type, configureOptions);
|
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
|
namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
|
||||||
|
@ -17,11 +24,18 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
|
||||||
using System.CodeDom.Compiler;
|
using System.CodeDom.Compiler;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
|
||||||
/// <summary>Provide core binding logic.</summary>
|
|
||||||
[GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
|
[GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
|
||||||
file static class CoreBindingHelper
|
file static class BindingExtensions
|
||||||
{
|
{
|
||||||
|
#region IConfiguration extensions.
|
||||||
|
/// <summary>Attempts to bind the configuration instance to a new instance of type T.</summary>
|
||||||
|
[InterceptsLocationAttribute(@"src-0.cs", 11, 20)]
|
||||||
|
public static object? Get(this IConfiguration configuration, Type type, Action<BinderOptions>? configureOptions) => GetCore(configuration, type, configureOptions);
|
||||||
|
#endregion IConfiguration extensions.
|
||||||
|
|
||||||
|
#region Core binding extensions.
|
||||||
private readonly static Lazy<HashSet<string>> s_configKeys_ProgramMyClass2 = new(() => new HashSet<string>(StringComparer.OrdinalIgnoreCase) { "MyInt" });
|
private readonly static Lazy<HashSet<string>> s_configKeys_ProgramMyClass2 = new(() => new HashSet<string>(StringComparer.OrdinalIgnoreCase) { "MyInt" });
|
||||||
|
|
||||||
public static object? GetCore(this IConfiguration configuration, Type type, Action<BinderOptions>? configureOptions)
|
public static object? GetCore(this IConfiguration configuration, Type type, Action<BinderOptions>? configureOptions)
|
||||||
|
@ -45,16 +59,11 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
|
||||||
return obj;
|
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)
|
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);
|
ValidateConfigurationKeys(typeof(Program.MyClass2), s_configKeys_ProgramMyClass2, configuration, binderOptions);
|
||||||
|
|
||||||
if (configuration["MyInt"] is string value1)
|
if (configuration["MyInt"] is string value1)
|
||||||
|
@ -63,6 +72,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// <summary>If required by the binder options, validates that there are no unknown keys in the input configuration object.</summary>
|
/// <summary>If required by the binder options, validates that there are no unknown keys in the input configuration object.</summary>
|
||||||
public static void ValidateConfigurationKeys(Type type, Lazy<HashSet<string>> keys, IConfiguration configuration, BinderOptions? binderOptions)
|
public static void ValidateConfigurationKeys(Type type, Lazy<HashSet<string>> keys, IConfiguration configuration, BinderOptions? binderOptions)
|
||||||
{
|
{
|
||||||
|
@ -115,7 +125,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
|
||||||
|
|
||||||
if (binderOptions.BindNonPublicProperties)
|
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;
|
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);
|
throw new InvalidOperationException($"Failed to convert configuration value at '{getPath()}' to type '{typeof(int)}'.", exception);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endregion Core binding extensions.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,31 +2,18 @@
|
||||||
#nullable enable
|
#nullable enable
|
||||||
#pragma warning disable CS0612, CS0618 // Suppress warnings about [Obsolete] member usage in generated code.
|
#pragma warning disable CS0612, CS0618 // Suppress warnings about [Obsolete] member usage in generated code.
|
||||||
|
|
||||||
/// <summary>Generated helper providing an AOT and linking compatible implementation for configuration binding.</summary>
|
namespace System.Runtime.CompilerServices
|
||||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
|
|
||||||
internal static class GeneratedOptionsBuilderBinder
|
|
||||||
{
|
{
|
||||||
/// <summary>Registers the dependency injection container to bind <typeparamref name="TOptions"/> against the <see cref="global::Microsoft.Extensions.Configuration.IConfiguration"/> obtained from the DI service provider.</summary>
|
using System;
|
||||||
public static global::Microsoft.Extensions.Options.OptionsBuilder<TOptions> BindConfiguration<TOptions>(this global::Microsoft.Extensions.Options.OptionsBuilder<TOptions> optionsBuilder, string configSectionPath, global::System.Action<global::Microsoft.Extensions.Configuration.BinderOptions>? configureOptions = null) where TOptions : class
|
using System.CodeDom.Compiler;
|
||||||
|
|
||||||
|
[GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
|
||||||
|
[AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]
|
||||||
|
file sealed class InterceptsLocationAttribute : Attribute
|
||||||
{
|
{
|
||||||
if (optionsBuilder is null)
|
public InterceptsLocationAttribute(string filePath, int line, int column)
|
||||||
{
|
{
|
||||||
throw new global::System.ArgumentNullException(nameof(optionsBuilder));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (configSectionPath is null)
|
|
||||||
{
|
|
||||||
throw new global::System.ArgumentNullException(nameof(configSectionPath));
|
|
||||||
}
|
|
||||||
|
|
||||||
optionsBuilder.Configure<global::Microsoft.Extensions.Configuration.IConfiguration>((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.IOptionsChangeTokenSource<TOptions>, global::Microsoft.Extensions.Options.ConfigurationChangeTokenSource<TOptions>>(optionsBuilder.Services);
|
|
||||||
return optionsBuilder;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -34,31 +21,74 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
|
||||||
{
|
{
|
||||||
using Microsoft.Extensions.Configuration;
|
using Microsoft.Extensions.Configuration;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using Microsoft.Extensions.Options;
|
||||||
using System;
|
using System;
|
||||||
using System.CodeDom.Compiler;
|
using System.CodeDom.Compiler;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
|
||||||
/// <summary>Provide core binding logic.</summary>
|
|
||||||
[GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
|
[GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
|
||||||
file static class CoreBindingHelper
|
file static class BindingExtensions
|
||||||
{
|
{
|
||||||
|
#region OptionsBuilder<TOptions> extensions.
|
||||||
|
/// <summary>Registers the dependency injection container to bind <typeparamref name="TOptions"/> against the <see cref="IConfiguration"/> obtained from the DI service provider.</summary>
|
||||||
|
[InterceptsLocationAttribute(@"src-0.cs", 12, 24)]
|
||||||
|
public static OptionsBuilder<TOptions> BindConfiguration<TOptions>(this OptionsBuilder<TOptions> optionsBuilder, string configSectionPath, Action<BinderOptions>? 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<IConfiguration>((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<IOptionsChangeTokenSource<TOptions>, ConfigurationChangeTokenSource<TOptions>>();
|
||||||
|
return optionsBuilder;
|
||||||
|
}
|
||||||
|
#endregion OptionsBuilder<TOptions> extensions.
|
||||||
|
|
||||||
|
#region Core binding extensions.
|
||||||
private readonly static Lazy<HashSet<string>> s_configKeys_ProgramMyClass = new(() => new HashSet<string>(StringComparer.OrdinalIgnoreCase) { "MyString", "MyInt", "MyList" });
|
private readonly static Lazy<HashSet<string>> s_configKeys_ProgramMyClass = new(() => new HashSet<string>(StringComparer.OrdinalIgnoreCase) { "MyString", "MyInt", "MyList" });
|
||||||
|
|
||||||
public static void BindCoreUntyped(this IConfiguration configuration, object obj, Type type, Action<BinderOptions>? configureOptions)
|
public static void BindCoreMain(IConfiguration configuration, object obj, Type type, Action<BinderOptions>? configureOptions)
|
||||||
{
|
{
|
||||||
if (configuration is null)
|
if (configuration is null)
|
||||||
{
|
{
|
||||||
throw new ArgumentNullException(nameof(configuration));
|
throw new ArgumentNullException(nameof(configuration));
|
||||||
}
|
}
|
||||||
|
|
||||||
BinderOptions? binderOptions = GetBinderOptions(configureOptions);
|
if (obj is null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(obj));
|
||||||
|
}
|
||||||
|
|
||||||
if (!HasValueOrChildren(configuration))
|
if (!HasValueOrChildren(configuration))
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BinderOptions? binderOptions = GetBinderOptions(configureOptions);
|
||||||
|
|
||||||
if (type == typeof(Program.MyClass))
|
if (type == typeof(Program.MyClass))
|
||||||
{
|
{
|
||||||
var temp = (Program.MyClass)obj;
|
var temp = (Program.MyClass)obj;
|
||||||
|
@ -66,16 +96,11 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
|
||||||
return;
|
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<int> obj, BinderOptions? binderOptions)
|
public static void BindCore(IConfiguration configuration, ref List<int> obj, BinderOptions? binderOptions)
|
||||||
{
|
{
|
||||||
if (obj is null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(obj));
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (IConfigurationSection section in configuration.GetChildren())
|
foreach (IConfigurationSection section in configuration.GetChildren())
|
||||||
{
|
{
|
||||||
if (section.Value is string value)
|
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)
|
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);
|
ValidateConfigurationKeys(typeof(Program.MyClass), s_configKeys_ProgramMyClass, configuration, binderOptions);
|
||||||
|
|
||||||
obj.MyString = configuration["MyString"]!;
|
obj.MyString = configuration["MyString"]!;
|
||||||
|
@ -110,6 +130,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// <summary>If required by the binder options, validates that there are no unknown keys in the input configuration object.</summary>
|
/// <summary>If required by the binder options, validates that there are no unknown keys in the input configuration object.</summary>
|
||||||
public static void ValidateConfigurationKeys(Type type, Lazy<HashSet<string>> keys, IConfiguration configuration, BinderOptions? binderOptions)
|
public static void ValidateConfigurationKeys(Type type, Lazy<HashSet<string>> keys, IConfiguration configuration, BinderOptions? binderOptions)
|
||||||
{
|
{
|
||||||
|
@ -162,7 +183,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
|
||||||
|
|
||||||
if (binderOptions.BindNonPublicProperties)
|
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;
|
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);
|
throw new InvalidOperationException($"Failed to convert configuration value at '{getPath()}' to type '{typeof(int)}'.", exception);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endregion Core binding extensions.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,49 +2,18 @@
|
||||||
#nullable enable
|
#nullable enable
|
||||||
#pragma warning disable CS0612, CS0618 // Suppress warnings about [Obsolete] member usage in generated code.
|
#pragma warning disable CS0612, CS0618 // Suppress warnings about [Obsolete] member usage in generated code.
|
||||||
|
|
||||||
/// <summary>Generated helper providing an AOT and linking compatible implementation for configuration binding.</summary>
|
namespace System.Runtime.CompilerServices
|
||||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
|
|
||||||
internal static class GeneratedOptionsBuilderBinder
|
|
||||||
{
|
{
|
||||||
/// <summary>Registers a configuration instance which <typeparamref name="TOptions"/> will bind against.</summary>
|
using System;
|
||||||
public static global::Microsoft.Extensions.Options.OptionsBuilder<TOptions> Bind<TOptions>(this global::Microsoft.Extensions.Options.OptionsBuilder<TOptions> optionsBuilder, global::Microsoft.Extensions.Configuration.IConfiguration configuration) where TOptions : class
|
using System.CodeDom.Compiler;
|
||||||
|
|
||||||
|
[GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
|
||||||
|
[AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]
|
||||||
|
file sealed class InterceptsLocationAttribute : Attribute
|
||||||
{
|
{
|
||||||
return global::GeneratedOptionsBuilderBinder.Bind(optionsBuilder, configuration, configureOptions: null);
|
public InterceptsLocationAttribute(string filePath, int line, int column)
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>Registers a configuration instance which <typeparamref name="TOptions"/> will bind against.</summary>
|
|
||||||
public static global::Microsoft.Extensions.Options.OptionsBuilder<TOptions> Bind<TOptions>(this global::Microsoft.Extensions.Options.OptionsBuilder<TOptions> optionsBuilder, global::Microsoft.Extensions.Configuration.IConfiguration configuration, global::System.Action<global::Microsoft.Extensions.Configuration.BinderOptions>? configureOptions) where TOptions : class
|
|
||||||
{
|
|
||||||
if (optionsBuilder is null)
|
|
||||||
{
|
{
|
||||||
throw new global::System.ArgumentNullException(nameof(optionsBuilder));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
global::GeneratedServiceCollectionBinder.Configure<TOptions>(optionsBuilder.Services, optionsBuilder.Name, configuration, configureOptions);
|
|
||||||
return optionsBuilder;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>Generated helper providing an AOT and linking compatible implementation for configuration binding.</summary>
|
|
||||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
|
|
||||||
internal static class GeneratedServiceCollectionBinder
|
|
||||||
{
|
|
||||||
/// <summary>Registers a configuration instance which TOptions will bind against.</summary>
|
|
||||||
public static global::Microsoft.Extensions.DependencyInjection.IServiceCollection Configure<TOptions>(this global::Microsoft.Extensions.DependencyInjection.IServiceCollection services, string? name, global::Microsoft.Extensions.Configuration.IConfiguration configuration, global::System.Action<global::Microsoft.Extensions.Configuration.BinderOptions>? 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<global::Microsoft.Extensions.Options.IOptionsChangeTokenSource<TOptions>>(services, new global::Microsoft.Extensions.Options.ConfigurationChangeTokenSource<TOptions>(name, configuration));
|
|
||||||
return global::Microsoft.Extensions.DependencyInjection.ServiceCollectionServiceExtensions.AddSingleton<global::Microsoft.Extensions.Options.IConfigureOptions<TOptions>>(services, new global::Microsoft.Extensions.Options.ConfigureNamedOptions<TOptions>(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.Configuration;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using Microsoft.Extensions.Options;
|
||||||
using System;
|
using System;
|
||||||
using System.CodeDom.Compiler;
|
using System.CodeDom.Compiler;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
|
||||||
/// <summary>Provide core binding logic.</summary>
|
|
||||||
[GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
|
[GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
|
||||||
file static class CoreBindingHelper
|
file static class BindingExtensions
|
||||||
{
|
{
|
||||||
|
#region OptionsBuilder<TOptions> extensions.
|
||||||
|
/// <summary>Registers a configuration instance which <typeparamref name="TOptions"/> will bind against.</summary>
|
||||||
|
[InterceptsLocationAttribute(@"src-0.cs", 15, 24)]
|
||||||
|
public static OptionsBuilder<TOptions> Bind<TOptions>(this OptionsBuilder<TOptions> optionsBuilder, IConfiguration configuration) where TOptions : class
|
||||||
|
{
|
||||||
|
return Bind(optionsBuilder, configuration, configureOptions: null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Registers a configuration instance which <typeparamref name="TOptions"/> will bind against.</summary>
|
||||||
|
public static OptionsBuilder<TOptions> Bind<TOptions>(this OptionsBuilder<TOptions> optionsBuilder, IConfiguration configuration, Action<BinderOptions>? configureOptions) where TOptions : class
|
||||||
|
{
|
||||||
|
if (optionsBuilder is null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(optionsBuilder));
|
||||||
|
}
|
||||||
|
|
||||||
|
Configure<TOptions>(optionsBuilder.Services, optionsBuilder.Name, configuration, configureOptions);
|
||||||
|
return optionsBuilder;
|
||||||
|
}
|
||||||
|
#endregion OptionsBuilder<TOptions> extensions.
|
||||||
|
|
||||||
|
#region IServiceCollection extensions.
|
||||||
|
/// <summary>Registers a configuration instance which TOptions will bind against.</summary>
|
||||||
|
public static IServiceCollection Configure<TOptions>(this IServiceCollection services, string? name, IConfiguration configuration, Action<BinderOptions>? 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<IOptionsChangeTokenSource<TOptions>>(new ConfigurationChangeTokenSource<TOptions>(name, configuration));
|
||||||
|
return services.AddSingleton<Microsoft.Extensions.Options.IConfigureOptions<TOptions>>(new Microsoft.Extensions.Options.ConfigureNamedOptions<TOptions>(name, obj => BindCoreMain(configuration, obj, typeof(TOptions)configureOptions)));
|
||||||
|
}
|
||||||
|
#endregion IServiceCollection extensions.
|
||||||
|
|
||||||
|
#region Core binding extensions.
|
||||||
private readonly static Lazy<HashSet<string>> s_configKeys_ProgramMyClass = new(() => new HashSet<string>(StringComparer.OrdinalIgnoreCase) { "MyString", "MyInt", "MyList" });
|
private readonly static Lazy<HashSet<string>> s_configKeys_ProgramMyClass = new(() => new HashSet<string>(StringComparer.OrdinalIgnoreCase) { "MyString", "MyInt", "MyList" });
|
||||||
|
|
||||||
public static void BindCoreUntyped(this IConfiguration configuration, object obj, Type type, Action<BinderOptions>? configureOptions)
|
public static void BindCoreMain(IConfiguration configuration, object obj, Type type, Action<BinderOptions>? configureOptions)
|
||||||
{
|
{
|
||||||
if (configuration is null)
|
if (configuration is null)
|
||||||
{
|
{
|
||||||
throw new ArgumentNullException(nameof(configuration));
|
throw new ArgumentNullException(nameof(configuration));
|
||||||
}
|
}
|
||||||
|
|
||||||
BinderOptions? binderOptions = GetBinderOptions(configureOptions);
|
if (obj is null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(obj));
|
||||||
|
}
|
||||||
|
|
||||||
if (!HasValueOrChildren(configuration))
|
if (!HasValueOrChildren(configuration))
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BinderOptions? binderOptions = GetBinderOptions(configureOptions);
|
||||||
|
|
||||||
if (type == typeof(Program.MyClass))
|
if (type == typeof(Program.MyClass))
|
||||||
{
|
{
|
||||||
var temp = (Program.MyClass)obj;
|
var temp = (Program.MyClass)obj;
|
||||||
|
@ -84,16 +101,11 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
|
||||||
return;
|
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<int> obj, BinderOptions? binderOptions)
|
public static void BindCore(IConfiguration configuration, ref List<int> obj, BinderOptions? binderOptions)
|
||||||
{
|
{
|
||||||
if (obj is null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(obj));
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (IConfigurationSection section in configuration.GetChildren())
|
foreach (IConfigurationSection section in configuration.GetChildren())
|
||||||
{
|
{
|
||||||
if (section.Value is string value)
|
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)
|
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);
|
ValidateConfigurationKeys(typeof(Program.MyClass), s_configKeys_ProgramMyClass, configuration, binderOptions);
|
||||||
|
|
||||||
obj.MyString = configuration["MyString"]!;
|
obj.MyString = configuration["MyString"]!;
|
||||||
|
@ -128,6 +135,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// <summary>If required by the binder options, validates that there are no unknown keys in the input configuration object.</summary>
|
/// <summary>If required by the binder options, validates that there are no unknown keys in the input configuration object.</summary>
|
||||||
public static void ValidateConfigurationKeys(Type type, Lazy<HashSet<string>> keys, IConfiguration configuration, BinderOptions? binderOptions)
|
public static void ValidateConfigurationKeys(Type type, Lazy<HashSet<string>> keys, IConfiguration configuration, BinderOptions? binderOptions)
|
||||||
{
|
{
|
||||||
|
@ -180,7 +188,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
|
||||||
|
|
||||||
if (binderOptions.BindNonPublicProperties)
|
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;
|
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);
|
throw new InvalidOperationException($"Failed to convert configuration value at '{getPath()}' to type '{typeof(int)}'.", exception);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endregion Core binding extensions.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,43 +2,18 @@
|
||||||
#nullable enable
|
#nullable enable
|
||||||
#pragma warning disable CS0612, CS0618 // Suppress warnings about [Obsolete] member usage in generated code.
|
#pragma warning disable CS0612, CS0618 // Suppress warnings about [Obsolete] member usage in generated code.
|
||||||
|
|
||||||
/// <summary>Generated helper providing an AOT and linking compatible implementation for configuration binding.</summary>
|
namespace System.Runtime.CompilerServices
|
||||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
|
|
||||||
internal static class GeneratedOptionsBuilderBinder
|
|
||||||
{
|
{
|
||||||
/// <summary>Registers a configuration instance which <typeparamref name="TOptions"/> will bind against.</summary>
|
using System;
|
||||||
public static global::Microsoft.Extensions.Options.OptionsBuilder<TOptions> Bind<TOptions>(this global::Microsoft.Extensions.Options.OptionsBuilder<TOptions> optionsBuilder, global::Microsoft.Extensions.Configuration.IConfiguration configuration, global::System.Action<global::Microsoft.Extensions.Configuration.BinderOptions>? configureOptions) where TOptions : class
|
using System.CodeDom.Compiler;
|
||||||
|
|
||||||
|
[GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
|
||||||
|
[AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]
|
||||||
|
file sealed class InterceptsLocationAttribute : Attribute
|
||||||
{
|
{
|
||||||
if (optionsBuilder is null)
|
public InterceptsLocationAttribute(string filePath, int line, int column)
|
||||||
{
|
{
|
||||||
throw new global::System.ArgumentNullException(nameof(optionsBuilder));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
global::GeneratedServiceCollectionBinder.Configure<TOptions>(optionsBuilder.Services, optionsBuilder.Name, configuration, configureOptions);
|
|
||||||
return optionsBuilder;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>Generated helper providing an AOT and linking compatible implementation for configuration binding.</summary>
|
|
||||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
|
|
||||||
internal static class GeneratedServiceCollectionBinder
|
|
||||||
{
|
|
||||||
/// <summary>Registers a configuration instance which TOptions will bind against.</summary>
|
|
||||||
public static global::Microsoft.Extensions.DependencyInjection.IServiceCollection Configure<TOptions>(this global::Microsoft.Extensions.DependencyInjection.IServiceCollection services, string? name, global::Microsoft.Extensions.Configuration.IConfiguration configuration, global::System.Action<global::Microsoft.Extensions.Configuration.BinderOptions>? 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<global::Microsoft.Extensions.Options.IOptionsChangeTokenSource<TOptions>>(services, new global::Microsoft.Extensions.Options.ConfigurationChangeTokenSource<TOptions>(name, configuration));
|
|
||||||
return global::Microsoft.Extensions.DependencyInjection.ServiceCollectionServiceExtensions.AddSingleton<global::Microsoft.Extensions.Options.IConfigureOptions<TOptions>>(services, new global::Microsoft.Extensions.Options.ConfigureNamedOptions<TOptions>(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.Configuration;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using Microsoft.Extensions.Options;
|
||||||
using System;
|
using System;
|
||||||
using System.CodeDom.Compiler;
|
using System.CodeDom.Compiler;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
|
||||||
/// <summary>Provide core binding logic.</summary>
|
|
||||||
[GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
|
[GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
|
||||||
file static class CoreBindingHelper
|
file static class BindingExtensions
|
||||||
{
|
{
|
||||||
|
#region OptionsBuilder<TOptions> extensions.
|
||||||
|
/// <summary>Registers a configuration instance which <typeparamref name="TOptions"/> will bind against.</summary>
|
||||||
|
[InterceptsLocationAttribute(@"src-0.cs", 15, 24)]
|
||||||
|
public static OptionsBuilder<TOptions> Bind<TOptions>(this OptionsBuilder<TOptions> optionsBuilder, IConfiguration configuration, Action<BinderOptions>? configureOptions) where TOptions : class
|
||||||
|
{
|
||||||
|
if (optionsBuilder is null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(optionsBuilder));
|
||||||
|
}
|
||||||
|
|
||||||
|
Configure<TOptions>(optionsBuilder.Services, optionsBuilder.Name, configuration, configureOptions);
|
||||||
|
return optionsBuilder;
|
||||||
|
}
|
||||||
|
#endregion OptionsBuilder<TOptions> extensions.
|
||||||
|
|
||||||
|
#region IServiceCollection extensions.
|
||||||
|
/// <summary>Registers a configuration instance which TOptions will bind against.</summary>
|
||||||
|
public static IServiceCollection Configure<TOptions>(this IServiceCollection services, string? name, IConfiguration configuration, Action<BinderOptions>? 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<IOptionsChangeTokenSource<TOptions>>(new ConfigurationChangeTokenSource<TOptions>(name, configuration));
|
||||||
|
return services.AddSingleton<Microsoft.Extensions.Options.IConfigureOptions<TOptions>>(new Microsoft.Extensions.Options.ConfigureNamedOptions<TOptions>(name, obj => BindCoreMain(configuration, obj, typeof(TOptions)configureOptions)));
|
||||||
|
}
|
||||||
|
#endregion IServiceCollection extensions.
|
||||||
|
|
||||||
|
#region Core binding extensions.
|
||||||
private readonly static Lazy<HashSet<string>> s_configKeys_ProgramMyClass = new(() => new HashSet<string>(StringComparer.OrdinalIgnoreCase) { "MyString", "MyInt", "MyList" });
|
private readonly static Lazy<HashSet<string>> s_configKeys_ProgramMyClass = new(() => new HashSet<string>(StringComparer.OrdinalIgnoreCase) { "MyString", "MyInt", "MyList" });
|
||||||
|
|
||||||
public static void BindCoreUntyped(this IConfiguration configuration, object obj, Type type, Action<BinderOptions>? configureOptions)
|
public static void BindCoreMain(IConfiguration configuration, object obj, Type type, Action<BinderOptions>? configureOptions)
|
||||||
{
|
{
|
||||||
if (configuration is null)
|
if (configuration is null)
|
||||||
{
|
{
|
||||||
throw new ArgumentNullException(nameof(configuration));
|
throw new ArgumentNullException(nameof(configuration));
|
||||||
}
|
}
|
||||||
|
|
||||||
BinderOptions? binderOptions = GetBinderOptions(configureOptions);
|
if (obj is null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(obj));
|
||||||
|
}
|
||||||
|
|
||||||
if (!HasValueOrChildren(configuration))
|
if (!HasValueOrChildren(configuration))
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BinderOptions? binderOptions = GetBinderOptions(configureOptions);
|
||||||
|
|
||||||
if (type == typeof(Program.MyClass))
|
if (type == typeof(Program.MyClass))
|
||||||
{
|
{
|
||||||
var temp = (Program.MyClass)obj;
|
var temp = (Program.MyClass)obj;
|
||||||
|
@ -78,16 +95,11 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
|
||||||
return;
|
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<int> obj, BinderOptions? binderOptions)
|
public static void BindCore(IConfiguration configuration, ref List<int> obj, BinderOptions? binderOptions)
|
||||||
{
|
{
|
||||||
if (obj is null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(obj));
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (IConfigurationSection section in configuration.GetChildren())
|
foreach (IConfigurationSection section in configuration.GetChildren())
|
||||||
{
|
{
|
||||||
if (section.Value is string value)
|
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)
|
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);
|
ValidateConfigurationKeys(typeof(Program.MyClass), s_configKeys_ProgramMyClass, configuration, binderOptions);
|
||||||
|
|
||||||
obj.MyString = configuration["MyString"]!;
|
obj.MyString = configuration["MyString"]!;
|
||||||
|
@ -122,6 +129,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// <summary>If required by the binder options, validates that there are no unknown keys in the input configuration object.</summary>
|
/// <summary>If required by the binder options, validates that there are no unknown keys in the input configuration object.</summary>
|
||||||
public static void ValidateConfigurationKeys(Type type, Lazy<HashSet<string>> keys, IConfiguration configuration, BinderOptions? binderOptions)
|
public static void ValidateConfigurationKeys(Type type, Lazy<HashSet<string>> keys, IConfiguration configuration, BinderOptions? binderOptions)
|
||||||
{
|
{
|
||||||
|
@ -174,7 +182,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
|
||||||
|
|
||||||
if (binderOptions.BindNonPublicProperties)
|
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;
|
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);
|
throw new InvalidOperationException($"Failed to convert configuration value at '{getPath()}' to type '{typeof(int)}'.", exception);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endregion Core binding extensions.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,12 +2,19 @@
|
||||||
#nullable enable
|
#nullable enable
|
||||||
#pragma warning disable CS0612, CS0618 // Suppress warnings about [Obsolete] member usage in generated code.
|
#pragma warning disable CS0612, CS0618 // Suppress warnings about [Obsolete] member usage in generated code.
|
||||||
|
|
||||||
/// <summary>Generated helper providing an AOT and linking compatible implementation for configuration binding.</summary>
|
namespace System.Runtime.CompilerServices
|
||||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
|
|
||||||
internal static class GeneratedConfigurationBinder
|
|
||||||
{
|
{
|
||||||
/// <summary>Attempts to bind the given object instance to configuration values by matching property names against configuration keys recursively.</summary>
|
using System;
|
||||||
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.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
|
namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
|
||||||
|
@ -17,20 +24,36 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
|
||||||
using System.CodeDom.Compiler;
|
using System.CodeDom.Compiler;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
|
||||||
/// <summary>Provide core binding logic.</summary>
|
|
||||||
[GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
|
[GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
|
||||||
file static class CoreBindingHelper
|
file static class BindingExtensions
|
||||||
{
|
{
|
||||||
private readonly static Lazy<HashSet<string>> s_configKeys_ProgramMyClass = new(() => new HashSet<string>(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" });
|
#region IConfiguration extensions.
|
||||||
|
/// <summary>Attempts to bind the given object instance to configuration values by matching property names against configuration keys recursively.</summary>
|
||||||
public static void BindCore(IConfiguration configuration, ref Program.MyClass obj, BinderOptions? binderOptions)
|
[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)
|
if (obj is null)
|
||||||
{
|
{
|
||||||
throw new ArgumentNullException(nameof(obj));
|
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<HashSet<string>> s_configKeys_ProgramMyClass = new(() => new HashSet<string>(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);
|
ValidateConfigurationKeys(typeof(Program.MyClass), s_configKeys_ProgramMyClass, configuration, binderOptions);
|
||||||
|
|
||||||
if (configuration["Prop0"] is string value0)
|
if (configuration["Prop0"] is string value0)
|
||||||
|
@ -168,6 +191,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// <summary>If required by the binder options, validates that there are no unknown keys in the input configuration object.</summary>
|
/// <summary>If required by the binder options, validates that there are no unknown keys in the input configuration object.</summary>
|
||||||
public static void ValidateConfigurationKeys(Type type, Lazy<HashSet<string>> keys, IConfiguration configuration, BinderOptions? binderOptions)
|
public static void ValidateConfigurationKeys(Type type, Lazy<HashSet<string>> keys, IConfiguration configuration, BinderOptions? binderOptions)
|
||||||
{
|
{
|
||||||
|
@ -517,5 +541,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
|
||||||
throw new InvalidOperationException($"Failed to convert configuration value at '{getPath()}' to type '{typeof(byte[])}'.", exception);
|
throw new InvalidOperationException($"Failed to convert configuration value at '{getPath()}' to type '{typeof(byte[])}'.", exception);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endregion Core binding extensions.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,64 +2,84 @@
|
||||||
#nullable enable
|
#nullable enable
|
||||||
#pragma warning disable CS0612, CS0618 // Suppress warnings about [Obsolete] member usage in generated code.
|
#pragma warning disable CS0612, CS0618 // Suppress warnings about [Obsolete] member usage in generated code.
|
||||||
|
|
||||||
/// <summary>Generated helper providing an AOT and linking compatible implementation for configuration binding.</summary>
|
namespace System.Runtime.CompilerServices
|
||||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
|
|
||||||
internal static class GeneratedServiceCollectionBinder
|
|
||||||
{
|
{
|
||||||
/// <summary>Registers a configuration instance which TOptions will bind against.</summary>
|
using System;
|
||||||
public static global::Microsoft.Extensions.DependencyInjection.IServiceCollection Configure<TOptions>(this global::Microsoft.Extensions.DependencyInjection.IServiceCollection services, global::Microsoft.Extensions.Configuration.IConfiguration configuration) where TOptions : class
|
using System.CodeDom.Compiler;
|
||||||
|
|
||||||
|
[GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
|
||||||
|
[AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]
|
||||||
|
file sealed class InterceptsLocationAttribute : Attribute
|
||||||
{
|
{
|
||||||
return global::GeneratedServiceCollectionBinder.Configure<TOptions>(services, string.Empty, configuration, configureOptions: null);
|
public InterceptsLocationAttribute(string filePath, int line, int column)
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>Registers a configuration instance which TOptions will bind against.</summary>
|
|
||||||
public static global::Microsoft.Extensions.DependencyInjection.IServiceCollection Configure<TOptions>(this global::Microsoft.Extensions.DependencyInjection.IServiceCollection services, string? name, global::Microsoft.Extensions.Configuration.IConfiguration configuration, global::System.Action<global::Microsoft.Extensions.Configuration.BinderOptions>? 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<global::Microsoft.Extensions.Options.IOptionsChangeTokenSource<TOptions>>(services, new global::Microsoft.Extensions.Options.ConfigurationChangeTokenSource<TOptions>(name, configuration));
|
|
||||||
return global::Microsoft.Extensions.DependencyInjection.ServiceCollectionServiceExtensions.AddSingleton<global::Microsoft.Extensions.Options.IConfigureOptions<TOptions>>(services, new global::Microsoft.Extensions.Options.ConfigureNamedOptions<TOptions>(name, obj => global::Microsoft.Extensions.Configuration.Binder.SourceGeneration.CoreBindingHelper.BindCoreUntyped(configuration, obj, typeof(TOptions), configureOptions)));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
|
namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
|
||||||
{
|
{
|
||||||
using Microsoft.Extensions.Configuration;
|
using Microsoft.Extensions.Configuration;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using System;
|
using System;
|
||||||
using System.CodeDom.Compiler;
|
using System.CodeDom.Compiler;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
|
||||||
/// <summary>Provide core binding logic.</summary>
|
|
||||||
[GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
|
[GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
|
||||||
file static class CoreBindingHelper
|
file static class BindingExtensions
|
||||||
{
|
{
|
||||||
|
#region IServiceCollection extensions.
|
||||||
|
/// <summary>Registers a configuration instance which TOptions will bind against.</summary>
|
||||||
|
[InterceptsLocationAttribute(@"src-0.cs", 14, 18)]
|
||||||
|
public static IServiceCollection Configure<TOptions>(this IServiceCollection services, IConfiguration configuration) where TOptions : class
|
||||||
|
{
|
||||||
|
return Configure<TOptions>(services, string.Empty, configuration, configureOptions: null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Registers a configuration instance which TOptions will bind against.</summary>
|
||||||
|
public static IServiceCollection Configure<TOptions>(this IServiceCollection services, string? name, IConfiguration configuration, Action<BinderOptions>? 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<IOptionsChangeTokenSource<TOptions>>(new ConfigurationChangeTokenSource<TOptions>(name, configuration));
|
||||||
|
return services.AddSingleton<Microsoft.Extensions.Options.IConfigureOptions<TOptions>>(new Microsoft.Extensions.Options.ConfigureNamedOptions<TOptions>(name, obj => BindCoreMain(configuration, obj, typeof(TOptions)configureOptions)));
|
||||||
|
}
|
||||||
|
#endregion IServiceCollection extensions.
|
||||||
|
|
||||||
|
#region Core binding extensions.
|
||||||
private readonly static Lazy<HashSet<string>> s_configKeys_ProgramMyClass2 = new(() => new HashSet<string>(StringComparer.OrdinalIgnoreCase) { "MyInt" });
|
private readonly static Lazy<HashSet<string>> s_configKeys_ProgramMyClass2 = new(() => new HashSet<string>(StringComparer.OrdinalIgnoreCase) { "MyInt" });
|
||||||
private readonly static Lazy<HashSet<string>> s_configKeys_ProgramMyClass = new(() => new HashSet<string>(StringComparer.OrdinalIgnoreCase) { "MyString", "MyInt", "MyList", "MyList2", "MyDictionary" });
|
private readonly static Lazy<HashSet<string>> s_configKeys_ProgramMyClass = new(() => new HashSet<string>(StringComparer.OrdinalIgnoreCase) { "MyString", "MyInt", "MyList", "MyList2", "MyDictionary" });
|
||||||
|
|
||||||
public static void BindCoreUntyped(this IConfiguration configuration, object obj, Type type, Action<BinderOptions>? configureOptions)
|
public static void BindCoreMain(IConfiguration configuration, object obj, Type type, Action<BinderOptions>? configureOptions)
|
||||||
{
|
{
|
||||||
if (configuration is null)
|
if (configuration is null)
|
||||||
{
|
{
|
||||||
throw new ArgumentNullException(nameof(configuration));
|
throw new ArgumentNullException(nameof(configuration));
|
||||||
}
|
}
|
||||||
|
|
||||||
BinderOptions? binderOptions = GetBinderOptions(configureOptions);
|
if (obj is null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(obj));
|
||||||
|
}
|
||||||
|
|
||||||
if (!HasValueOrChildren(configuration))
|
if (!HasValueOrChildren(configuration))
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BinderOptions? binderOptions = GetBinderOptions(configureOptions);
|
||||||
|
|
||||||
if (type == typeof(Program.MyClass))
|
if (type == typeof(Program.MyClass))
|
||||||
{
|
{
|
||||||
var temp = (Program.MyClass)obj;
|
var temp = (Program.MyClass)obj;
|
||||||
|
@ -67,16 +87,11 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
|
||||||
return;
|
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<int> obj, BinderOptions? binderOptions)
|
public static void BindCore(IConfiguration configuration, ref List<int> obj, BinderOptions? binderOptions)
|
||||||
{
|
{
|
||||||
if (obj is null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(obj));
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (IConfigurationSection section in configuration.GetChildren())
|
foreach (IConfigurationSection section in configuration.GetChildren())
|
||||||
{
|
{
|
||||||
if (section.Value is string value)
|
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)
|
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);
|
ValidateConfigurationKeys(typeof(Program.MyClass2), s_configKeys_ProgramMyClass2, configuration, binderOptions);
|
||||||
|
|
||||||
if (configuration["MyInt"] is string value1)
|
if (configuration["MyInt"] is string value1)
|
||||||
|
@ -103,11 +113,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
|
||||||
|
|
||||||
public static void BindCore(IConfiguration configuration, ref List<Program.MyClass2> obj, BinderOptions? binderOptions)
|
public static void BindCore(IConfiguration configuration, ref List<Program.MyClass2> obj, BinderOptions? binderOptions)
|
||||||
{
|
{
|
||||||
if (obj is null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(obj));
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (IConfigurationSection section in configuration.GetChildren())
|
foreach (IConfigurationSection section in configuration.GetChildren())
|
||||||
{
|
{
|
||||||
var value = new Program.MyClass2();
|
var value = new Program.MyClass2();
|
||||||
|
@ -118,11 +123,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
|
||||||
|
|
||||||
public static void BindCore(IConfiguration configuration, ref Dictionary<string, string> obj, BinderOptions? binderOptions)
|
public static void BindCore(IConfiguration configuration, ref Dictionary<string, string> obj, BinderOptions? binderOptions)
|
||||||
{
|
{
|
||||||
if (obj is null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(obj));
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (IConfigurationSection section in configuration.GetChildren())
|
foreach (IConfigurationSection section in configuration.GetChildren())
|
||||||
{
|
{
|
||||||
if (section.Value is string value)
|
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)
|
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);
|
ValidateConfigurationKeys(typeof(Program.MyClass), s_configKeys_ProgramMyClass, configuration, binderOptions);
|
||||||
|
|
||||||
obj.MyString = configuration["MyString"]!;
|
obj.MyString = configuration["MyString"]!;
|
||||||
|
@ -173,6 +168,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// <summary>If required by the binder options, validates that there are no unknown keys in the input configuration object.</summary>
|
/// <summary>If required by the binder options, validates that there are no unknown keys in the input configuration object.</summary>
|
||||||
public static void ValidateConfigurationKeys(Type type, Lazy<HashSet<string>> keys, IConfiguration configuration, BinderOptions? binderOptions)
|
public static void ValidateConfigurationKeys(Type type, Lazy<HashSet<string>> keys, IConfiguration configuration, BinderOptions? binderOptions)
|
||||||
{
|
{
|
||||||
|
@ -225,7 +221,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
|
||||||
|
|
||||||
if (binderOptions.BindNonPublicProperties)
|
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;
|
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);
|
throw new InvalidOperationException($"Failed to convert configuration value at '{getPath()}' to type '{typeof(int)}'.", exception);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endregion Core binding extensions.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,64 +2,84 @@
|
||||||
#nullable enable
|
#nullable enable
|
||||||
#pragma warning disable CS0612, CS0618 // Suppress warnings about [Obsolete] member usage in generated code.
|
#pragma warning disable CS0612, CS0618 // Suppress warnings about [Obsolete] member usage in generated code.
|
||||||
|
|
||||||
/// <summary>Generated helper providing an AOT and linking compatible implementation for configuration binding.</summary>
|
namespace System.Runtime.CompilerServices
|
||||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
|
|
||||||
internal static class GeneratedServiceCollectionBinder
|
|
||||||
{
|
{
|
||||||
/// <summary>Registers a configuration instance which TOptions will bind against.</summary>
|
using System;
|
||||||
public static global::Microsoft.Extensions.DependencyInjection.IServiceCollection Configure<TOptions>(this global::Microsoft.Extensions.DependencyInjection.IServiceCollection services, global::Microsoft.Extensions.Configuration.IConfiguration configuration, global::System.Action<global::Microsoft.Extensions.Configuration.BinderOptions>? configureOptions) where TOptions : class
|
using System.CodeDom.Compiler;
|
||||||
|
|
||||||
|
[GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
|
||||||
|
[AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]
|
||||||
|
file sealed class InterceptsLocationAttribute : Attribute
|
||||||
{
|
{
|
||||||
return global::GeneratedServiceCollectionBinder.Configure<TOptions>(services, string.Empty, configuration, configureOptions);
|
public InterceptsLocationAttribute(string filePath, int line, int column)
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>Registers a configuration instance which TOptions will bind against.</summary>
|
|
||||||
public static global::Microsoft.Extensions.DependencyInjection.IServiceCollection Configure<TOptions>(this global::Microsoft.Extensions.DependencyInjection.IServiceCollection services, string? name, global::Microsoft.Extensions.Configuration.IConfiguration configuration, global::System.Action<global::Microsoft.Extensions.Configuration.BinderOptions>? 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<global::Microsoft.Extensions.Options.IOptionsChangeTokenSource<TOptions>>(services, new global::Microsoft.Extensions.Options.ConfigurationChangeTokenSource<TOptions>(name, configuration));
|
|
||||||
return global::Microsoft.Extensions.DependencyInjection.ServiceCollectionServiceExtensions.AddSingleton<global::Microsoft.Extensions.Options.IConfigureOptions<TOptions>>(services, new global::Microsoft.Extensions.Options.ConfigureNamedOptions<TOptions>(name, obj => global::Microsoft.Extensions.Configuration.Binder.SourceGeneration.CoreBindingHelper.BindCoreUntyped(configuration, obj, typeof(TOptions), configureOptions)));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
|
namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
|
||||||
{
|
{
|
||||||
using Microsoft.Extensions.Configuration;
|
using Microsoft.Extensions.Configuration;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using System;
|
using System;
|
||||||
using System.CodeDom.Compiler;
|
using System.CodeDom.Compiler;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
|
||||||
/// <summary>Provide core binding logic.</summary>
|
|
||||||
[GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
|
[GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
|
||||||
file static class CoreBindingHelper
|
file static class BindingExtensions
|
||||||
{
|
{
|
||||||
|
#region IServiceCollection extensions.
|
||||||
|
/// <summary>Registers a configuration instance which TOptions will bind against.</summary>
|
||||||
|
[InterceptsLocationAttribute(@"src-0.cs", 14, 18)]
|
||||||
|
public static IServiceCollection Configure<TOptions>(this IServiceCollection services, IConfiguration configuration, Action<BinderOptions>? configureOptions) where TOptions : class
|
||||||
|
{
|
||||||
|
return Configure<TOptions>(services, string.Empty, configuration, configureOptions);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Registers a configuration instance which TOptions will bind against.</summary>
|
||||||
|
public static IServiceCollection Configure<TOptions>(this IServiceCollection services, string? name, IConfiguration configuration, Action<BinderOptions>? 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<IOptionsChangeTokenSource<TOptions>>(new ConfigurationChangeTokenSource<TOptions>(name, configuration));
|
||||||
|
return services.AddSingleton<Microsoft.Extensions.Options.IConfigureOptions<TOptions>>(new Microsoft.Extensions.Options.ConfigureNamedOptions<TOptions>(name, obj => BindCoreMain(configuration, obj, typeof(TOptions)configureOptions)));
|
||||||
|
}
|
||||||
|
#endregion IServiceCollection extensions.
|
||||||
|
|
||||||
|
#region Core binding extensions.
|
||||||
private readonly static Lazy<HashSet<string>> s_configKeys_ProgramMyClass2 = new(() => new HashSet<string>(StringComparer.OrdinalIgnoreCase) { "MyInt" });
|
private readonly static Lazy<HashSet<string>> s_configKeys_ProgramMyClass2 = new(() => new HashSet<string>(StringComparer.OrdinalIgnoreCase) { "MyInt" });
|
||||||
private readonly static Lazy<HashSet<string>> s_configKeys_ProgramMyClass = new(() => new HashSet<string>(StringComparer.OrdinalIgnoreCase) { "MyString", "MyInt", "MyList", "MyList2", "MyDictionary" });
|
private readonly static Lazy<HashSet<string>> s_configKeys_ProgramMyClass = new(() => new HashSet<string>(StringComparer.OrdinalIgnoreCase) { "MyString", "MyInt", "MyList", "MyList2", "MyDictionary" });
|
||||||
|
|
||||||
public static void BindCoreUntyped(this IConfiguration configuration, object obj, Type type, Action<BinderOptions>? configureOptions)
|
public static void BindCoreMain(IConfiguration configuration, object obj, Type type, Action<BinderOptions>? configureOptions)
|
||||||
{
|
{
|
||||||
if (configuration is null)
|
if (configuration is null)
|
||||||
{
|
{
|
||||||
throw new ArgumentNullException(nameof(configuration));
|
throw new ArgumentNullException(nameof(configuration));
|
||||||
}
|
}
|
||||||
|
|
||||||
BinderOptions? binderOptions = GetBinderOptions(configureOptions);
|
if (obj is null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(obj));
|
||||||
|
}
|
||||||
|
|
||||||
if (!HasValueOrChildren(configuration))
|
if (!HasValueOrChildren(configuration))
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BinderOptions? binderOptions = GetBinderOptions(configureOptions);
|
||||||
|
|
||||||
if (type == typeof(Program.MyClass))
|
if (type == typeof(Program.MyClass))
|
||||||
{
|
{
|
||||||
var temp = (Program.MyClass)obj;
|
var temp = (Program.MyClass)obj;
|
||||||
|
@ -67,16 +87,11 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
|
||||||
return;
|
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<int> obj, BinderOptions? binderOptions)
|
public static void BindCore(IConfiguration configuration, ref List<int> obj, BinderOptions? binderOptions)
|
||||||
{
|
{
|
||||||
if (obj is null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(obj));
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (IConfigurationSection section in configuration.GetChildren())
|
foreach (IConfigurationSection section in configuration.GetChildren())
|
||||||
{
|
{
|
||||||
if (section.Value is string value)
|
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)
|
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);
|
ValidateConfigurationKeys(typeof(Program.MyClass2), s_configKeys_ProgramMyClass2, configuration, binderOptions);
|
||||||
|
|
||||||
if (configuration["MyInt"] is string value1)
|
if (configuration["MyInt"] is string value1)
|
||||||
|
@ -103,11 +113,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
|
||||||
|
|
||||||
public static void BindCore(IConfiguration configuration, ref List<Program.MyClass2> obj, BinderOptions? binderOptions)
|
public static void BindCore(IConfiguration configuration, ref List<Program.MyClass2> obj, BinderOptions? binderOptions)
|
||||||
{
|
{
|
||||||
if (obj is null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(obj));
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (IConfigurationSection section in configuration.GetChildren())
|
foreach (IConfigurationSection section in configuration.GetChildren())
|
||||||
{
|
{
|
||||||
var value = new Program.MyClass2();
|
var value = new Program.MyClass2();
|
||||||
|
@ -118,11 +123,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
|
||||||
|
|
||||||
public static void BindCore(IConfiguration configuration, ref Dictionary<string, string> obj, BinderOptions? binderOptions)
|
public static void BindCore(IConfiguration configuration, ref Dictionary<string, string> obj, BinderOptions? binderOptions)
|
||||||
{
|
{
|
||||||
if (obj is null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(obj));
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (IConfigurationSection section in configuration.GetChildren())
|
foreach (IConfigurationSection section in configuration.GetChildren())
|
||||||
{
|
{
|
||||||
if (section.Value is string value)
|
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)
|
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);
|
ValidateConfigurationKeys(typeof(Program.MyClass), s_configKeys_ProgramMyClass, configuration, binderOptions);
|
||||||
|
|
||||||
obj.MyString = configuration["MyString"]!;
|
obj.MyString = configuration["MyString"]!;
|
||||||
|
@ -173,6 +168,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// <summary>If required by the binder options, validates that there are no unknown keys in the input configuration object.</summary>
|
/// <summary>If required by the binder options, validates that there are no unknown keys in the input configuration object.</summary>
|
||||||
public static void ValidateConfigurationKeys(Type type, Lazy<HashSet<string>> keys, IConfiguration configuration, BinderOptions? binderOptions)
|
public static void ValidateConfigurationKeys(Type type, Lazy<HashSet<string>> keys, IConfiguration configuration, BinderOptions? binderOptions)
|
||||||
{
|
{
|
||||||
|
@ -225,7 +221,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
|
||||||
|
|
||||||
if (binderOptions.BindNonPublicProperties)
|
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;
|
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);
|
throw new InvalidOperationException($"Failed to convert configuration value at '{getPath()}' to type '{typeof(int)}'.", exception);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endregion Core binding extensions.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,64 +2,84 @@
|
||||||
#nullable enable
|
#nullable enable
|
||||||
#pragma warning disable CS0612, CS0618 // Suppress warnings about [Obsolete] member usage in generated code.
|
#pragma warning disable CS0612, CS0618 // Suppress warnings about [Obsolete] member usage in generated code.
|
||||||
|
|
||||||
/// <summary>Generated helper providing an AOT and linking compatible implementation for configuration binding.</summary>
|
namespace System.Runtime.CompilerServices
|
||||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
|
|
||||||
internal static class GeneratedServiceCollectionBinder
|
|
||||||
{
|
{
|
||||||
/// <summary>Registers a configuration instance which TOptions will bind against.</summary>
|
using System;
|
||||||
public static global::Microsoft.Extensions.DependencyInjection.IServiceCollection Configure<TOptions>(this global::Microsoft.Extensions.DependencyInjection.IServiceCollection services, string? name, global::Microsoft.Extensions.Configuration.IConfiguration configuration) where TOptions : class
|
using System.CodeDom.Compiler;
|
||||||
|
|
||||||
|
[GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
|
||||||
|
[AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]
|
||||||
|
file sealed class InterceptsLocationAttribute : Attribute
|
||||||
{
|
{
|
||||||
return global::GeneratedServiceCollectionBinder.Configure<TOptions>(services, name, configuration, configureOptions: null);
|
public InterceptsLocationAttribute(string filePath, int line, int column)
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>Registers a configuration instance which TOptions will bind against.</summary>
|
|
||||||
public static global::Microsoft.Extensions.DependencyInjection.IServiceCollection Configure<TOptions>(this global::Microsoft.Extensions.DependencyInjection.IServiceCollection services, string? name, global::Microsoft.Extensions.Configuration.IConfiguration configuration, global::System.Action<global::Microsoft.Extensions.Configuration.BinderOptions>? 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<global::Microsoft.Extensions.Options.IOptionsChangeTokenSource<TOptions>>(services, new global::Microsoft.Extensions.Options.ConfigurationChangeTokenSource<TOptions>(name, configuration));
|
|
||||||
return global::Microsoft.Extensions.DependencyInjection.ServiceCollectionServiceExtensions.AddSingleton<global::Microsoft.Extensions.Options.IConfigureOptions<TOptions>>(services, new global::Microsoft.Extensions.Options.ConfigureNamedOptions<TOptions>(name, obj => global::Microsoft.Extensions.Configuration.Binder.SourceGeneration.CoreBindingHelper.BindCoreUntyped(configuration, obj, typeof(TOptions), configureOptions)));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
|
namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
|
||||||
{
|
{
|
||||||
using Microsoft.Extensions.Configuration;
|
using Microsoft.Extensions.Configuration;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using System;
|
using System;
|
||||||
using System.CodeDom.Compiler;
|
using System.CodeDom.Compiler;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
|
||||||
/// <summary>Provide core binding logic.</summary>
|
|
||||||
[GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
|
[GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
|
||||||
file static class CoreBindingHelper
|
file static class BindingExtensions
|
||||||
{
|
{
|
||||||
|
#region IServiceCollection extensions.
|
||||||
|
/// <summary>Registers a configuration instance which TOptions will bind against.</summary>
|
||||||
|
[InterceptsLocationAttribute(@"src-0.cs", 14, 18)]
|
||||||
|
public static IServiceCollection Configure<TOptions>(this IServiceCollection services, string? name, IConfiguration configuration) where TOptions : class
|
||||||
|
{
|
||||||
|
return Configure<TOptions>(services, name, configuration, configureOptions: null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Registers a configuration instance which TOptions will bind against.</summary>
|
||||||
|
public static IServiceCollection Configure<TOptions>(this IServiceCollection services, string? name, IConfiguration configuration, Action<BinderOptions>? 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<IOptionsChangeTokenSource<TOptions>>(new ConfigurationChangeTokenSource<TOptions>(name, configuration));
|
||||||
|
return services.AddSingleton<Microsoft.Extensions.Options.IConfigureOptions<TOptions>>(new Microsoft.Extensions.Options.ConfigureNamedOptions<TOptions>(name, obj => BindCoreMain(configuration, obj, typeof(TOptions)configureOptions)));
|
||||||
|
}
|
||||||
|
#endregion IServiceCollection extensions.
|
||||||
|
|
||||||
|
#region Core binding extensions.
|
||||||
private readonly static Lazy<HashSet<string>> s_configKeys_ProgramMyClass2 = new(() => new HashSet<string>(StringComparer.OrdinalIgnoreCase) { "MyInt" });
|
private readonly static Lazy<HashSet<string>> s_configKeys_ProgramMyClass2 = new(() => new HashSet<string>(StringComparer.OrdinalIgnoreCase) { "MyInt" });
|
||||||
private readonly static Lazy<HashSet<string>> s_configKeys_ProgramMyClass = new(() => new HashSet<string>(StringComparer.OrdinalIgnoreCase) { "MyString", "MyInt", "MyList", "MyList2", "MyDictionary" });
|
private readonly static Lazy<HashSet<string>> s_configKeys_ProgramMyClass = new(() => new HashSet<string>(StringComparer.OrdinalIgnoreCase) { "MyString", "MyInt", "MyList", "MyList2", "MyDictionary" });
|
||||||
|
|
||||||
public static void BindCoreUntyped(this IConfiguration configuration, object obj, Type type, Action<BinderOptions>? configureOptions)
|
public static void BindCoreMain(IConfiguration configuration, object obj, Type type, Action<BinderOptions>? configureOptions)
|
||||||
{
|
{
|
||||||
if (configuration is null)
|
if (configuration is null)
|
||||||
{
|
{
|
||||||
throw new ArgumentNullException(nameof(configuration));
|
throw new ArgumentNullException(nameof(configuration));
|
||||||
}
|
}
|
||||||
|
|
||||||
BinderOptions? binderOptions = GetBinderOptions(configureOptions);
|
if (obj is null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(obj));
|
||||||
|
}
|
||||||
|
|
||||||
if (!HasValueOrChildren(configuration))
|
if (!HasValueOrChildren(configuration))
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BinderOptions? binderOptions = GetBinderOptions(configureOptions);
|
||||||
|
|
||||||
if (type == typeof(Program.MyClass))
|
if (type == typeof(Program.MyClass))
|
||||||
{
|
{
|
||||||
var temp = (Program.MyClass)obj;
|
var temp = (Program.MyClass)obj;
|
||||||
|
@ -67,16 +87,11 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
|
||||||
return;
|
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<int> obj, BinderOptions? binderOptions)
|
public static void BindCore(IConfiguration configuration, ref List<int> obj, BinderOptions? binderOptions)
|
||||||
{
|
{
|
||||||
if (obj is null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(obj));
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (IConfigurationSection section in configuration.GetChildren())
|
foreach (IConfigurationSection section in configuration.GetChildren())
|
||||||
{
|
{
|
||||||
if (section.Value is string value)
|
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)
|
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);
|
ValidateConfigurationKeys(typeof(Program.MyClass2), s_configKeys_ProgramMyClass2, configuration, binderOptions);
|
||||||
|
|
||||||
if (configuration["MyInt"] is string value1)
|
if (configuration["MyInt"] is string value1)
|
||||||
|
@ -103,11 +113,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
|
||||||
|
|
||||||
public static void BindCore(IConfiguration configuration, ref List<Program.MyClass2> obj, BinderOptions? binderOptions)
|
public static void BindCore(IConfiguration configuration, ref List<Program.MyClass2> obj, BinderOptions? binderOptions)
|
||||||
{
|
{
|
||||||
if (obj is null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(obj));
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (IConfigurationSection section in configuration.GetChildren())
|
foreach (IConfigurationSection section in configuration.GetChildren())
|
||||||
{
|
{
|
||||||
var value = new Program.MyClass2();
|
var value = new Program.MyClass2();
|
||||||
|
@ -118,11 +123,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
|
||||||
|
|
||||||
public static void BindCore(IConfiguration configuration, ref Dictionary<string, string> obj, BinderOptions? binderOptions)
|
public static void BindCore(IConfiguration configuration, ref Dictionary<string, string> obj, BinderOptions? binderOptions)
|
||||||
{
|
{
|
||||||
if (obj is null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(obj));
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (IConfigurationSection section in configuration.GetChildren())
|
foreach (IConfigurationSection section in configuration.GetChildren())
|
||||||
{
|
{
|
||||||
if (section.Value is string value)
|
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)
|
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);
|
ValidateConfigurationKeys(typeof(Program.MyClass), s_configKeys_ProgramMyClass, configuration, binderOptions);
|
||||||
|
|
||||||
obj.MyString = configuration["MyString"]!;
|
obj.MyString = configuration["MyString"]!;
|
||||||
|
@ -173,6 +168,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// <summary>If required by the binder options, validates that there are no unknown keys in the input configuration object.</summary>
|
/// <summary>If required by the binder options, validates that there are no unknown keys in the input configuration object.</summary>
|
||||||
public static void ValidateConfigurationKeys(Type type, Lazy<HashSet<string>> keys, IConfiguration configuration, BinderOptions? binderOptions)
|
public static void ValidateConfigurationKeys(Type type, Lazy<HashSet<string>> keys, IConfiguration configuration, BinderOptions? binderOptions)
|
||||||
{
|
{
|
||||||
|
@ -225,7 +221,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
|
||||||
|
|
||||||
if (binderOptions.BindNonPublicProperties)
|
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;
|
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);
|
throw new InvalidOperationException($"Failed to convert configuration value at '{getPath()}' to type '{typeof(int)}'.", exception);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endregion Core binding extensions.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,58 +2,78 @@
|
||||||
#nullable enable
|
#nullable enable
|
||||||
#pragma warning disable CS0612, CS0618 // Suppress warnings about [Obsolete] member usage in generated code.
|
#pragma warning disable CS0612, CS0618 // Suppress warnings about [Obsolete] member usage in generated code.
|
||||||
|
|
||||||
/// <summary>Generated helper providing an AOT and linking compatible implementation for configuration binding.</summary>
|
namespace System.Runtime.CompilerServices
|
||||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
|
|
||||||
internal static class GeneratedServiceCollectionBinder
|
|
||||||
{
|
{
|
||||||
/// <summary>Registers a configuration instance which TOptions will bind against.</summary>
|
using System;
|
||||||
public static global::Microsoft.Extensions.DependencyInjection.IServiceCollection Configure<TOptions>(this global::Microsoft.Extensions.DependencyInjection.IServiceCollection services, string? name, global::Microsoft.Extensions.Configuration.IConfiguration configuration, global::System.Action<global::Microsoft.Extensions.Configuration.BinderOptions>? configureOptions) where TOptions : class
|
using System.CodeDom.Compiler;
|
||||||
|
|
||||||
|
[GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
|
||||||
|
[AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]
|
||||||
|
file sealed class InterceptsLocationAttribute : Attribute
|
||||||
{
|
{
|
||||||
if (services is null)
|
public InterceptsLocationAttribute(string filePath, int line, int column)
|
||||||
{
|
{
|
||||||
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<global::Microsoft.Extensions.Options.IOptionsChangeTokenSource<TOptions>>(services, new global::Microsoft.Extensions.Options.ConfigurationChangeTokenSource<TOptions>(name, configuration));
|
|
||||||
return global::Microsoft.Extensions.DependencyInjection.ServiceCollectionServiceExtensions.AddSingleton<global::Microsoft.Extensions.Options.IConfigureOptions<TOptions>>(services, new global::Microsoft.Extensions.Options.ConfigureNamedOptions<TOptions>(name, obj => global::Microsoft.Extensions.Configuration.Binder.SourceGeneration.CoreBindingHelper.BindCoreUntyped(configuration, obj, typeof(TOptions), configureOptions)));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
|
namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
|
||||||
{
|
{
|
||||||
using Microsoft.Extensions.Configuration;
|
using Microsoft.Extensions.Configuration;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using System;
|
using System;
|
||||||
using System.CodeDom.Compiler;
|
using System.CodeDom.Compiler;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
|
||||||
/// <summary>Provide core binding logic.</summary>
|
|
||||||
[GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
|
[GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "42.42.42.42")]
|
||||||
file static class CoreBindingHelper
|
file static class BindingExtensions
|
||||||
{
|
{
|
||||||
|
#region IServiceCollection extensions.
|
||||||
|
/// <summary>Registers a configuration instance which TOptions will bind against.</summary>
|
||||||
|
[InterceptsLocationAttribute(@"src-0.cs", 14, 18)]
|
||||||
|
public static IServiceCollection Configure<TOptions>(this IServiceCollection services, string? name, IConfiguration configuration, Action<BinderOptions>? 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<IOptionsChangeTokenSource<TOptions>>(new ConfigurationChangeTokenSource<TOptions>(name, configuration));
|
||||||
|
return services.AddSingleton<Microsoft.Extensions.Options.IConfigureOptions<TOptions>>(new Microsoft.Extensions.Options.ConfigureNamedOptions<TOptions>(name, obj => BindCoreMain(configuration, obj, typeof(TOptions)configureOptions)));
|
||||||
|
}
|
||||||
|
#endregion IServiceCollection extensions.
|
||||||
|
|
||||||
|
#region Core binding extensions.
|
||||||
private readonly static Lazy<HashSet<string>> s_configKeys_ProgramMyClass2 = new(() => new HashSet<string>(StringComparer.OrdinalIgnoreCase) { "MyInt" });
|
private readonly static Lazy<HashSet<string>> s_configKeys_ProgramMyClass2 = new(() => new HashSet<string>(StringComparer.OrdinalIgnoreCase) { "MyInt" });
|
||||||
private readonly static Lazy<HashSet<string>> s_configKeys_ProgramMyClass = new(() => new HashSet<string>(StringComparer.OrdinalIgnoreCase) { "MyString", "MyInt", "MyList", "MyList2", "MyDictionary" });
|
private readonly static Lazy<HashSet<string>> s_configKeys_ProgramMyClass = new(() => new HashSet<string>(StringComparer.OrdinalIgnoreCase) { "MyString", "MyInt", "MyList", "MyList2", "MyDictionary" });
|
||||||
|
|
||||||
public static void BindCoreUntyped(this IConfiguration configuration, object obj, Type type, Action<BinderOptions>? configureOptions)
|
public static void BindCoreMain(IConfiguration configuration, object obj, Type type, Action<BinderOptions>? configureOptions)
|
||||||
{
|
{
|
||||||
if (configuration is null)
|
if (configuration is null)
|
||||||
{
|
{
|
||||||
throw new ArgumentNullException(nameof(configuration));
|
throw new ArgumentNullException(nameof(configuration));
|
||||||
}
|
}
|
||||||
|
|
||||||
BinderOptions? binderOptions = GetBinderOptions(configureOptions);
|
if (obj is null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(obj));
|
||||||
|
}
|
||||||
|
|
||||||
if (!HasValueOrChildren(configuration))
|
if (!HasValueOrChildren(configuration))
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BinderOptions? binderOptions = GetBinderOptions(configureOptions);
|
||||||
|
|
||||||
if (type == typeof(Program.MyClass))
|
if (type == typeof(Program.MyClass))
|
||||||
{
|
{
|
||||||
var temp = (Program.MyClass)obj;
|
var temp = (Program.MyClass)obj;
|
||||||
|
@ -61,16 +81,11 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
|
||||||
return;
|
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<int> obj, BinderOptions? binderOptions)
|
public static void BindCore(IConfiguration configuration, ref List<int> obj, BinderOptions? binderOptions)
|
||||||
{
|
{
|
||||||
if (obj is null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(obj));
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (IConfigurationSection section in configuration.GetChildren())
|
foreach (IConfigurationSection section in configuration.GetChildren())
|
||||||
{
|
{
|
||||||
if (section.Value is string value)
|
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)
|
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);
|
ValidateConfigurationKeys(typeof(Program.MyClass2), s_configKeys_ProgramMyClass2, configuration, binderOptions);
|
||||||
|
|
||||||
if (configuration["MyInt"] is string value1)
|
if (configuration["MyInt"] is string value1)
|
||||||
|
@ -97,11 +107,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
|
||||||
|
|
||||||
public static void BindCore(IConfiguration configuration, ref List<Program.MyClass2> obj, BinderOptions? binderOptions)
|
public static void BindCore(IConfiguration configuration, ref List<Program.MyClass2> obj, BinderOptions? binderOptions)
|
||||||
{
|
{
|
||||||
if (obj is null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(obj));
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (IConfigurationSection section in configuration.GetChildren())
|
foreach (IConfigurationSection section in configuration.GetChildren())
|
||||||
{
|
{
|
||||||
var value = new Program.MyClass2();
|
var value = new Program.MyClass2();
|
||||||
|
@ -112,11 +117,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
|
||||||
|
|
||||||
public static void BindCore(IConfiguration configuration, ref Dictionary<string, string> obj, BinderOptions? binderOptions)
|
public static void BindCore(IConfiguration configuration, ref Dictionary<string, string> obj, BinderOptions? binderOptions)
|
||||||
{
|
{
|
||||||
if (obj is null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(obj));
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (IConfigurationSection section in configuration.GetChildren())
|
foreach (IConfigurationSection section in configuration.GetChildren())
|
||||||
{
|
{
|
||||||
if (section.Value is string value)
|
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)
|
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);
|
ValidateConfigurationKeys(typeof(Program.MyClass), s_configKeys_ProgramMyClass, configuration, binderOptions);
|
||||||
|
|
||||||
obj.MyString = configuration["MyString"]!;
|
obj.MyString = configuration["MyString"]!;
|
||||||
|
@ -167,6 +162,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// <summary>If required by the binder options, validates that there are no unknown keys in the input configuration object.</summary>
|
/// <summary>If required by the binder options, validates that there are no unknown keys in the input configuration object.</summary>
|
||||||
public static void ValidateConfigurationKeys(Type type, Lazy<HashSet<string>> keys, IConfiguration configuration, BinderOptions? binderOptions)
|
public static void ValidateConfigurationKeys(Type type, Lazy<HashSet<string>> keys, IConfiguration configuration, BinderOptions? binderOptions)
|
||||||
{
|
{
|
||||||
|
@ -219,7 +215,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
|
||||||
|
|
||||||
if (binderOptions.BindNonPublicProperties)
|
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;
|
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);
|
throw new InvalidOperationException($"Failed to convert configuration value at '{getPath()}' to type '{typeof(int)}'.", exception);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endregion Core binding extensions.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration.Tests
|
||||||
{
|
{
|
||||||
public partial class ConfigurationBindingGeneratorTests
|
public partial class ConfigurationBindingGeneratorTests
|
||||||
{
|
{
|
||||||
|
#region IServiceCollection extensions.
|
||||||
private string GetConfigureSource(string paramList) => $$"""
|
private string GetConfigureSource(string paramList) => $$"""
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using Microsoft.Extensions.Configuration;
|
using Microsoft.Extensions.Configuration;
|
||||||
|
@ -40,7 +41,9 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration.Tests
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
""";
|
""";
|
||||||
|
#endregion IServiceCollection extensions.
|
||||||
|
|
||||||
|
#region OptionsBuilder<T> extensions.
|
||||||
[Fact]
|
[Fact]
|
||||||
public async Task Configure_T() =>
|
public async Task Configure_T() =>
|
||||||
await VerifyAgainstBaselineUsingFile("Configure_T.generated.txt", GetConfigureSource("section"), extType: ExtensionClassType.ServiceCollection);
|
await VerifyAgainstBaselineUsingFile("Configure_T.generated.txt", GetConfigureSource("section"), extType: ExtensionClassType.ServiceCollection);
|
||||||
|
@ -126,5 +129,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration.Tests
|
||||||
await VerifyAgainstBaselineUsingFile("BindConfiguration.generated.txt", GetSource(), extType: ExtensionClassType.OptionsBuilder);
|
await VerifyAgainstBaselineUsingFile("BindConfiguration.generated.txt", GetSource(), extType: ExtensionClassType.OptionsBuilder);
|
||||||
await VerifyAgainstBaselineUsingFile("BindConfiguration.generated.txt", GetSource(@", _ => { }"), extType: ExtensionClassType.OptionsBuilder);
|
await VerifyAgainstBaselineUsingFile("BindConfiguration.generated.txt", GetSource(@", _ => { }"), extType: ExtensionClassType.OptionsBuilder);
|
||||||
}
|
}
|
||||||
|
#endregion OptionsBuilder<T> extensions.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,6 @@
|
||||||
// The .NET Foundation licenses this file to you under the MIT license.
|
// The .NET Foundation licenses this file to you under the MIT license.
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Globalization;
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.CodeAnalysis;
|
using Microsoft.CodeAnalysis;
|
||||||
|
@ -44,7 +43,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration.Tests
|
||||||
|
|
||||||
[Theory]
|
[Theory]
|
||||||
[InlineData(LanguageVersion.Preview)]
|
[InlineData(LanguageVersion.Preview)]
|
||||||
[InlineData(LanguageVersion.CSharp11)]
|
|
||||||
public async Task Bind(LanguageVersion langVersion) =>
|
public async Task Bind(LanguageVersion langVersion) =>
|
||||||
await VerifyAgainstBaselineUsingFile("Bind.generated.txt", BindCallSampleCode, langVersion, extType: ExtensionClassType.ConfigurationBinder);
|
await VerifyAgainstBaselineUsingFile("Bind.generated.txt", BindCallSampleCode, langVersion, extType: ExtensionClassType.ConfigurationBinder);
|
||||||
|
|
||||||
|
@ -651,7 +649,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration.Tests
|
||||||
|
|
||||||
await VerifyAgainstBaselineUsingFile("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()));
|
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(3, d.Where(diag => diag.Id == Diagnostics.TypeNotSupported.Id).Count());
|
||||||
Assert.Equal(6, d.Where(diag => diag.Id == Diagnostics.PropertyNotSupported.Id).Count());
|
Assert.Equal(6, d.Where(diag => diag.Id == Diagnostics.PropertyNotSupported.Id).Count());
|
||||||
});
|
});
|
||||||
|
|
|
@ -52,15 +52,17 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration.Tests
|
||||||
ServiceCollection,
|
ServiceCollection,
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Theory]
|
||||||
public async Task LangVersionMustBeCharp11OrHigher()
|
[InlineData(LanguageVersion.CSharp11)]
|
||||||
|
[InlineData(LanguageVersion.CSharp10)]
|
||||||
|
public async Task LangVersionMustBeCharp12OrHigher(LanguageVersion langVersion)
|
||||||
{
|
{
|
||||||
var (d, r) = await RunGenerator(BindCallSampleCode, LanguageVersion.CSharp10);
|
var (d, r) = await RunGenerator(BindCallSampleCode, langVersion);
|
||||||
Assert.Empty(r);
|
Assert.Empty(r);
|
||||||
|
|
||||||
Diagnostic diagnostic = Assert.Single(d);
|
Diagnostic diagnostic = Assert.Single(d);
|
||||||
Assert.True(diagnostic.Id == "SYSLIB1102");
|
Assert.True(diagnostic.Id == "SYSLIB1102");
|
||||||
Assert.Contains("C# 11", diagnostic.Descriptor.Title.ToString(CultureInfo.InvariantCulture));
|
Assert.Contains("C# 12", diagnostic.Descriptor.Title.ToString(CultureInfo.InvariantCulture));
|
||||||
Assert.Equal(DiagnosticSeverity.Error, diagnostic.Severity);
|
Assert.Equal(DiagnosticSeverity.Error, diagnostic.Severity);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -250,9 +252,9 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration.Tests
|
||||||
Assert.Single(r);
|
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(this global::Microsoft.Extensions.Configuration.IConfiguration configuration, global::Program.MyClass0 obj) => {{ }};", generatedSource);
|
Assert.Contains("public static void Bind_ProgramMyClass0(this IConfiguration configuration, object? obj)", generatedSource);
|
||||||
Assert.Contains($"public static void Bind(this global::Microsoft.Extensions.Configuration.IConfiguration configuration, global::Program.MyClass1 obj, global::System.Action<global::Microsoft.Extensions.Configuration.BinderOptions>? configureOptions) => {{ }};", generatedSource);
|
Assert.Contains("public static void Bind_ProgramMyClass1(this IConfiguration configuration, object? obj, Action<BinderOptions>? configureOptions)", generatedSource);
|
||||||
Assert.Contains($"public static void Bind(this global::Microsoft.Extensions.Configuration.IConfiguration configuration, string key, global::Program.MyClass2 obj) => {{ }};", generatedSource);
|
Assert.Contains("public static void Bind_ProgramMyClass2(this IConfiguration configuration, string key, object? obj)", generatedSource);
|
||||||
|
|
||||||
Assert.Empty(d);
|
Assert.Empty(d);
|
||||||
}
|
}
|
||||||
|
@ -395,7 +397,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration.Tests
|
||||||
|
|
||||||
private static async Task<(ImmutableArray<Diagnostic>, ImmutableArray<GeneratedSourceResult>)> RunGenerator(
|
private static async Task<(ImmutableArray<Diagnostic>, ImmutableArray<GeneratedSourceResult>)> RunGenerator(
|
||||||
string testSourceCode,
|
string testSourceCode,
|
||||||
LanguageVersion langVersion = LanguageVersion.CSharp11,
|
LanguageVersion langVersion = LanguageVersion.Preview,
|
||||||
IEnumerable<Assembly>? references = null) =>
|
IEnumerable<Assembly>? references = null) =>
|
||||||
await RoslynTestUtils.RunGenerator(
|
await RoslynTestUtils.RunGenerator(
|
||||||
new ConfigurationBindingGenerator(),
|
new ConfigurationBindingGenerator(),
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
<EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles>
|
<EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles>
|
||||||
<!-- Type not supported; property on type not suppported -->
|
<!-- Type not supported; property on type not suppported -->
|
||||||
<NoWarn>SYSLIB1100,SYSLIB1101</NoWarn>
|
<NoWarn>SYSLIB1100,SYSLIB1101</NoWarn>
|
||||||
<!-- The SDK disables the configuration binding generator by default no matter how it was referenced, so we need to enable it here for testing. -->
|
<Features>$(Features);InterceptorsPreview</Features>
|
||||||
<EnableConfigurationBindingGenerator>true</EnableConfigurationBindingGenerator>
|
<EnableConfigurationBindingGenerator>true</EnableConfigurationBindingGenerator>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFrameworks>$(NetCoreAppCurrent);$(NetCoreAppPrevious);$(NetCoreAppMinimum);netstandard2.0;$(NetFrameworkMinimum)</TargetFrameworks>
|
<TargetFrameworks>$(NetCoreAppCurrent);$(NetCoreAppPrevious);$(NetCoreAppMinimum);netstandard2.0;$(NetFrameworkMinimum)</TargetFrameworks>
|
||||||
<EnableDefaultItems>true</EnableDefaultItems>
|
<EnableDefaultItems>true</EnableDefaultItems>
|
||||||
|
<Features>$(Features);InterceptorsPreview</Features>
|
||||||
<EnableConfigurationBindingGenerator>true</EnableConfigurationBindingGenerator>
|
<EnableConfigurationBindingGenerator>true</EnableConfigurationBindingGenerator>
|
||||||
<IsPackable>true</IsPackable>
|
<IsPackable>true</IsPackable>
|
||||||
<PackageDescription>Configuration support for Microsoft.Extensions.Logging.</PackageDescription>
|
<PackageDescription>Configuration support for Microsoft.Extensions.Logging.</PackageDescription>
|
||||||
|
|
|
@ -7,7 +7,9 @@
|
||||||
<DefineConstants>$(DefineConstants);NO_SUPPRESS_GC_TRANSITION</DefineConstants>
|
<DefineConstants>$(DefineConstants);NO_SUPPRESS_GC_TRANSITION</DefineConstants>
|
||||||
<IncludePlatformAttributes>true</IncludePlatformAttributes>
|
<IncludePlatformAttributes>true</IncludePlatformAttributes>
|
||||||
<IsPackable>true</IsPackable>
|
<IsPackable>true</IsPackable>
|
||||||
|
<Features>$(Features);InterceptorsPreview</Features>
|
||||||
<EnableConfigurationBindingGenerator>true</EnableConfigurationBindingGenerator>
|
<EnableConfigurationBindingGenerator>true</EnableConfigurationBindingGenerator>
|
||||||
|
<EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles>
|
||||||
<PackageDescription>Console logger provider implementation for Microsoft.Extensions.Logging.</PackageDescription>
|
<PackageDescription>Console logger provider implementation for Microsoft.Extensions.Logging.</PackageDescription>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
|
|
|
@ -2,9 +2,9 @@
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
<TargetFrameworks>$(NetCoreAppCurrent);$(NetFrameworkMinimum)</TargetFrameworks>
|
<TargetFrameworks>$(NetCoreAppCurrent);$(NetFrameworkMinimum)</TargetFrameworks>
|
||||||
<EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles>
|
|
||||||
<DefineConstants>$(DefineConstants);BUILDING_SOURCE_GENERATOR_TESTS;ROSLYN4_0_OR_GREATER;ROSLYN4_4_OR_GREATER</DefineConstants>
|
<DefineConstants>$(DefineConstants);BUILDING_SOURCE_GENERATOR_TESTS;ROSLYN4_0_OR_GREATER;ROSLYN4_4_OR_GREATER</DefineConstants>
|
||||||
<!-- The SDK disables the configuration binding generator by default no matter how it was referenced, so we need to enable it here for testing. -->
|
<Features>$(Features);InterceptorsPreview</Features>
|
||||||
|
<EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles>
|
||||||
<EnableConfigurationBindingGenerator>true</EnableConfigurationBindingGenerator>
|
<EnableConfigurationBindingGenerator>true</EnableConfigurationBindingGenerator>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue