Honour ErrorOnUnknownConfiguration on value conversion fail - #131933
Draft
rosebyte wants to merge 1 commit into
Draft
Honour ErrorOnUnknownConfiguration on value conversion fail#131933rosebyte wants to merge 1 commit into
rosebyte wants to merge 1 commit into
Conversation
…otnet#131354) # Honour ErrorOnUnknownConfiguration on value conversion fail Fixes dotnet#98231 ## Problem `BinderOptions.ErrorOnUnknownConfiguration` is documented as controlling whether the binder throws "when converting a value", but it was only honoured on some of the paths that can fail: | Failure | Flag honoured? | |---|---| | Unknown configuration key | Yes | | Leaf value with no `TypeConverter` at all | Yes | | Collection item that fails to convert | Yes | | **Leaf value whose `TypeConverter` throws** | **No, always threw** | So a single malformed value in an otherwise valid configuration source would tear down binding even for callers that had deliberately left the flag at its default: ```csharp // appsettings.json: { "Timeout": "not-a-number" } var options = config.Get<MyOptions>(); // threw InvalidOperationException ``` This is inconsistent both with the documented contract on the property and with the sibling "no converter" case a few lines away in the same method, which already returned quietly. ## Fix Gate the rethrow on the flag, in both the reflection binder and the source generator. ### Reflection binder `BindInstance` no longer rethrows the conversion error unconditionally; it returns and leaves the binding point untouched, so the member keeps whatever value it already had. ### Source generator The emitted `ParseX(value, path)` helpers become `TryParseX(value, path, errorOnFailedBinding, out result)`: ```csharp public static bool TryParseInt(string value, string? path, bool errorOnFailedBinding, out int result) { try { result = int.Parse(value, NumberStyles.Integer, CultureInfo.InvariantCulture); return true; } catch when (!errorOnFailedBinding) { result = default; return false; } catch (Exception exception) { throw new InvalidOperationException($"Failed to convert configuration value '{value ?? "null"}' at '{path}' to type '{typeof(int)}'.", exception); } } ``` Call sites pass `binderOptions?.ErrorOnUnknownConfiguration is true`, except for two cases that must always report the failure: - `GetValueCore`, since `GetValue<T>` has no `BinderOptions` overload. - Constructor parameters with no declared default, which are unsatisfiable either way. These keep throwing the accurate `Failed to convert configuration value ...` rather than degrading to `... has no matching config`. A try/catch at each call site was considered instead, but it would also have swallowed nested binding errors in the dictionary case; a `Func<>`-based helper would have allocated. ## Behaviour change This is a breaking change and will need a breaking-change doc. | Scenario | Before | After | |---|---|---| | `Bind` / `Get<T>` with an unconvertible scalar, default options | throws | member keeps its existing value | | `GetSection("x").Get<int>()` with a bad value | throws | `default(int)` | | Same, with `ErrorOnUnknownConfiguration = true` | throws | throws (unchanged) | | `GetValue<T>` with a bad value | throws | throws (unchanged) | | Required constructor parameter with a bad value | throws | throws (unchanged) | | Constructor parameter with a declared default and a bad value | throws | falls back to the default | The `Get`/`Bind` versus `GetValue` asymmetry is deliberate and follows the design agreed in the issue, but it is user-visible. ## Also in this change - Fixes a latent generator bug: a primitive section with an empty value used to fall through `GetCore` to `throw new NotSupportedException("Unable to bind to type ...: generator did not detect the type as input.")`. It now returns `null`, matching the reflection binder. - Fixes a hard-coded path separator in `GeneratorTests.Helpers.cs` that stopped `/p:UpdateBaselines=true` working on non-Windows hosts. - Un-gates two `CollectionsBindingWithErrorOnUnknownConfiguration` tests that were restricted to the reflection binder; they now pass under source generation too. ## Testing - 4 existing tests that asserted the old unconditional throw now opt in with `ErrorOnUnknownConfiguration = true`. - New regression tests cover both flag states, the `GetValue` carve-out, and constructor parameters with and without declared defaults. All run in both binder modes. - 111 of the 120 generator baselines regenerated (`netcoreapp` and `net462`, `Version0` and `Version1`). Some `net462` `Version0` files additionally pick up unrelated drift corrections that had accumulated on `main`. ``` Microsoft.Extensions.Configuration.Binder.Tests 356 passed, 0 failed Microsoft.Extensions.Configuration.Binder.SourceGeneration.Tests 433 passed, 0 failed, 26 skipped ```
|
Azure Pipelines: Successfully started running 4 pipeline(s). 12 pipeline(s) were filtered out due to trigger conditions. There may be pipelines that require an authorized user to comment /azp run to run. |
Contributor
There was a problem hiding this comment.
Pull request overview
This PR updates Microsoft.Extensions.Configuration.Binder to consistently honor BinderOptions.ErrorOnUnknownConfiguration when value conversion fails, including when a TypeConverter exists but throws, and aligns the source-generated binder behavior with the reflection binder.
Changes:
- Reflection binder: suppresses conversion exceptions by default and preserves existing member values unless
ErrorOnUnknownConfiguration(or a required-parameter carve-out) forces throwing. - Source generator: replaces
ParseXhelpers withTryParseX(..., errorOnFailedBinding, out result)and updates call sites/baselines to gate conversion failures on the binder option (with explicit always-throw carve-outs). - Tests/baselines: add coverage for the new behavior and update generator baselines; fix baseline update path handling for non-Windows hosts.
Reviewed changes
Copilot reviewed 118 out of 118 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 | Gates leaf conversion failures on ErrorOnUnknownConfiguration (and a required-parameter “must throw” path). |
| src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Specs/TypeIndex.cs | Renames/retargets parse helper naming to TryParse* for generated code. |
| src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Emitter/Helpers.cs | Adds generator identifiers/expressions to plumb errorOnFailedBinding and result through emitted helpers. |
| src/libraries/Microsoft.Extensions.Configuration.Binder/tests/Common/ConfigurationBinderTests.cs | Updates existing tests to opt into throwing and adds new tests for default “suppress conversion failures” behavior + carve-outs. |
| src/libraries/Microsoft.Extensions.Configuration.Binder/tests/Common/ConfigurationBinderTests.TestClasses.cs | Adds new test model and ungates two tests to run under source-gen mode as well. |
| src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/GeneratorTests.Helpers.cs | Fixes baseline-update path composition to be cross-platform. |
| src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/Version1/UnsupportedTypes.generated.txt | Baseline update for TryParse* + option-gated conversion handling. |
| src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/Version0/EmptyConfigType.generated.txt | Baseline update for type name qualification / helper signatures. |
| src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/ServiceCollection/Version1/Configure_T.generated.txt | Baseline update for TryParse* call pattern. |
| src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/ServiceCollection/Version1/Configure_T_name.generated.txt | Baseline update for TryParse* call pattern. |
| src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/ServiceCollection/Version1/Configure_T_name_BinderOptions.generated.txt | Baseline update for TryParse* call pattern. |
| src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/ServiceCollection/Version1/Configure_T_BinderOptions.generated.txt | Baseline update for TryParse* call pattern. |
| src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/OptionsBuilder/Version1/BindConfigurationWithConfigureActions.generated.txt | Baseline update for TryParse* call pattern. |
| src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/OptionsBuilder/Version1/BindConfiguration.generated.txt | Baseline update for TryParse* call pattern. |
| src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/OptionsBuilder/Version1/Bind_T.generated.txt | Baseline update for TryParse* call pattern. |
| src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/OptionsBuilder/Version1/Bind_T_BinderOptions.generated.txt | Baseline update for TryParse* call pattern. |
| src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/OptionsBuilder/Version0/BindConfigurationWithConfigureActions.generated.txt | Baseline update for TryParse* call pattern + qualification drift. |
| src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/OptionsBuilder/Version0/BindConfiguration.generated.txt | Baseline update for TryParse* call pattern + qualification drift. |
| src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/ConfigurationBinder/Version1/GetValue.generated.txt | Baseline update: GetValueCore uses TryParse* with always-throw behavior. |
| src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/ConfigurationBinder/Version1/GetValue_TypeOf_Key.generated.txt | Baseline update: TryParse* always-throw for GetValue*. |
| src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/ConfigurationBinder/Version1/GetValue_TypeOf_Key_DefaultValue.generated.txt | Baseline update: TryParse* always-throw for GetValue*. |
| src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/ConfigurationBinder/Version1/GetValue_T_Key.generated.txt | Baseline update: TryParse* always-throw for GetValue*. |
| src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/ConfigurationBinder/Version1/GetValue_T_Key_DefaultValue.generated.txt | Baseline update: TryParse* always-throw for GetValue*. |
| src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/ConfigurationBinder/Version1/Get_TypeOf.generated.txt | Baseline update for TryParse* call pattern. |
| src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/ConfigurationBinder/Version1/Get_TypeOf_BinderOptions.generated.txt | Baseline update for TryParse* call pattern. |
| src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/ConfigurationBinder/Version1/Get_PrimitivesOnly.generated.txt | Baseline update: primitive leaf binding returns null on empty/unconvertible values unless opted in. |
| src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/ConfigurationBinder/Version1/Bind.generated.txt | Baseline update for TryParse* call pattern. |
| src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/ConfigurationBinder/Version1/Bind_Key_Instance.generated.txt | Baseline update for TryParse* call pattern. |
| src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/ConfigurationBinder/Version1/Bind_Instance.generated.txt | Baseline update for TryParse* call pattern. |
| src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/ConfigurationBinder/Version1/Bind_Instance_BinderOptions.generated.txt | Baseline update for TryParse* call pattern. |
| src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/ConfigurationBinder/Version0/GetValue.generated.txt | Baseline update: TryParse* always-throw for GetValue*. |
| src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/ConfigurationBinder/Version0/GetValue_TypeOf_Key.generated.txt | Baseline update: TryParse* always-throw for GetValue*. |
| src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/ConfigurationBinder/Version0/GetValue_TypeOf_Key_DefaultValue.generated.txt | Baseline update: TryParse* always-throw for GetValue*. |
| src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/ConfigurationBinder/Version0/GetValue_T_Key.generated.txt | Baseline update: TryParse* always-throw for GetValue*. |
| src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/ConfigurationBinder/Version0/GetValue_T_Key_DefaultValue.generated.txt | Baseline update: TryParse* always-throw for GetValue*. |
| src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/ConfigurationBinder/Version0/Get_TypeOf.generated.txt | Baseline update for TryParse* call pattern. |
| src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/ConfigurationBinder/Version0/Get_TypeOf_BinderOptions.generated.txt | Baseline update for TryParse* call pattern. |
| src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/netcoreapp/ConfigurationBinder/Version0/Get_PrimitivesOnly.generated.txt | Baseline update: primitive leaf binding returns null on empty/unconvertible values unless opted in. |
| src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/net462/Version1/UnsupportedTypes.generated.txt | Baseline update for TryParse* + option-gated conversion handling. |
| src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/net462/Version0/EmptyConfigType.generated.txt | Baseline update: emits TryGetConfigurationValue helper + qualification drift. |
| src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/net462/ServiceCollection/Version1/Configure_T.generated.txt | Baseline update for TryParse* call pattern. |
| src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/net462/ServiceCollection/Version1/Configure_T_name.generated.txt | Baseline update for TryParse* call pattern. |
| src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/net462/ServiceCollection/Version1/Configure_T_name_BinderOptions.generated.txt | Baseline update for TryParse* call pattern. |
| src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/net462/ServiceCollection/Version1/Configure_T_BinderOptions.generated.txt | Baseline update for TryParse* call pattern. |
| src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/net462/OptionsBuilder/Version1/BindConfigurationWithConfigureActions.generated.txt | Baseline update for TryParse* call pattern. |
| src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/net462/OptionsBuilder/Version1/BindConfiguration.generated.txt | Baseline update for TryParse* call pattern. |
| src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/net462/OptionsBuilder/Version1/Bind_T.generated.txt | Baseline update for TryParse* call pattern. |
| src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/net462/OptionsBuilder/Version1/Bind_T_BinderOptions.generated.txt | Baseline update for TryParse* call pattern. |
| src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/net462/ConfigurationBinder/Version1/GetValue.generated.txt | Baseline update: TryParse* always-throw for GetValue*. |
| src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/net462/ConfigurationBinder/Version1/GetValue_TypeOf_Key.generated.txt | Baseline update: TryParse* always-throw for GetValue*. |
| src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/net462/ConfigurationBinder/Version1/GetValue_TypeOf_Key_DefaultValue.generated.txt | Baseline update: TryParse* always-throw for GetValue*. |
| src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/net462/ConfigurationBinder/Version1/GetValue_T_Key.generated.txt | Baseline update: TryParse* always-throw for GetValue*. |
| src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/net462/ConfigurationBinder/Version1/GetValue_T_Key_DefaultValue.generated.txt | Baseline update: TryParse* always-throw for GetValue*. |
| src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/net462/ConfigurationBinder/Version1/Get_TypeOf.generated.txt | Baseline update for TryParse* call pattern. |
| src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/net462/ConfigurationBinder/Version1/Get_TypeOf_BinderOptions.generated.txt | Baseline update for TryParse* call pattern. |
| src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/net462/ConfigurationBinder/Version1/Get_PrimitivesOnly.generated.txt | Baseline update: primitive leaf binding returns null on empty/unconvertible values unless opted in. |
| src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/net462/ConfigurationBinder/Version1/Bind.generated.txt | Baseline update for TryParse* call pattern. |
| src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/net462/ConfigurationBinder/Version1/Bind_Key_Instance.generated.txt | Baseline update for TryParse* call pattern. |
| src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/net462/ConfigurationBinder/Version1/Bind_Instance.generated.txt | Baseline update for TryParse* call pattern. |
| src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/net462/ConfigurationBinder/Version1/Bind_Instance_BinderOptions.generated.txt | Baseline update for TryParse* call pattern. |
| src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/net462/ConfigurationBinder/Version0/GetValue.generated.txt | Baseline update: introduces TryGetConfigurationValue and TryParse* helpers for GetValue*. |
| src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/net462/ConfigurationBinder/Version0/GetValue_TypeOf_Key.generated.txt | Baseline update: introduces TryGetConfigurationValue and TryParse* helpers for GetValue*. |
| src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/net462/ConfigurationBinder/Version0/GetValue_TypeOf_Key_DefaultValue.generated.txt | Baseline update: introduces TryGetConfigurationValue and TryParse* helpers for GetValue*. |
| src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/net462/ConfigurationBinder/Version0/GetValue_T_Key.generated.txt | Baseline update: introduces TryGetConfigurationValue and TryParse* helpers for GetValue*. |
| src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/net462/ConfigurationBinder/Version0/GetValue_T_Key_DefaultValue.generated.txt | Baseline update: introduces TryGetConfigurationValue and TryParse* helpers for GetValue*. |
| src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/net462/ConfigurationBinder/Version0/Get_TypeOf.generated.txt | Baseline update: switches to TryGetConfigurationValue + TryParse* pattern. |
| src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/net462/ConfigurationBinder/Version0/Get_TypeOf_BinderOptions.generated.txt | Baseline update: switches to TryGetConfigurationValue + TryParse* pattern. |
| src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/net462/ConfigurationBinder/Version0/Get_PrimitivesOnly.generated.txt | Baseline update: primitive leaf binding uses TryGetConfigurationValue and returns null when unconvertible unless opted in. |
| src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/net462/ConfigurationBinder/Version0/Bind_ParseTypeFromMethodParam.generated.txt | Baseline update: method names and helper inclusion drift (TryGetConfigurationValue emission). |
Comment on lines
+365
to
+373
| // A conversion failure is only reported when the caller opted in, matching how the binder treats | ||
| // a leaf value it has no converter for at all. Otherwise the binding point is left alone so the | ||
| // member keeps whatever value it already had. | ||
| if (options.ErrorOnUnknownConfiguration || errorOnFailedBinding) | ||
| { | ||
| throw error; | ||
| } | ||
|
|
||
| return; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #98231
Problem
BinderOptions.ErrorOnUnknownConfigurationis documented as controlling whether the binderthrows "when converting a value", but it was only honoured on some of the paths that can fail:
TypeConverterat allTypeConverterthrowsSo a single malformed value in an otherwise valid configuration source would tear down binding
even for callers that had deliberately left the flag at its default:
This is inconsistent both with the documented contract on the property and with the sibling
"no converter" case a few lines away in the same method, which already returned quietly.
Fix
Gate the rethrow on the flag, in both the reflection binder and the source generator.
Reflection binder
BindInstanceno longer rethrows the conversion error unconditionally; it returns and leavesthe binding point untouched, so the member keeps whatever value it already had.
Source generator
The emitted
ParseX(value, path)helpers becomeTryParseX(value, path, errorOnFailedBinding, out result):Call sites pass
binderOptions?.ErrorOnUnknownConfiguration is true, except for two cases thatmust always report the failure:
GetValueCore, sinceGetValue<T>has noBinderOptionsoverload.throwing the accurate
Failed to convert configuration value ...rather than degrading to... has no matching config.A try/catch at each call site was considered instead, but it would also have swallowed nested
binding errors in the dictionary case; a
Func<>-based helper would have allocated.Behaviour change
This is a breaking change and will need a breaking-change doc.
Bind/Get<T>with an unconvertible scalar, default optionsGetSection("x").Get<int>()with a bad valuedefault(int)ErrorOnUnknownConfiguration = trueGetValue<T>with a bad valueThe
Get/BindversusGetValueasymmetry is deliberate and follows the design agreed in theissue, but it is user-visible.
Also in this change
GetCoretothrow new NotSupportedException("Unable to bind to type ...: generator did not detect the type as input."). It now returnsnull, matching the reflection binder.GeneratorTests.Helpers.csthat stopped/p:UpdateBaselines=trueworking on non-Windows hosts.CollectionsBindingWithErrorOnUnknownConfigurationtests that were restricted tothe reflection binder; they now pass under source generation too.
Testing
ErrorOnUnknownConfiguration = true.GetValuecarve-out, and constructorparameters with and without declared defaults. All run in both binder modes.
netcoreappandnet462,Version0andVersion1). Somenet462Version0files additionally pick up unrelated drift correctionsthat had accumulated on
main.