Allow configuration binding to set-only properties#125768
Allow configuration binding to set-only properties#125768cincuranet wants to merge 10 commits intodotnet:mainfrom
Conversation
Fixes dotnet#63508 The configuration binder previously skipped all properties without a getter. This change enables binding to true set-only properties (those with a setter but no getter at all) in both the reflection-based binder and the source generator. Reflection binder (ConfigurationBinder.cs): - Restructured the BindProperty guard to allow set-only properties with accessible setters while still filtering indexers and non-public properties. - Set-only properties use a null initial value instead of calling property.GetValue(), avoiding the exception that would occur with no getter. Source generator (CoreBindingHelpers.cs): - Added HasAnyGetter to MemberSpec/PropertySpec to distinguish true set-only properties (no getter) from properties with non-public getters, keeping behavior consistent with the reflection binder. - Relaxed the parsable type guard from canSet && canGet to canSet && (canGet || !member.HasAnyGetter). - Fixed complex reference type binding for set-only properties to use a temp variable instead of ref on the property (CS0206). - Added canGet guard on the defaultValueIfNotFound block and array null-check fallback that read the current property value. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
This PR updates the Microsoft.Extensions.Configuration binder to allow binding to true set-only properties (setter present, no getter) in both the reflection-based binder and the source-generated binder, aligning behavior with documented expectations (Fixes #63508).
Changes:
- Reflection binder: allow binding set-only properties by handling the “no getter” case in
BindProperty. - Source generator: distinguish “no getter at all” vs “non-public getter” and generate binding code for true set-only properties.
- Tests: update/extend coverage for set-only binding (including complex types and type conversion) and adjust an existing virtual-property assertion.
Reviewed changes
Copilot reviewed 6 out of 6 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| src/libraries/Microsoft.Extensions.Configuration.Binder/src/ConfigurationBinder.cs | Enables reflection binder binding for true set-only properties by adjusting getter/setter checks and binding point initialization. |
| src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Specs/Members/MemberSpec.cs | Adds HasAnyGetter to distinguish true set-only from “non-public getter” properties in generator metadata. |
| src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Specs/Members/PropertySpec.cs | Implements HasAnyGetter for properties based on presence of any getter (regardless of accessibility). |
| src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Emitter/CoreBindingHelpers.cs | Updates generated binding logic to support set-only properties and avoid emitting getter-dependent code paths. |
| src/libraries/Microsoft.Extensions.Configuration.Binder/tests/Common/ConfigurationBinderTests.cs | Updates existing test and adds new tests validating set-only binding scenarios (simple, conversion, complex). |
| src/libraries/Microsoft.Extensions.Configuration.Binder/tests/Common/ConfigurationBinderTests.TestClasses.cs | Expands test POCOs to track which setters were invoked and adds new POCOs for complex/type-conversion scenarios. |
Comments suppressed due to low confidence (1)
src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Emitter/CoreBindingHelpers.cs:992
- The source-generator path skips the empty-string -> empty-array fallback when the bound member is set-only (no getter), but the reflection binder will still assign an empty array in that case (because the binding point’s initial value is null). To keep parity, emit a set-only-specific fallback that assigns Array.Empty() when the config value is "" without reading the member value (since it has no getter).
// The current configuration section doesn't have any children, let's check if we are binding to an array and the configuration value is empty string.
// In this case, we will assign an empty array to the member. Otherwise, we will skip the binding logic.
// The null check on the member requires a getter, so skip this fallback for set-only properties.
if ((complexType is ArraySpec || complexType.IsExactIEnumerableOfT) && canSet && canGet)
{
// Either we have an array or we have an IEnumerable<T> both these types can be assigned an empty array when having empty string configuration value.
Debug.Assert(complexType is ArraySpec || complexType is EnumerableSpec);
string valueIdentifier = GetIncrementalIdentifier(Identifier.value);
EmitStartBlock($@"if ({memberAccessExpr} is null && {Identifier.TryGetConfigurationValue}({configSection}, {Identifier.key}: null, out string? {valueIdentifier}) && {valueIdentifier} == string.Empty)");
_writer.WriteLine($"{memberAccessExpr} = global::System.{Identifier.Array}.Empty<{((CollectionSpec)complexType).ElementTypeRef.FullyQualifiedName}>();");
EmitEndBlock();
You can also share your feedback on Copilot code review. Take the survey.
src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Emitter/CoreBindingHelpers.cs
Show resolved
Hide resolved
src/libraries/Microsoft.Extensions.Configuration.Binder/src/ConfigurationBinder.cs
Outdated
Show resolved
Hide resolved
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
This PR updates Microsoft.Extensions.Configuration.Binder to bind true set-only properties (setter present, no getter at all) in both the reflection-based binder and the configuration binding source generator, addressing the documented behavior gap from #63508.
Changes:
- Reflection binder: allow binding of set-only properties by handling
PropertyInfo.GetMethod == nulland using aBindingPointwithout a getter-backed initial value. - Source generator: add
HasAnyGetterto distinguish true set-only properties from properties with non-public getters, and update emission logic to support set-only binding. - Tests: update/extend coverage to validate set-only binding, including type conversion and complex object binding; update virtual set-only property binding expectation.
Reviewed changes
Copilot reviewed 6 out of 6 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| src/libraries/Microsoft.Extensions.Configuration.Binder/tests/Common/ConfigurationBinderTests.cs | Updates existing test and adds new tests covering set-only binding scenarios (including complex and type conversion) and virtual set-only property binding. |
| src/libraries/Microsoft.Extensions.Configuration.Binder/tests/Common/ConfigurationBinderTests.TestClasses.cs | Updates SetOnlyPoco test helper and adds new POCOs used by set-only binding tests. |
| src/libraries/Microsoft.Extensions.Configuration.Binder/src/ConfigurationBinder.cs | Implements reflection binder support for set-only properties by adjusting property filtering and binding point initialization. |
| src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Specs/Members/PropertySpec.cs | Adds HasAnyGetter to capture “getter exists at any accessibility” for generated binding decisions. |
| src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Specs/Members/MemberSpec.cs | Introduces HasAnyGetter contract (defaulting to CanGet) to distinguish true set-only properties vs. non-public getters. |
| src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Emitter/CoreBindingHelpers.cs | Updates generated binding logic to allow set-only properties while trying to preserve parity with reflection binder behavior. |
You can also share your feedback on Copilot code review. Take the survey.
src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Emitter/CoreBindingHelpers.cs
Show resolved
Hide resolved
src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Emitter/CoreBindingHelpers.cs
Show resolved
Hide resolved
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
This PR updates Microsoft.Extensions.Configuration.Binder to bind true set-only properties (properties with a setter and no getter at all) in both the reflection-based binder and the source-generated binder, aligning behavior more closely with the documented expectations.
Changes:
- Reflection binder: allow binding to set-only properties by treating them as writable binding targets even without an initial value getter.
- Source generator: distinguish “true set-only” (no getter) from “non-public getter” to enable the former while continuing to skip the latter.
- Tests: update existing coverage and add new cases for set-only binding (including complex and type-converted scenarios).
Reviewed changes
Copilot reviewed 6 out of 6 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| src/libraries/Microsoft.Extensions.Configuration.Binder/src/ConfigurationBinder.cs | Enables reflection-based binding for set-only properties by changing property eligibility checks and binding-point initialization. |
| src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Emitter/CoreBindingHelpers.cs | Updates generated binding logic to allow true set-only properties and handle getterless complex members via temp variables. |
| src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Specs/Members/MemberSpec.cs | Introduces HasAnyGetter abstraction to differentiate “no getter” vs “non-public getter”. |
| src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Specs/Members/PropertySpec.cs | Implements HasAnyGetter for properties (getter exists at any accessibility). |
| src/libraries/Microsoft.Extensions.Configuration.Binder/tests/Common/ConfigurationBinderTests.cs | Renames/updates existing test and adds new tests validating set-only binding scenarios. |
| src/libraries/Microsoft.Extensions.Configuration.Binder/tests/Common/ConfigurationBinderTests.TestClasses.cs | Adds new POCOs used by the new/updated set-only binding tests. |
Comments suppressed due to low confidence (1)
src/libraries/Microsoft.Extensions.Configuration.Binder/tests/Common/ConfigurationBinderTests.cs:1386
- New behavior adds support for set-only properties, including honoring
BindNonPublicPropertiesfor non-public setters in the reflection binder. There’s no test exercising a true set-only property with a non-public setter (and no getter) that only becomes bindable whenBindNonPublicProperties = true, which would help prevent regressions in the new accessibility checks.
public void BindsSetOnlyProperties()
{
var dic = new Dictionary<string, string>
{
{"SetOnly", "42"},
{"PrivateGetter", "42"},
{"InitOnly", "42"},
};
You can also share your feedback on Copilot code review. Take the survey.
src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Emitter/CoreBindingHelpers.cs
Show resolved
Hide resolved
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
Enables Microsoft.Extensions.Configuration.Binder to bind configuration values to true set-only properties (setter present, no getter) in both the reflection-based binder and the configuration binding source generator, aligning behavior with the documented expectations.
Changes:
- Update reflection binder property binding to support set-only properties while continuing to skip properties that only have non-public getters (unless opted in via
BindNonPublicProperties). - Extend source generator member modeling and emitted binding logic to support true set-only properties (including complex types and empty-string → empty-array behavior).
- Add/adjust tests to validate binding set-only properties (simple, type conversion, and complex object binding), plus update expectations for virtual set-only property binding.
Reviewed changes
Copilot reviewed 6 out of 6 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| src/libraries/Microsoft.Extensions.Configuration.Binder/src/ConfigurationBinder.cs | Updates reflection binder to bind set-only properties by adjusting property eligibility checks and binding-point initialization. |
| src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Specs/Members/MemberSpec.cs | Adds HasAnyGetter to distinguish true set-only properties from properties with non-public getters. |
| src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Specs/Members/PropertySpec.cs | Implements HasAnyGetter based on Roslyn symbol getter presence. |
| src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Emitter/CoreBindingHelpers.cs | Updates generated binding logic to allow true set-only properties and avoid emitting getter-dependent code paths when no getter exists. |
| src/libraries/Microsoft.Extensions.Configuration.Binder/tests/Common/ConfigurationBinderTests.cs | Renames/updates existing test and adds new tests for set-only binding scenarios; updates virtual set-only property expectation. |
| src/libraries/Microsoft.Extensions.Configuration.Binder/tests/Common/ConfigurationBinderTests.TestClasses.cs | Expands/adjusts test POCOs to track per-property invocation and introduces new set-only test types. |
You can also share your feedback on Copilot code review. Take the survey.
src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Emitter/CoreBindingHelpers.cs
Outdated
Show resolved
Hide resolved
src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Emitter/CoreBindingHelpers.cs
Outdated
Show resolved
Hide resolved
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
This PR updates Microsoft.Extensions.Configuration.Binder to allow configuration binding to true set-only properties (public setter with no getter at all) in both the reflection-based binder and the source generator, aligning behavior more closely with documented expectations.
Changes:
- Reflection binder: allow binding to properties with no getter, when an accessible setter exists.
- Source generator: distinguish “no getter at all” vs “non-public getter” and bind only the former (when settable).
- Tests: add coverage for set-only binding scenarios (including type conversion and complex objects) and update virtual set-only property expectations.
Reviewed changes
Copilot reviewed 6 out of 6 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| src/libraries/Microsoft.Extensions.Configuration.Binder/src/ConfigurationBinder.cs | Enables reflection binder to bind true set-only properties and adjusts binding point initialization accordingly. |
| src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Emitter/CoreBindingHelpers.cs | Updates source-gen emission rules to support true set-only properties while continuing to skip non-public getters for parity. |
| src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Specs/Members/MemberSpec.cs | Introduces HasAnyGetter to distinguish true set-only properties from non-public getter properties. |
| src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Specs/Members/PropertySpec.cs | Implements HasAnyGetter based on presence of any getter on the symbol. |
| src/libraries/Microsoft.Extensions.Configuration.Binder/tests/Common/ConfigurationBinderTests*.cs | Adds/updates tests validating set-only binding behavior (string, conversion, complex) and virtual set-only binding. |
You can also share your feedback on Copilot code review. Take the survey.
src/libraries/Microsoft.Extensions.Configuration.Binder/src/ConfigurationBinder.cs
Show resolved
Hide resolved
src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Emitter/CoreBindingHelpers.cs
Outdated
Show resolved
Hide resolved
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
This PR updates Microsoft.Extensions.Configuration.Binder to allow binding to true set-only properties (properties with a setter but no getter) in both the reflection-based binder and the source-generated binder, aligning behavior with documented expectations.
Changes:
- Reflection binder: allow binding to set-only properties while still skipping indexers and respecting
BindNonPublicPropertiesfor accessor visibility. - Source generator: add a
HasAnyGetterdistinction so true set-only properties can be bound, while properties with non-public getters are still skipped to match reflection behavior. - Tests: expand coverage to validate binding of set-only properties, including type conversion and complex object binding; update an existing virtual-property test to reflect the new behavior.
Reviewed changes
Copilot reviewed 6 out of 6 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| src/libraries/Microsoft.Extensions.Configuration.Binder/tests/Common/ConfigurationBinderTests.cs | Adds/updates tests to validate binding to set-only properties (including conversion/complex types) and updates the virtual set-only property expectation. |
| src/libraries/Microsoft.Extensions.Configuration.Binder/tests/Common/ConfigurationBinderTests.TestClasses.cs | Updates/introduces test POCOs for set-only scenarios (simple, complex, and conversion-driven). |
| src/libraries/Microsoft.Extensions.Configuration.Binder/src/ConfigurationBinder.cs | Enables reflection-based binding for true set-only properties while maintaining indexer/non-public filtering rules. |
| src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Specs/Members/PropertySpec.cs | Tracks presence of any getter (HasAnyGetter) to differentiate true set-only vs non-public getters for generator decisions. |
| src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Specs/Members/MemberSpec.cs | Introduces HasAnyGetter to support generator logic distinctions around getter presence. |
| src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Emitter/CoreBindingHelpers.cs | Updates emitted binding logic to handle true set-only properties without reading current values. |
You can also share your feedback on Copilot code review. Take the survey.
src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Emitter/CoreBindingHelpers.cs
Outdated
Show resolved
Hide resolved
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
This PR updates Microsoft.Extensions.Configuration.Binder to support binding to true set-only properties (properties with a setter but no getter) in both the reflection-based binder and the source generator, aligning behavior with documented expectations (Issue #63508).
Changes:
- Reflection binder: allow binding to set-only properties by validating accessibility via the setter when no getter exists.
- Source generator: distinguish true set-only properties (no getter at all) from properties with non-public getters, and emit binding code accordingly.
- Tests: expand coverage for set-only property binding (including type conversion and complex types) and update a virtual set-only property test expectation.
Reviewed changes
Copilot reviewed 6 out of 6 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| src/libraries/Microsoft.Extensions.Configuration.Binder/tests/Common/ConfigurationBinderTests.cs | Updates/expands tests to validate binding to set-only properties and adjusts an existing virtual-property assertion. |
| src/libraries/Microsoft.Extensions.Configuration.Binder/tests/Common/ConfigurationBinderTests.TestClasses.cs | Refactors/extends test POCOs to track which set-only properties were invoked; adds new set-only test types. |
| src/libraries/Microsoft.Extensions.Configuration.Binder/src/ConfigurationBinder.cs | Enables reflection-based binding for true set-only properties and adjusts setter-invocation conditions. |
| src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Specs/Members/PropertySpec.cs | Adds HasAnyGetter metadata for distinguishing true set-only vs non-public getter cases. |
| src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Specs/Members/MemberSpec.cs | Introduces HasAnyGetter (virtual) to support source-gen decisions around set-only properties. |
| src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Emitter/CoreBindingHelpers.cs | Updates emitted binding logic to support true set-only properties while continuing to skip properties with non-public getters. |
You can also share your feedback on Copilot code review. Take the survey.
src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Emitter/CoreBindingHelpers.cs
Outdated
Show resolved
Hide resolved
...libraries/Microsoft.Extensions.Configuration.Binder/tests/Common/ConfigurationBinderTests.cs
Show resolved
Hide resolved
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
Enables Microsoft.Extensions.Configuration.Binder to bind to true set-only properties (setter present, no getter at all) in both the reflection-based binder and the source generator, aligning behavior with documented expectations.
Changes:
- Update reflection binder property-binding logic to allow set-only properties while preserving indexer/non-public accessor rules.
- Extend source generator specs/emitter to distinguish true set-only properties from properties with non-public getters and emit appropriate binding code.
- Add/adjust unit tests covering set-only binding scenarios (including type conversion and complex/struct properties).
Reviewed changes
Copilot reviewed 6 out of 6 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| src/libraries/Microsoft.Extensions.Configuration.Binder/tests/Common/ConfigurationBinderTests.cs | Adds/updates tests for set-only binding; currently contains a compile-breaking type declaration placement. |
| src/libraries/Microsoft.Extensions.Configuration.Binder/tests/Common/ConfigurationBinderTests.TestClasses.cs | Updates existing test POCO and adds new POCOs used by the new set-only tests. |
| src/libraries/Microsoft.Extensions.Configuration.Binder/src/ConfigurationBinder.cs | Allows binding set-only properties in reflection binder and refines setter invocation conditions. |
| src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Specs/Members/PropertySpec.cs | Adds HasAnyGetter tracking to distinguish true set-only properties in generator. |
| src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Specs/Members/MemberSpec.cs | Introduces HasAnyGetter abstraction and documentation for generator logic. |
| src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Emitter/CoreBindingHelpers.cs | Updates generator emission logic to bind true set-only properties while skipping non-public getters. |
You can also share your feedback on Copilot code review. Take the survey.
The configuration binder previously skipped all properties without a getter. This change enables binding to true set-only properties (those with a setter but no getter at all) in both the reflection-based binder and the source generator.
Fixes #63508.