Skip to content

Handle null FieldName in FieldIdentifier.GetHashCode#66409

Open
MohamedOthman1 wants to merge 2 commits intodotnet:mainfrom
MohamedOthman1:bugfix/45096-fieldidentifier-default-hashcode
Open

Handle null FieldName in FieldIdentifier.GetHashCode#66409
MohamedOthman1 wants to merge 2 commits intodotnet:mainfrom
MohamedOthman1:bugfix/45096-fieldidentifier-default-hashcode

Conversation

@MohamedOthman1
Copy link
Copy Markdown

Summary

Fixes #45096.

FieldIdentifier is a readonly struct whose public constructor rejects null for fieldName. However, default(FieldIdentifier) bypasses the constructor and leaves Model and FieldName as null. Calling GetHashCode() on that default value invokes StringComparer.Ordinal.GetHashCode(null), which throws:

System.ArgumentNullException: Value cannot be null. (Parameter 'obj')

This surfaces via any caller that hashes a default-valued FieldIdentifier — most commonly EditContext.NotifyFieldChanged, which uses a Dictionary<FieldIdentifier, FieldState> keyed on the identifier. The repro in the issue hits this when a component calls EditContext.NotifyFieldChanged(FieldIdentifier) before its ValueExpression has been assigned.

Fix

Guard FieldIdentifier.GetHashCode() against a null FieldName. Model is already safe because RuntimeHelpers.GetHashCode(null) returns 0 and does not throw. Equals also already handles null via string.Equals(..., StringComparison.Ordinal), so no change is needed there.

This is a root-cause fix at the struct level, so every consumer (NotifyFieldChanged, MarkAsUnmodified, GetValidationMessages(FieldIdentifier), IsValid(FieldIdentifier), etc.) benefits automatically — rather than adding a guard at each public entry point.

Tests

Added three tests to FieldIdentifierTest covering default(FieldIdentifier):

  • DefaultFieldIdentifier_GetHashCode_DoesNotThrow — regression test against the original crash.
  • DefaultFieldIdentifiers_AreEqual — verifies consistent equality / hash between two default values.
  • DefaultFieldIdentifier_CanBeUsedAsDictionaryKey — mirrors the real-world EditContext usage.

Full Microsoft.AspNetCore.Components.Forms.Tests suite: 81 passed, 0 failed locally.

The public constructor rejects null fieldName, but `default(FieldIdentifier)`
bypasses it and leaves both Model and FieldName as null. Calling GetHashCode
on that default value invoked StringComparer.Ordinal.GetHashCode(null), which
throws ArgumentNullException with the message "Value cannot be null.
(Parameter 'obj')" — surfaced by callers such as EditContext.NotifyFieldChanged.

Guard against the null FieldName so dictionary lookups and Equals comparisons
work for default-valued instances. Model is already safe because
RuntimeHelpers.GetHashCode returns 0 for null.

Fixes dotnet#45096
Copilot AI review requested due to automatic review settings April 21, 2026 17:55
@MohamedOthman1 MohamedOthman1 requested a review from a team as a code owner April 21, 2026 17:55
@github-actions github-actions Bot added the needs-area-label Used by the dotnet-issue-labeler to label those issues which couldn't be triaged automatically label Apr 21, 2026
@dotnet-policy-service dotnet-policy-service Bot added the community-contribution Indicates that the PR has been added by a community member label Apr 21, 2026
@dotnet-policy-service
Copy link
Copy Markdown
Contributor

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

Copy link
Copy Markdown
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

Fixes a crash when default(FieldIdentifier) is used as a dictionary key (or otherwise hashed) by making FieldIdentifier.GetHashCode() resilient to a null FieldName, which can occur when the struct is default-initialized (bypassing the constructor).

Changes:

  • Guard FieldIdentifier.GetHashCode() against FieldName == null to prevent ArgumentNullException.
  • Add regression tests ensuring default FieldIdentifier hashing/equality works and it can be used as a dictionary key.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.

File Description
src/Components/Forms/src/FieldIdentifier.cs Prevents GetHashCode() from throwing when FieldName is null on a default struct value.
src/Components/Forms/test/FieldIdentifierTest.cs Adds regression coverage for hashing/equality and dictionary usage of default(FieldIdentifier).

@MohamedOthman1
Copy link
Copy Markdown
Author

@dotnet-policy-service agree

@martincostello martincostello added area-blazor Includes: Blazor, Razor Components and removed needs-area-label Used by the dotnet-issue-labeler to label those issues which couldn't be triaged automatically labels Apr 21, 2026
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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Blazor Value cannot be null. (Parameter 'obj')

3 participants