Skip to content

Attempting to Get a configuration section using a type defined as a record will duplicate collection values. #83803

Description

@vsfeedback

Recent status can be found in the comment #83803 (comment)

Edited by @tarekgh
This issue claimed the problem is not occurring on .NET 6.0 which is not true. The comment #83803 (comment) clarified that. In short, this issue is not a regression from .NET 6.0. Actually, .NET 7.0 behavior is not throwing.
End of @tarekgh edit

Edit by @tarekgh: additional case to cover when fixing
The same duplication also happens with a class (not a record) when a constructor parameter name differs only by case from a collection property, including a class that uses a params collection constructor (for example a parameter instances and a property Instances). The reflection based runtime binder fix for that case is tracked by #129760 and PR #129775. When fixing this issue in the configuration source generator, the fix should be extended to cover both the record case described above and this class case so the reflection binder and the source generator behave the same.
End of @tarekgh edit

This issue has been moved from a ticket on Developer Community.


[severity:It bothers me. A fix would be nice]
The behaviour has changed unexpectedly from how .Net 6.0 used to work.

/* Environment Variables
"MonitorConfig__Services__0__Name": "Service A"
"MonitorConfig__Services__0__Url": "http://localhost:5201/health",
"MonitorConfig__Services__1__Name": "Service B",
"MonitorConfig__Services__1__Url": "http://localhost:5202/health"
*/

/* defined Records types
public record MonitorConfig(ServiceConfig[] Services = null);

public record ServiceConfig(string Name, string Url);
*/

var builder = WebApplication.CreateBuilder(args);

builder.Configuration.AddEnvironmentVariables();

var monitorConfig = builder.Configuration.GetSection("MonitorConfig").Get();

monitorConfig will contain 4 ServiceConfig entries with duplicated instances of both ServiceA and ServceB declarations.

The expectation should be two entries as defined by the environment variables.

If I convert to use class types instead of record types, the behaviour works as expected.

The use of records should be supported and work as it did for .Net 6.0 using the same code, as I should not have to go and rewrite records to as classes after porting to .Net 7.


Original Comments

Feedback Bot on 3/8/2023, 05:37 PM:

(private comment, text removed)


Original Solutions

Chris Westermann solved on 3/9/2023, 05:05 AM, 0 votes:

I found that if I override the default constructor, then I get the behaviour I would expect

public record MonitorConfig(ServiceConfig[] Services)
{
public MonitorConfig()
: this((ServiceConfig[])null)
{ }
}

While this is a workaround, it seems odd I would need to do this since, conceptually, setting the default value of the positional parameter to null should produce the same behaviour and not cause the actual instance to have twice as many array entries as expected.

Metadata

Metadata

Assignees

Type

No type
No fields configured for issues without a type.

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions