dotnet / runtime

.NET is a cross-platform runtime for cloud, mobile, desktop, and IoT apps.
https://docs.microsoft.com/dotnet/core/
MIT License
15.47k stars 4.77k forks source link

ConfigurationBinding source generator ignores init-only properties without warning #107856

Open RichardD2 opened 2 months ago

RichardD2 commented 2 months ago

Description

I am trying to migration some (working) configuration code to use the new configuration source binding generator. However, the source generator never initializes the properties of the configuration object, and no warning or error is generated to highlight the issue.

Reproduction Steps

Configuration section:

public class SqlServerSettings
{
    public int? CompatibilityLevel { get; init; }
}

Usage:

private static int? GetCompatibilityLevel(IConfiguration configuration)
{
    return configuration.GetSection("SqlServer").Get<SqlServerSettings>()?.CompatibilityLevel;
}

appSettings.json:

{
    "SqlServer": {
        "CompatibilityLevel": 130
    }
}

Expected behavior

Ideally, GetCompatibilityLevel should return 130 (probably impossible).

Alternatively, a compiler warning / error should be issued to highlight the fact that the source generator cannot set init-only properties.

Actual behavior

GetCompatibilityLevel returns 0.

The generated BindCore method does not attempt to set any properties:

public static void BindCore(IConfiguration configuration, ref SqlServerSettings instance, bool defaultValueIfNotFound, BinderOptions? binderOptions)
{
    ValidateConfigurationKeys(typeof(SqlServerSettings), s_configKeys_SqlServerSettings, configuration, binderOptions);
}

No errors or warnings are issued.

Regression?

No response

Known Workarounds

Changing the init-only property to a writeable property restores the correct behaviour.

public class SqlServerSettings
{
    public int? CompatibilityLevel { get; set; }
}
public static void BindCore(IConfiguration configuration, ref SqlServerSettings instance, bool defaultValueIfNotFound, BinderOptions? binderOptions)
{
    ValidateConfigurationKeys(typeof(SqlServerSettings), s_configKeys_SqlServerSettings, configuration, binderOptions);

    if (configuration["CompatibilityLevel"] is string value2)
    {
        instance.CompatibilityLevel = ParseInt(value2, () => configuration.GetSection("CompatibilityLevel").Path);
    }
}

Configuration

.NET SDK: Version: 8.0.400 Commit: 36fe6dda56 Workload version: 8.0.400-manifests.6c274a57 MSBuild version: 17.11.3+0c8610977

Runtime Environment: OS Name: Windows OS Version: 10.0.22631 OS Platform: Windows RID: win-x64 Base Path: C:\Program Files\dotnet\sdk\8.0.400\

Visual Studio 2022 v17.11.3

Other information

Possibly related to #92638?

dotnet-policy-service[bot] commented 2 months ago

Tagging subscribers to this area: @dotnet/area-extensions-configuration See info in area-owners.md if you want to be subscribed.

ericstj commented 2 months ago

Similar issue to https://github.com/dotnet/runtime/issues/95006