Skip to content

Configuration.Binder source generator produces non-compiling code for properties named with C# keywords (@base, @event, etc.) #130433

Description

@NoirHare

Description

The Configuration.Binder source generator emits property and type names verbatim into identifier position without escaping C# keywords. If a configuration model has a property whose name is a keyword (declared with @, e.g. @base, @event), the generated validator emits e.g. base instead of @base, which does not compile.

Reproduction Steps

// sln

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net11.0</TargetFramework>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>
    <EnableConfigurationBindingGenerator>true</EnableConfigurationBindingGenerator>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Microsoft.Extensions.Configuration" Version="10.0.9" />
    <PackageReference Include="Microsoft.Extensions.Configuration.Binder" Version="10.0.9" />
  </ItemGroup>

</Project>
// Program.cs

using Microsoft.Extensions.Configuration;

internal class Program
{
    private static void Main(string[] args)
    {
        ConfigurationManager manager = new();
        MyConfiguration? options = manager.GetSection("My").Get<MyConfiguration>();
    }
}

class MyConfiguration(string @base, string @event)
{
    public string Base { get; } = @base;
    public string Event { get; } = @event;
}

Expected behavior

The generated code compiles, emitting configuration.@base (or otherwise escaping keyword identifiers).

Actual behavior

Build fails. The generated BindingExtensions.g.cs contains (note the unescaped base and event):

        public static global::MyConfiguration InitializeMyConfiguration(IConfiguration configuration, BinderOptions? binderOptions)
        {
            if (configuration["Base"] is not string base)
            {
                throw new InvalidOperationException("Cannot create instance of type 'MyConfiguration' because parameter 'base' has no matching config. Each parameter in the constructor that does not have a default value must have a corresponding config entry.");
            }

            if (configuration["Event"] is not string event)
            {
                throw new InvalidOperationException("Cannot create instance of type 'MyConfiguration' because parameter 'event' 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::MyConfiguration(base, event);
        }

This causes confusing compiler errors.

Restore complete (1.8s)
  ConfigBinderKeywordBindingRepro net10.0 failed with 5 error(s) (0.7s)
    D:\Code\csharp\ConfigBinderKeywordBindingRepro\obj\Debug\net10.0\generated\Microsoft.Extensions.Configuration.Binder.SourceGeneration\Microsoft.Extensions.Configuration.Binder.SourceGeneration.ConfigurationBindingGenerator\BindingExtensions.g.cs(78,59): error CS0065: 'BindingExtensions.': event property must have both add and remove accessors
    D:\Code\csharp\ConfigBinderKeywordBindingRepro\obj\Debug\net10.0\generated\Microsoft.Extensions.Configuration.Binder.SourceGeneration\Microsoft.Extensions.Configuration.Binder.SourceGeneration.ConfigurationBindingGenerator\BindingExtensions.g.cs(83,59): error CS0065: 'BindingExtensions.': event property must have both add and remove accessors
    D:\Code\csharp\ConfigBinderKeywordBindingRepro\obj\Debug\net10.0\generated\Microsoft.Extensions.Configuration.Binder.SourceGeneration\Microsoft.Extensions.Configuration.Binder.SourceGeneration.ConfigurationBindingGenerator\BindingExtensions.g.cs(83,59): error CS0102: The type 'BindingExtensions' already contains a definition for ''
    D:\Code\csharp\ConfigBinderKeywordBindingRepro\obj\Debug\net10.0\generated\Microsoft.Extensions.Configuration.Binder.SourceGeneration\Microsoft.Extensions.Configuration.Binder.SourceGeneration.ConfigurationBindingGenerator\BindingExtensions.g.cs(78,59): error CS0708: '': cannot declare instance members in a static class
    D:\Code\csharp\ConfigBinderKeywordBindingRepro\obj\Debug\net10.0\generated\Microsoft.Extensions.Configuration.Binder.SourceGeneration\Microsoft.Extensions.Configuration.Binder.SourceGeneration.ConfigurationBindingGenerator\BindingExtensions.g.cs(83,59): error CS0708: '': cannot declare instance members in a static class

Build failed with 5 error(s) in 2.7s

Regression?

No response

Known Workarounds

No response

Configuration

No response

Other information

I think the reason is probably similar to #130318 .
Both failed to process keyword identifiers.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions