Skip to content

Allow configuration binding to set-only properties#125768

Draft
cincuranet wants to merge 10 commits intodotnet:mainfrom
cincuranet:dev/set-only-config-binding
Draft

Allow configuration binding to set-only properties#125768
cincuranet wants to merge 10 commits intodotnet:mainfrom
cincuranet:dev/set-only-config-binding

Conversation

@cincuranet
Copy link
Contributor

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.

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>
Copilot AI review requested due to automatic review settings March 19, 2026 11:04
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings March 19, 2026 11:13
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 == null and using a BindingPoint without a getter-backed initial value.
  • Source generator: add HasAnyGetter to 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.

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings March 19, 2026 12:34
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 BindNonPublicProperties for 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 when BindNonPublicProperties = 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.

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings March 19, 2026 12:44
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings March 19, 2026 12:54
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings March 19, 2026 13:10
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 BindNonPublicProperties for accessor visibility.
  • Source generator: add a HasAnyGetter distinction 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.

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings March 19, 2026 13:20
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings March 19, 2026 13:31
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Allow configuration binding to set-only properties

2 participants