Skip to content

Fix NullReferenceException when InputSelect (multiple) has no selection - #66868

Open
irfanajaffer wants to merge 57 commits into
dotnet:mainfrom
irfanajaffer:1028792_InputSelect
Open

irfanajaffer wants to merge 57 commits into
dotnet:mainfrom
irfanajaffer:1028792_InputSelect

Conversation

@irfanajaffer

@irfanajaffer irfanajaffer commented May 27, 2026 •

Copy link
Copy Markdown
Contributor

Description:

When data-binding to an array type in a Blazor component (for example using @Bind with a property of type T[]), formatting a null array value could throw a NullReferenceException. The exception occurred because the FormatArrayValue delegate inside BindConverter.MakeArrayFormatter() accessed the array's Length (value.Length) without first checking whether value was null.
This change adds a null-guard at the start of the FormatArrayValue local function in BindConverter.cs:
if (value is null) return null;
This short-circuits formatting for uninitialized arrays and prevents the NullReferenceException when resolving the string representation during component parameter binding.

Root Cause

The local FormatArrayValue function assumed the incoming array was non-null and immediately accessed value.Length and iterated the elements. When a bound array property was null, this access caused a NullReferenceException. A simple null-check was missing at the start of the formatter.

Testing

Added a unit test that exercises the array formatter with a null array input and asserts that:
No exception is thrown when formatting a null array.
The formatter returns null (or the expected string representation for null per contract).
Verified existing binding tests still pass.

Fixes #54431

@irfanajaffer
irfanajaffer requested a review from a team as a code owner May 27, 2026 10:29
@github-actions github-actions Bot added the area-blazor Includes: Blazor, Razor Components label May 27, 2026
@dotnet-policy-service dotnet-policy-service Bot added the community-contribution Indicates that the PR has been added by a community member label May 27, 2026
@dotnet-policy-service

Copy link
Copy Markdown
Contributor

Thanks for your PR, @irfanajaffer. Someone from the team will get assigned to your PR shortly and we'll get it reviewed.

@irfanajaffer

Copy link
Copy Markdown
Contributor Author

@dotnet-policy-service agree company="Syncfusion, Inc."

@ilonatommy ilonatommy left a comment •

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

When this feature landed, #33950, E2E tests were added. Let's patch their coverage in this PR with a null array test -> next to

<InputSelect @bind-Value="person.TicketClass" size="4" multiple>

Beyond that, I'm thinking if null is really better than "[]". Is there a specific case when differentiation between never-selected from all-unseleced matters?

@irfanajaffer
irfanajaffer requested a review from ilonatommy July 8, 2026 04:05
Comment thread src/Components/Components/test/BindConverterTest.cs Outdated
Comment thread src/Components/Web/test/Forms/InputSelectTest.cs Outdated
Comment thread src/Components/Forms/src/FieldIdentifier.cs Outdated
@dotnet-policy-service

Copy link
Copy Markdown
Contributor

Looks like this PR hasn't been active for some time and the codebase could have been changed in the meantime.
To make sure no conflicting changes have occurred, please rerun validation before merging. You can do this by leaving an /azp run comment here (requires commit rights), or by simply closing and reopening.

@dotnet-policy-service dotnet-policy-service Bot added the pending-ci-rerun When assigned to a PR indicates that the CI checks should be rerun label Sep 26, 2026

@PureWeen PureWeen left a comment •

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Written with GitHub Copilot (AI), which did the code reading and the local test runs described below ("I" refers to those runs). Posted by PureWeen.

Thanks for sticking with this. I went through the follow-up at 2fd5f52 and ilonatommy's earlier requests look addressed, and the top-level string[] case from #54431 now maps to []. I ran the mapper/BindConverter/InputSelect tests locally and found one regression that I think needs fixing before this merges. It's the same cause in two places, see the inline comments.

I didn't run the E2E tests (FormsTest / InputSelectMultipleDeselectAllTest), so the SSR scenario is only checked at the FormDataMapper level.

Separately, ilonatommy's 2026-07-02 "changes requested" review is still recorded as outstanding even though his requests look addressed, so it'll need a re-review or dismissal from a maintainer once the above is sorted.

Comment thread src/Components/Endpoints/src/FormMapping/Converters/CollectionConverter.cs Outdated
Comment thread src/Components/Endpoints/src/FormMapping/Converters/DictionaryConverter.cs Outdated

@PureWeen PureWeen left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Written with GitHub Copilot (AI), which did the code reading and the local test runs described below ("I" refers to those runs). Posted by PureWeen.

Looked at 376d934. The two problems from my earlier review (found = true leaking through the complex-type converter) are fixed: List<Person> / List<List<int>> terminate again, absent nested objects stay null, and a missing required collection reports "Missing required value". Re-adding found = true makes exactly the 12 new theory rows fail, so the new tests do guard it.

One new thing, inline: the empty-on-absence change applies to every collection and dictionary, not just arrays.

ilonatommy's 2026-07-02 changes-requested review is still recorded as outstanding even though its items look addressed, so a maintainer will need to re-review or dismiss it. Also, #68297 edits BindConverter.cs too and conflicts with this PR, so it's worth coordinating which lands first.

Locally at this head: BindConverterTest 50/50, InputSelectTest 16/16, FormDataMapperTests 296/296. I didn't run the E2E tests or the Server tests.

Comment thread src/Components/Endpoints/src/FormMapping/Converters/CollectionConverter.cs Outdated
Comment thread src/Components/Endpoints/src/FormMapping/Converters/DictionaryConverter.cs Outdated
@irfanajaffer

Copy link
Copy Markdown
Contributor Author

@PureWeen ,

Thanks for your review.You're right that my previous change unintentionally broadened the behavior from the original string[] scenario to all collections and dictionaries.

I've updated the implementation to keep the behavior change array-specific:

  1. CollectionConverter now returns an empty value on absence only for array types.
  2. Non-array collections continue to return default when no values are present.
  3. DictionaryConverter has been restored to return default when no keys are provided.
  4. The earlier found = true propagation fix remains unchanged, so the nested collection/dictionary mapping issue and related regression scenarios are still covered.

I also restored the original expectations for lists and dictionaries in FormDataMapperTests and verified that the previously identified regression cases now behave as expected while retaining the intended fix for InputSelect<string[]>.

Validation:

Reproduced the four failing scenarios called out in review by temporarily restoring the previous behavior.
Reapplied the fix and reran the targeted FormDataMapperTests.

This narrows the behavioral change back to the original scope of the PR while preserving the fix for the nested form mapping issue.

This branch has not been deployed

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

Labels

area-blazor Includes: Blazor, Razor Components community-contribution Indicates that the PR has been added by a community member pending-ci-rerun When assigned to a PR indicates that the CI checks should be rerun

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Blazor InputSelect with multiple enabled throws NullRefException if nothing is selected

4 participants