dotnet / runtime

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

InvalidOperationException for nullable int in ConfigurationBinder source generator generated code #103859

Open harrison314 opened 1 week ago

harrison314 commented 1 week ago

Description

The ConfigurationBinder source generator in the AOT template generates code that doesn’t consider the use of nullable value types like int, long, etc. As a result, binding fails with an InvalidOperationException because it tries to parse an empty string as an int in generated code.

Microsoft.Extensions.Configuration.Binder.SourceGeneration version 8.0.10.26715

Reproduction Steps

Configuration class:

public class LimitSetup
{
    public int? MaxCount { get; set; }
}

Binding in Program.cs (ASP web api AOT template):

builder.Services
    .AddOptions<LimitSetup>()
    .BindConfiguration("LimitSetup");

In appsettings.json:

"LimitSetup": {
  "MaxCount": null
}

csproj file:

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

  <PropertyGroup>
    <TargetFramework>net8.0</TargetFramework>
    <Nullable>enable</Nullable>
    <ImplicitUsings>enable</ImplicitUsings>
    <InvariantGlobalization>true</InvariantGlobalization>
    <PublishAot>true</PublishAot>
  </PropertyGroup>

</Project>

Expected behavior

In options LimitSetup.MaxCount property is null value.

Actual behavior

I get an exception when binding:

System.InvalidOperationException: 'Failed to convert configuration value at 'LimitSetup:MaxCount' to type 'System.Int32'.'

ConfigurationBinder source generator generate this code:

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

Value value1 is empty string if MaxCount is null in appsettings.json.

Regression?

No response

Known Workarounds

No response

Configuration

.NET 8 - ASP.NET Core Web API (Native AOT) template

Other information

No response

dotnet-policy-service[bot] commented 1 week ago

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

tarekgh commented 1 week ago

The reflection binder successfully handles this case https://github.com/dotnet/runtime/blob/98e75704a85bfe4a71dd5932c8a2e5f860a09d05/src/libraries/Microsoft.Extensions.Configuration.Binder/src/ConfigurationBinder.cs#L879 We need to ensure the source generator handles that too.