Skip to content

Configuration Binder source generator generates uncompilable code for SslClientAuthenticationOptions #107003

@eerhardt

Description

@eerhardt

Description

When trying to use the Configuration Binder source generator in the .NET Aspire Dashboard, I'm getting compile errors.

See https://github.com/dotnet/aspire/blob/4251f912cf9f516eae6917788578185d1939887d/src/Aspire.Dashboard/ResourceService/DashboardClient.cs#L130 for the original location that runs into this. I've extracted the case in the repro steps below.

Reproduction Steps

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <TargetFramework>net8.0</TargetFramework>
    <Nullable>enable</Nullable>
    <ImplicitUsings>enable</ImplicitUsings>
    <EnableConfigurationBindingGenerator>true</EnableConfigurationBindingGenerator>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Microsoft.Extensions.Configuration" Version="9.0.0-preview.7.24405.7" />
    <PackageReference Include="Microsoft.Extensions.Configuration.Binder" Version="9.0.0-preview.7.24405.7" />
  </ItemGroup>
</Project>
using Microsoft.Extensions.Configuration;
using System.Net.Security;

IConfigurationSection c = new ConfigurationBuilder().Build().GetSection("Options");
c.Get<SslClientAuthenticationOptions>();

dotnet build the above.

Expected behavior

The project should build successfully.

Actual behavior

There are 2 build errors:

image

The name 'InitializeCipherSuitesPolicy' does not exist in the current context
Argument 1: cannot convert from 'System.ReadOnlyMemory' to 'byte[]'

Here is the generated code:

Click to expand

Generated Code

// <auto-generated/>

#nullable enable annotations
#nullable disable warnings

// Suppress warnings about [Obsolete] member usage in generated code.
#pragma warning disable CS0612, CS0618

namespace System.Runtime.CompilerServices
{
    using System;
    using System.CodeDom.Compiler;

    [GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "9.0.10.40507")]
    [AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]
    file sealed class InterceptsLocationAttribute : Attribute
    {
        public InterceptsLocationAttribute(int version, string data)
        {
        }
    }
}

namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration
{
    using Microsoft.Extensions.Configuration;
    using System;
    using System.CodeDom.Compiler;
    using System.Collections.Generic;
    using System.Globalization;
    using System.Linq;
    using System.Runtime.CompilerServices;

    [GeneratedCode("Microsoft.Extensions.Configuration.Binder.SourceGeneration", "9.0.10.40507")]
    file static class BindingExtensions
    {
        #region IConfiguration extensions.
        /// <summary>Attempts to bind the configuration instance to a new instance of type T.</summary>
        [InterceptsLocation(1, "akE8tCV3pXJvEgp69Un+26AAAABQcm9ncmFtLmNz")] // C:\Users\eerhardt\source\repos\ConsoleApp132\ConsoleApp132\Program.cs(5,3)
        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_ReadOnlySpanByte = new(() => new HashSet<string>(StringComparer.OrdinalIgnoreCase) { "Length", "Empty", "IsEmpty" });
        private readonly static Lazy<HashSet<string>> s_configKeys_ReadOnlyMemoryByte = new(() => new HashSet<string>(StringComparer.OrdinalIgnoreCase) { "Empty", "IsEmpty", "Length", "Span" });
        private readonly static Lazy<HashSet<string>> s_configKeys_SslApplicationProtocol = new(() => new HashSet<string>(StringComparer.OrdinalIgnoreCase) { "Protocol" });
        private readonly static Lazy<HashSet<string>> s_configKeys_Oid = new(() => new HashSet<string>(StringComparer.OrdinalIgnoreCase) { "FriendlyName", "Value" });
        private readonly static Lazy<HashSet<string>> s_configKeys_X509Extension = new(() => new HashSet<string>(StringComparer.OrdinalIgnoreCase) { "Critical", "Oid", "RawData" });
        private readonly static Lazy<HashSet<string>> s_configKeys_X500DistinguishedName = new(() => new HashSet<string>(StringComparer.OrdinalIgnoreCase) { "Name", "Oid", "RawData" });
        private readonly static Lazy<HashSet<string>> s_configKeys_KeySizes = new(() => new HashSet<string>(StringComparer.OrdinalIgnoreCase) { "MinSize", "MaxSize", "SkipSize" });
        private readonly static Lazy<HashSet<string>> s_configKeys_AsymmetricAlgorithm = new(() => new HashSet<string>(StringComparer.OrdinalIgnoreCase) { "KeyExchangeAlgorithm", "KeySize", "LegalKeySizes", "SignatureAlgorithm" });
        private readonly static Lazy<HashSet<string>> s_configKeys_AsnEncodedData = new(() => new HashSet<string>(StringComparer.OrdinalIgnoreCase) { "RawData", "Oid" });
        private readonly static Lazy<HashSet<string>> s_configKeys_PublicKey = new(() => new HashSet<string>(StringComparer.OrdinalIgnoreCase) { "Key", "EncodedKeyValue", "EncodedParameters", "Oid" });
        private readonly static Lazy<HashSet<string>> s_configKeys_X509Certificate2 = new(() => new HashSet<string>(StringComparer.OrdinalIgnoreCase) { "Archived", "Extensions", "FriendlyName", "HasPrivateKey", "IssuerName", "NotAfter", "NotBefore", "PrivateKey", "PublicKey", "RawData", "RawDataMemory", "SerialNumber", "SignatureAlgorithm", "SubjectName", "Thumbprint", "Version", "Issuer", "SerialNumberBytes", "Subject" });
        private readonly static Lazy<HashSet<string>> s_configKeys_X509ChainPolicy = new(() => new HashSet<string>(StringComparer.OrdinalIgnoreCase) { "ApplicationPolicy", "CertificatePolicy", "CustomTrustStore", "DisableCertificateDownloads", "ExtraStore", "RevocationFlag", "RevocationMode", "TrustMode", "UrlRetrievalTimeout", "VerificationFlags", "VerificationTime", "VerificationTimeIgnored" });
        private readonly static Lazy<HashSet<string>> s_configKeys_SslStreamCertificateContext = new(() => new HashSet<string>(StringComparer.OrdinalIgnoreCase) { "IntermediateCertificates", "TargetCertificate" });
        private readonly static Lazy<HashSet<string>> s_configKeys_SslClientAuthenticationOptions = new(() => new HashSet<string>(StringComparer.OrdinalIgnoreCase) { "AllowRenegotiation", "AllowTlsResume", "ApplicationProtocols", "CertificateChainPolicy", "CertificateRevocationCheckMode", "CipherSuitesPolicy", "ClientCertificateContext", "ClientCertificates", "EnabledSslProtocols", "EncryptionPolicy", "TargetHost" });

        public static object? GetCore(this IConfiguration configuration, Type type, Action<BinderOptions>? configureOptions)
        {
            ArgumentNullException.ThrowIfNull(configuration);

            BinderOptions? binderOptions = GetBinderOptions(configureOptions);

            if (!HasValueOrChildren(configuration))
            {
                return null;
            }

            if (type == typeof(global::System.Net.Security.SslClientAuthenticationOptions))
            {
                var instance = new global::System.Net.Security.SslClientAuthenticationOptions();
                BindCore(configuration, ref instance, defaultValueIfNotFound: true, binderOptions);
                return instance;
            }

            throw new NotSupportedException($"Unable to bind to type '{type}': generator did not detect the type as input.");
        }

        public static void BindCore(IConfiguration configuration, ref global::System.ReadOnlySpan<byte> instance, bool defaultValueIfNotFound, BinderOptions? binderOptions)
        {
            ValidateConfigurationKeys(typeof(global::System.ReadOnlySpan<byte>), s_configKeys_ReadOnlySpanByte, configuration, binderOptions);

            if (AsConfigWithChildren(configuration.GetSection("Empty")) is IConfigurationSection section1)
            {
            }
        }

        public static void BindCore(IConfiguration configuration, ref global::System.ReadOnlyMemory<byte> instance, bool defaultValueIfNotFound, BinderOptions? binderOptions)
        {
            ValidateConfigurationKeys(typeof(global::System.ReadOnlyMemory<byte>), s_configKeys_ReadOnlyMemoryByte, configuration, binderOptions);

            if (AsConfigWithChildren(configuration.GetSection("Empty")) is IConfigurationSection section3)
            {
            }

            if (AsConfigWithChildren(configuration.GetSection("Span")) is IConfigurationSection section5)
            {
            }
        }

        public static void BindCore(IConfiguration configuration, ref global::System.Net.Security.SslApplicationProtocol instance, bool defaultValueIfNotFound, BinderOptions? binderOptions)
        {
            ValidateConfigurationKeys(typeof(global::System.Net.Security.SslApplicationProtocol), s_configKeys_SslApplicationProtocol, configuration, binderOptions);

            if (AsConfigWithChildren(configuration.GetSection("Protocol")) is IConfigurationSection section7)
            {
            }
        }

        public static void BindCore(IConfiguration configuration, ref global::System.Collections.Generic.List<global::System.Net.Security.SslApplicationProtocol> instance, bool defaultValueIfNotFound, BinderOptions? binderOptions)
        {
            foreach (IConfigurationSection section in configuration.GetChildren())
            {
                if (!string.IsNullOrEmpty(section.Value) && !section.GetChildren().Any())
                {
                    continue;
                }
                var value = InitializeSslApplicationProtocol(section, binderOptions);
                BindCore(section, ref value, defaultValueIfNotFound: false, binderOptions);
                instance.Add(value);
            }
        }

        public static void BindCore(IConfiguration configuration, ref global::System.Security.Cryptography.Oid instance, bool defaultValueIfNotFound, BinderOptions? binderOptions)
        {
            ValidateConfigurationKeys(typeof(global::System.Security.Cryptography.Oid), s_configKeys_Oid, configuration, binderOptions);

            if (configuration["FriendlyName"] is string value10)
            {
                instance.FriendlyName = value10;
            }
            else if (defaultValueIfNotFound)
            {
                var currentValue = instance.FriendlyName;
                if (currentValue is not null)
                {
                    instance.FriendlyName = currentValue;
                }
            }

            if (configuration["Value"] is string value11)
            {
                instance.Value = value11;
            }
            else if (defaultValueIfNotFound)
            {
                var currentValue = instance.Value;
                if (currentValue is not null)
                {
                    instance.Value = currentValue;
                }
            }
        }

        public static void BindCore(IConfiguration configuration, ref global::System.Security.Cryptography.X509Certificates.X509Extension instance, bool defaultValueIfNotFound, BinderOptions? binderOptions)
        {
            ValidateConfigurationKeys(typeof(global::System.Security.Cryptography.X509Certificates.X509Extension), s_configKeys_X509Extension, configuration, binderOptions);

            if (configuration["Critical"] is string value12)
            {
                instance.Critical = ParseBool(value12, configuration.GetSection("Critical").Path);
            }
            else if (defaultValueIfNotFound)
            {
                instance.Critical = instance.Critical;
            }

            if (AsConfigWithChildren(configuration.GetSection("Oid")) is IConfigurationSection section13)
            {
                global::System.Security.Cryptography.Oid? temp15 = instance.Oid;
                temp15 ??= new global::System.Security.Cryptography.Oid();
                BindCore(section13, ref temp15, defaultValueIfNotFound: false, binderOptions);
                instance.Oid = temp15;
            }

            if (configuration["RawData"] is string value16)
            {
                instance.RawData = ParseByteArray(value16, configuration.GetSection("RawData").Path);
            }
            else if (defaultValueIfNotFound)
            {
                var currentValue = instance.RawData;
                if (currentValue is not null)
                {
                    instance.RawData = currentValue;
                }
            }
        }

        public static void BindCore(IConfiguration configuration, ref global::System.Security.Cryptography.X509Certificates.X509ExtensionCollection instance, bool defaultValueIfNotFound, BinderOptions? binderOptions)
        {
            foreach (IConfigurationSection section in configuration.GetChildren())
            {
            }
        }

        public static void BindCore(IConfiguration configuration, ref global::System.Security.Cryptography.X509Certificates.X500DistinguishedName instance, bool defaultValueIfNotFound, BinderOptions? binderOptions)
        {
            ValidateConfigurationKeys(typeof(global::System.Security.Cryptography.X509Certificates.X500DistinguishedName), s_configKeys_X500DistinguishedName, configuration, binderOptions);

            if (AsConfigWithChildren(configuration.GetSection("Oid")) is IConfigurationSection section17)
            {
                global::System.Security.Cryptography.Oid? temp19 = instance.Oid;
                temp19 ??= new global::System.Security.Cryptography.Oid();
                BindCore(section17, ref temp19, defaultValueIfNotFound: false, binderOptions);
                instance.Oid = temp19;
            }

            if (configuration["RawData"] is string value20)
            {
                instance.RawData = ParseByteArray(value20, configuration.GetSection("RawData").Path);
            }
            else if (defaultValueIfNotFound)
            {
                var currentValue = instance.RawData;
                if (currentValue is not null)
                {
                    instance.RawData = currentValue;
                }
            }
        }

        public static void BindCore(IConfiguration configuration, ref global::System.Security.Cryptography.KeySizes instance, bool defaultValueIfNotFound, BinderOptions? binderOptions)
        {
            ValidateConfigurationKeys(typeof(global::System.Security.Cryptography.KeySizes), s_configKeys_KeySizes, configuration, binderOptions);
        }

        public static void BindCore(IConfiguration configuration, ref global::System.Security.Cryptography.KeySizes[] instance, bool defaultValueIfNotFound, BinderOptions? binderOptions)
        {
            var temp21 = new List<global::System.Security.Cryptography.KeySizes>();

            foreach (IConfigurationSection section in configuration.GetChildren())
            {
                if (!string.IsNullOrEmpty(section.Value) && !section.GetChildren().Any())
                {
                    continue;
                }
                var value = InitializeKeySizes(section, binderOptions);
                BindCore(section, ref value, defaultValueIfNotFound: false, binderOptions);
                temp21.Add(value);
            }

            int originalCount = instance.Length;
            Array.Resize(ref instance, originalCount + temp21.Count);
            temp21.CopyTo(instance, originalCount);
        }

        public static void BindCore(IConfiguration configuration, ref global::System.Security.Cryptography.AsymmetricAlgorithm instance, bool defaultValueIfNotFound, BinderOptions? binderOptions)
        {
            ValidateConfigurationKeys(typeof(global::System.Security.Cryptography.AsymmetricAlgorithm), s_configKeys_AsymmetricAlgorithm, configuration, binderOptions);

            if (configuration["KeySize"] is string value23)
            {
                instance.KeySize = ParseInt(value23, configuration.GetSection("KeySize").Path);
            }
            else if (defaultValueIfNotFound)
            {
                instance.KeySize = instance.KeySize;
            }

            if (AsConfigWithChildren(configuration.GetSection("LegalKeySizes")) is IConfigurationSection section24)
            {
                global::System.Security.Cryptography.KeySizes[]? temp26 = instance.LegalKeySizes;
                temp26 ??= new global::System.Security.Cryptography.KeySizes[0];
                BindCore(section24, ref temp26, defaultValueIfNotFound: false, binderOptions);
            }
        }

        public static void BindCore(IConfiguration configuration, ref global::System.Security.Cryptography.AsnEncodedData instance, bool defaultValueIfNotFound, BinderOptions? binderOptions)
        {
            ValidateConfigurationKeys(typeof(global::System.Security.Cryptography.AsnEncodedData), s_configKeys_AsnEncodedData, configuration, binderOptions);

            if (AsConfigWithChildren(configuration.GetSection("Oid")) is IConfigurationSection section27)
            {
                global::System.Security.Cryptography.Oid? temp29 = instance.Oid;
                temp29 ??= new global::System.Security.Cryptography.Oid();
                BindCore(section27, ref temp29, defaultValueIfNotFound: false, binderOptions);
                instance.Oid = temp29;
            }

            if (configuration["RawData"] is string value30)
            {
                instance.RawData = ParseByteArray(value30, configuration.GetSection("RawData").Path);
            }
            else if (defaultValueIfNotFound)
            {
                var currentValue = instance.RawData;
                if (currentValue is not null)
                {
                    instance.RawData = currentValue;
                }
            }
        }

        public static void BindCore(IConfiguration configuration, ref global::System.Security.Cryptography.X509Certificates.PublicKey instance, bool defaultValueIfNotFound, BinderOptions? binderOptions)
        {
            ValidateConfigurationKeys(typeof(global::System.Security.Cryptography.X509Certificates.PublicKey), s_configKeys_PublicKey, configuration, binderOptions);

            if (AsConfigWithChildren(configuration.GetSection("EncodedKeyValue")) is IConfigurationSection section31)
            {
                global::System.Security.Cryptography.AsnEncodedData? temp33 = instance.EncodedKeyValue;
                if (temp33 is not null)
                {
                    BindCore(section31, ref temp33, defaultValueIfNotFound: false, binderOptions);
                }
                else
                {
                    throw new InvalidOperationException("Cannot create instance of type 'System.Security.Cryptography.AsnEncodedData' because it has multiple public parameterized constructors.");
                }
            }

            if (AsConfigWithChildren(configuration.GetSection("EncodedParameters")) is IConfigurationSection section34)
            {
                global::System.Security.Cryptography.AsnEncodedData? temp36 = instance.EncodedParameters;
                if (temp36 is not null)
                {
                    BindCore(section34, ref temp36, defaultValueIfNotFound: false, binderOptions);
                }
                else
                {
                    throw new InvalidOperationException("Cannot create instance of type 'System.Security.Cryptography.AsnEncodedData' because it has multiple public parameterized constructors.");
                }
            }

            if (AsConfigWithChildren(configuration.GetSection("Key")) is IConfigurationSection section37)
            {
                global::System.Security.Cryptography.AsymmetricAlgorithm? temp39 = instance.Key;
                if (temp39 is not null)
                {
                    BindCore(section37, ref temp39, defaultValueIfNotFound: false, binderOptions);
                }
                else
                {
                    throw new InvalidOperationException("Cannot create instance of type 'System.Security.Cryptography.AsymmetricAlgorithm' because it is missing a public instance constructor.");
                }
            }

            if (AsConfigWithChildren(configuration.GetSection("Oid")) is IConfigurationSection section40)
            {
                global::System.Security.Cryptography.Oid? temp42 = instance.Oid;
                temp42 ??= new global::System.Security.Cryptography.Oid();
                BindCore(section40, ref temp42, defaultValueIfNotFound: false, binderOptions);
            }
        }

        public static void BindCore(IConfiguration configuration, ref global::System.Security.Cryptography.X509Certificates.X509Certificate2 instance, bool defaultValueIfNotFound, BinderOptions? binderOptions)
        {
            ValidateConfigurationKeys(typeof(global::System.Security.Cryptography.X509Certificates.X509Certificate2), s_configKeys_X509Certificate2, configuration, binderOptions);

            if (configuration["Archived"] is string value43)
            {
                instance.Archived = ParseBool(value43, configuration.GetSection("Archived").Path);
            }
            else if (defaultValueIfNotFound)
            {
                instance.Archived = instance.Archived;
            }

            if (AsConfigWithChildren(configuration.GetSection("Extensions")) is IConfigurationSection section44)
            {
                global::System.Security.Cryptography.X509Certificates.X509ExtensionCollection? temp46 = instance.Extensions;
                temp46 ??= new global::System.Security.Cryptography.X509Certificates.X509ExtensionCollection();
                BindCore(section44, ref temp46, defaultValueIfNotFound: false, binderOptions);
            }

            if (configuration["FriendlyName"] is string value47)
            {
                instance.FriendlyName = value47;
            }
            else if (defaultValueIfNotFound)
            {
                var currentValue = instance.FriendlyName;
                if (currentValue is not null)
                {
                    instance.FriendlyName = currentValue;
                }
            }

            if (AsConfigWithChildren(configuration.GetSection("IssuerName")) is IConfigurationSection section48)
            {
                global::System.Security.Cryptography.X509Certificates.X500DistinguishedName? temp50 = instance.IssuerName;
                if (temp50 is not null)
                {
                    BindCore(section48, ref temp50, defaultValueIfNotFound: false, binderOptions);
                }
                else
                {
                    throw new InvalidOperationException("Cannot create instance of type 'System.Security.Cryptography.X509Certificates.X500DistinguishedName' because one or more parameters cannot be bound to. Constructor parameters must have corresponding properties. Fields are not supported. Missing properties are: 'encodedDistinguishedName'");
                }
            }

            if (AsConfigWithChildren(configuration.GetSection("PrivateKey")) is IConfigurationSection section51)
            {
                global::System.Security.Cryptography.AsymmetricAlgorithm? temp53 = instance.PrivateKey;
                if (temp53 is not null)
                {
                    BindCore(section51, ref temp53, defaultValueIfNotFound: false, binderOptions);
                    instance.PrivateKey = temp53;
                }
                else
                {
                    throw new InvalidOperationException("Cannot create instance of type 'System.Security.Cryptography.AsymmetricAlgorithm' because it is missing a public instance constructor.");
                }
            }

            if (AsConfigWithChildren(configuration.GetSection("PublicKey")) is IConfigurationSection section54)
            {
                global::System.Security.Cryptography.X509Certificates.PublicKey? temp56 = instance.PublicKey;
                if (temp56 is not null)
                {
                    BindCore(section54, ref temp56, defaultValueIfNotFound: false, binderOptions);
                }
                else
                {
                    throw new InvalidOperationException("Cannot create instance of type 'System.Security.Cryptography.X509Certificates.PublicKey' because it has multiple public parameterized constructors.");
                }
            }

            if (AsConfigWithChildren(configuration.GetSection("RawDataMemory")) is IConfigurationSection section57)
            {
            }

            if (AsConfigWithChildren(configuration.GetSection("SignatureAlgorithm")) is IConfigurationSection section59)
            {
                global::System.Security.Cryptography.Oid? temp61 = instance.SignatureAlgorithm;
                temp61 ??= new global::System.Security.Cryptography.Oid();
                BindCore(section59, ref temp61, defaultValueIfNotFound: false, binderOptions);
            }

            if (AsConfigWithChildren(configuration.GetSection("SubjectName")) is IConfigurationSection section62)
            {
                global::System.Security.Cryptography.X509Certificates.X500DistinguishedName? temp64 = instance.SubjectName;
                if (temp64 is not null)
                {
                    BindCore(section62, ref temp64, defaultValueIfNotFound: false, binderOptions);
                }
                else
                {
                    throw new InvalidOperationException("Cannot create instance of type 'System.Security.Cryptography.X509Certificates.X500DistinguishedName' because one or more parameters cannot be bound to. Constructor parameters must have corresponding properties. Fields are not supported. Missing properties are: 'encodedDistinguishedName'");
                }
            }

            if (AsConfigWithChildren(configuration.GetSection("SerialNumberBytes")) is IConfigurationSection section65)
            {
            }
        }

        public static void BindCore(IConfiguration configuration, ref global::System.Security.Cryptography.X509Certificates.X509Certificate2Collection instance, bool defaultValueIfNotFound, BinderOptions? binderOptions)
        {
            foreach (IConfigurationSection section in configuration.GetChildren())
            {
                if (!string.IsNullOrEmpty(section.Value) && !section.GetChildren().Any())
                {
                    continue;
                }
                var value = new global::System.Security.Cryptography.X509Certificates.X509Certificate2();
                BindCore(section, ref value, defaultValueIfNotFound: false, binderOptions);
                instance.Add(value);
            }
        }

        public static void BindCore(IConfiguration configuration, ref global::System.Security.Cryptography.X509Certificates.X509ChainPolicy instance, bool defaultValueIfNotFound, BinderOptions? binderOptions)
        {
            ValidateConfigurationKeys(typeof(global::System.Security.Cryptography.X509Certificates.X509ChainPolicy), s_configKeys_X509ChainPolicy, configuration, binderOptions);

            if (AsConfigWithChildren(configuration.GetSection("CustomTrustStore")) is IConfigurationSection section68)
            {
                global::System.Security.Cryptography.X509Certificates.X509Certificate2Collection? temp70 = instance.CustomTrustStore;
                temp70 ??= new global::System.Security.Cryptography.X509Certificates.X509Certificate2Collection();
                BindCore(section68, ref temp70, defaultValueIfNotFound: false, binderOptions);
            }

            if (configuration["DisableCertificateDownloads"] is string value71)
            {
                instance.DisableCertificateDownloads = ParseBool(value71, configuration.GetSection("DisableCertificateDownloads").Path);
            }
            else if (defaultValueIfNotFound)
            {
                instance.DisableCertificateDownloads = instance.DisableCertificateDownloads;
            }

            if (AsConfigWithChildren(configuration.GetSection("ExtraStore")) is IConfigurationSection section72)
            {
                global::System.Security.Cryptography.X509Certificates.X509Certificate2Collection? temp74 = instance.ExtraStore;
                temp74 ??= new global::System.Security.Cryptography.X509Certificates.X509Certificate2Collection();
                BindCore(section72, ref temp74, defaultValueIfNotFound: false, binderOptions);
            }

            if (configuration["RevocationFlag"] is string value75)
            {
                instance.RevocationFlag = ParseEnum<global::System.Security.Cryptography.X509Certificates.X509RevocationFlag>(value75, configuration.GetSection("RevocationFlag").Path);
            }
            else if (defaultValueIfNotFound)
            {
                instance.RevocationFlag = instance.RevocationFlag;
            }

            if (configuration["RevocationMode"] is string value76)
            {
                instance.RevocationMode = ParseEnum<global::System.Security.Cryptography.X509Certificates.X509RevocationMode>(value76, configuration.GetSection("RevocationMode").Path);
            }
            else if (defaultValueIfNotFound)
            {
                instance.RevocationMode = instance.RevocationMode;
            }

            if (configuration["TrustMode"] is string value77)
            {
                instance.TrustMode = ParseEnum<global::System.Security.Cryptography.X509Certificates.X509ChainTrustMode>(value77, configuration.GetSection("TrustMode").Path);
            }
            else if (defaultValueIfNotFound)
            {
                instance.TrustMode = instance.TrustMode;
            }

            if (configuration["UrlRetrievalTimeout"] is string value78)
            {
                instance.UrlRetrievalTimeout = ParseSystemTimeSpan(value78, configuration.GetSection("UrlRetrievalTimeout").Path);
            }
            else if (defaultValueIfNotFound)
            {
                instance.UrlRetrievalTimeout = instance.UrlRetrievalTimeout;
            }

            if (configuration["VerificationFlags"] is string value79)
            {
                instance.VerificationFlags = ParseEnum<global::System.Security.Cryptography.X509Certificates.X509VerificationFlags>(value79, configuration.GetSection("VerificationFlags").Path);
            }
            else if (defaultValueIfNotFound)
            {
                instance.VerificationFlags = instance.VerificationFlags;
            }

            if (configuration["VerificationTime"] is string value80)
            {
                instance.VerificationTime = ParseSystemDateTime(value80, configuration.GetSection("VerificationTime").Path);
            }
            else if (defaultValueIfNotFound)
            {
                instance.VerificationTime = instance.VerificationTime;
            }

            if (configuration["VerificationTimeIgnored"] is string value81)
            {
                instance.VerificationTimeIgnored = ParseBool(value81, configuration.GetSection("VerificationTimeIgnored").Path);
            }
            else if (defaultValueIfNotFound)
            {
                instance.VerificationTimeIgnored = instance.VerificationTimeIgnored;
            }
        }

        public static void BindCore(IConfiguration configuration, ref global::System.Net.Security.SslStreamCertificateContext instance, bool defaultValueIfNotFound, BinderOptions? binderOptions)
        {
            ValidateConfigurationKeys(typeof(global::System.Net.Security.SslStreamCertificateContext), s_configKeys_SslStreamCertificateContext, configuration, binderOptions);

            if (AsConfigWithChildren(configuration.GetSection("TargetCertificate")) is IConfigurationSection section82)
            {
                global::System.Security.Cryptography.X509Certificates.X509Certificate2? temp84 = instance.TargetCertificate;
                temp84 ??= new global::System.Security.Cryptography.X509Certificates.X509Certificate2();
                BindCore(section82, ref temp84, defaultValueIfNotFound: false, binderOptions);
            }
        }

        public static void BindCore(IConfiguration configuration, ref global::System.Net.Security.SslClientAuthenticationOptions instance, bool defaultValueIfNotFound, BinderOptions? binderOptions)
        {
            ValidateConfigurationKeys(typeof(global::System.Net.Security.SslClientAuthenticationOptions), s_configKeys_SslClientAuthenticationOptions, configuration, binderOptions);

            if (configuration["AllowRenegotiation"] is string value85)
            {
                instance.AllowRenegotiation = ParseBool(value85, configuration.GetSection("AllowRenegotiation").Path);
            }
            else if (defaultValueIfNotFound)
            {
                instance.AllowRenegotiation = instance.AllowRenegotiation;
            }

            if (configuration["AllowTlsResume"] is string value86)
            {
                instance.AllowTlsResume = ParseBool(value86, configuration.GetSection("AllowTlsResume").Path);
            }
            else if (defaultValueIfNotFound)
            {
                instance.AllowTlsResume = instance.AllowTlsResume;
            }

            if (AsConfigWithChildren(configuration.GetSection("ApplicationProtocols")) is IConfigurationSection section87)
            {
                global::System.Collections.Generic.List<global::System.Net.Security.SslApplicationProtocol>? temp89 = instance.ApplicationProtocols;
                temp89 ??= new global::System.Collections.Generic.List<global::System.Net.Security.SslApplicationProtocol>();
                BindCore(section87, ref temp89, defaultValueIfNotFound: false, binderOptions);
                instance.ApplicationProtocols = temp89;
            }

            if (AsConfigWithChildren(configuration.GetSection("CertificateChainPolicy")) is IConfigurationSection section90)
            {
                global::System.Security.Cryptography.X509Certificates.X509ChainPolicy? temp92 = instance.CertificateChainPolicy;
                temp92 ??= new global::System.Security.Cryptography.X509Certificates.X509ChainPolicy();
                BindCore(section90, ref temp92, defaultValueIfNotFound: false, binderOptions);
                instance.CertificateChainPolicy = temp92;
            }

            if (configuration["CertificateRevocationCheckMode"] is string value93)
            {
                instance.CertificateRevocationCheckMode = ParseEnum<global::System.Security.Cryptography.X509Certificates.X509RevocationMode>(value93, configuration.GetSection("CertificateRevocationCheckMode").Path);
            }
            else if (defaultValueIfNotFound)
            {
                instance.CertificateRevocationCheckMode = instance.CertificateRevocationCheckMode;
            }

            if (AsConfigWithChildren(configuration.GetSection("CipherSuitesPolicy")) is IConfigurationSection section94)
            {
                instance.CipherSuitesPolicy ??= InitializeCipherSuitesPolicy(section94, binderOptions);
            }

            if (AsConfigWithChildren(configuration.GetSection("ClientCertificateContext")) is IConfigurationSection section96)
            {
                global::System.Net.Security.SslStreamCertificateContext? temp98 = instance.ClientCertificateContext;
                if (temp98 is not null)
                {
                    BindCore(section96, ref temp98, defaultValueIfNotFound: false, binderOptions);
                    instance.ClientCertificateContext = temp98;
                }
                else
                {
                    throw new InvalidOperationException("Cannot create instance of type 'System.Net.Security.SslStreamCertificateContext' because it is missing a public instance constructor.");
                }
            }

            if (configuration["EnabledSslProtocols"] is string value99)
            {
                instance.EnabledSslProtocols = ParseEnum<global::System.Security.Authentication.SslProtocols>(value99, configuration.GetSection("EnabledSslProtocols").Path);
            }
            else if (defaultValueIfNotFound)
            {
                instance.EnabledSslProtocols = instance.EnabledSslProtocols;
            }

            if (configuration["EncryptionPolicy"] is string value100)
            {
                instance.EncryptionPolicy = ParseEnum<global::System.Net.Security.EncryptionPolicy>(value100, configuration.GetSection("EncryptionPolicy").Path);
            }
            else if (defaultValueIfNotFound)
            {
                instance.EncryptionPolicy = instance.EncryptionPolicy;
            }

            if (configuration["TargetHost"] is string value101)
            {
                instance.TargetHost = value101;
            }
            else if (defaultValueIfNotFound)
            {
                var currentValue = instance.TargetHost;
                if (currentValue is not null)
                {
                    instance.TargetHost = currentValue;
                }
            }
        }

        public static global::System.Net.Security.SslApplicationProtocol InitializeSslApplicationProtocol(IConfiguration configuration, BinderOptions? binderOptions)
        {
            global::System.ReadOnlyMemory<byte> protocol = default;
            if (AsConfigWithChildren(configuration.GetSection("Protocol")) is IConfigurationSection section102)
            {
                global::System.ReadOnlyMemory<byte> temp103 = protocol;
                var temp104 = new global::System.ReadOnlyMemory<byte>();
                BindCore(section102, ref temp104, defaultValueIfNotFound: false, binderOptions);
                protocol = temp104;
                temp103 = temp104;
            }
            else
            {
                throw new InvalidOperationException("Cannot create instance of type 'System.Net.Security.SslApplicationProtocol' because parameter 'protocol' has no matching config. Each parameter in the constructor that does not have a default value must have a corresponding config entry.");
            }

            return new global::System.Net.Security.SslApplicationProtocol(protocol);
        }

        public static global::System.Security.Cryptography.KeySizes InitializeKeySizes(IConfiguration configuration, BinderOptions? binderOptions)
        {
            int minSize = default;
            if (configuration["MinSize"] is string value105)
            {
                minSize = ParseInt(value105, configuration.GetSection("MinSize").Path);
            }
            else
            {
                throw new InvalidOperationException("Cannot create instance of type 'System.Security.Cryptography.KeySizes' because parameter 'minSize' has no matching config. Each parameter in the constructor that does not have a default value must have a corresponding config entry.");
            }

            int maxSize = default;
            if (configuration["MaxSize"] is string value106)
            {
                maxSize = ParseInt(value106, configuration.GetSection("MaxSize").Path);
            }
            else
            {
                throw new InvalidOperationException("Cannot create instance of type 'System.Security.Cryptography.KeySizes' because parameter 'maxSize' has no matching config. Each parameter in the constructor that does not have a default value must have a corresponding config entry.");
            }

            int skipSize = default;
            if (configuration["SkipSize"] is string value107)
            {
                skipSize = ParseInt(value107, configuration.GetSection("SkipSize").Path);
            }
            else
            {
                throw new InvalidOperationException("Cannot create instance of type 'System.Security.Cryptography.KeySizes' because parameter 'skipSize' has no matching config. Each parameter in the constructor that does not have a default value must have a corresponding config entry.");
            }

            return new global::System.Security.Cryptography.KeySizes(minSize, maxSize, skipSize);
        }


        /// <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)
        {
            if (binderOptions?.ErrorOnUnknownConfiguration is true)
            {
                List<string>? temp = null;
        
                foreach (IConfigurationSection section in configuration.GetChildren())
                {
                    if (!keys.Value.Contains(section.Key))
                    {
                        (temp ??= new List<string>()).Add($"'{section.Key}'");
                    }
                }
        
                if (temp is not null)
                {
                    throw new InvalidOperationException($"'ErrorOnUnknownConfiguration' was set on the provided BinderOptions, but the following properties were not found on the instance of {type}: {string.Join(", ", temp)}");
                }
            }
        }

        public static bool HasValueOrChildren(IConfiguration configuration)
        {
            if ((configuration as IConfigurationSection)?.Value is not null)
            {
                return true;
            }
            return AsConfigWithChildren(configuration) is not null;
        }

        public static IConfiguration? AsConfigWithChildren(IConfiguration configuration)
        {
            foreach (IConfigurationSection _ in configuration.GetChildren())
            {
                return configuration;
            }
            return null;
        }

        public static BinderOptions? GetBinderOptions(Action<BinderOptions>? configureOptions)
        {
            if (configureOptions is null)
            {
                return null;
            }
        
            BinderOptions binderOptions = new();
            configureOptions(binderOptions);
        
            if (binderOptions.BindNonPublicProperties)
            {
                throw new NotSupportedException($"The configuration binding source generator does not support 'BinderOptions.BindNonPublicProperties'.");
            }
        
            return binderOptions;
        }

        public static T ParseEnum<T>(string value, string? path) where T : struct
        {
            try
            {
                return Enum.Parse<T>(value, ignoreCase: true);
            }
            catch (Exception exception)
            {
                throw new InvalidOperationException($"Failed to convert configuration value at '{path}' to type '{typeof(T)}'.", exception);
            }
        }

        public static bool ParseBool(string value, string? path)
        {
            try
            {
                return bool.Parse(value);
            }
            catch (Exception exception)
            {
                throw new InvalidOperationException($"Failed to convert configuration value at '{path}' to type '{typeof(bool)}'.", exception);
            }
        }

        public static int ParseInt(string value, string? path)
        {
            try
            {
                return int.Parse(value, NumberStyles.Integer, CultureInfo.InvariantCulture);
            }
            catch (Exception exception)
            {
                throw new InvalidOperationException($"Failed to convert configuration value at '{path}' to type '{typeof(int)}'.", exception);
            }
        }

        public static byte[] ParseByteArray(string value, string? path)
        {
            try
            {
                return Convert.FromBase64String(value);
            }
            catch (Exception exception)
            {
                throw new InvalidOperationException($"Failed to convert configuration value at '{path}' to type '{typeof(byte[])}'.", exception);
            }
        }

        public static global::System.DateTime ParseSystemDateTime(string value, string? path)
        {
            try
            {
                return global::System.DateTime.Parse(value, CultureInfo.InvariantCulture);
            }
            catch (Exception exception)
            {
                throw new InvalidOperationException($"Failed to convert configuration value at '{path}' to type '{typeof(global::System.DateTime)}'.", exception);
            }
        }

        public static global::System.TimeSpan ParseSystemTimeSpan(string value, string? path)
        {
            try
            {
                return global::System.TimeSpan.Parse(value, CultureInfo.InvariantCulture);
            }
            catch (Exception exception)
            {
                throw new InvalidOperationException($"Failed to convert configuration value at '{path}' to type '{typeof(global::System.TimeSpan)}'.", exception);
            }
        }
        #endregion Core binding extensions.
    }
}

Regression?

No

Known Workarounds

No response

Configuration

No response

Other information

cc @ericstj @tarekgh

Metadata

Metadata

Assignees

Labels

area-Extensions-Configurationbugin-prThere is an active PR which will close this issue when it is mergedsource-generatorIndicates an issue with a source generator feature

Type

No type
No fields configured for issues without a type.

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions