Skip to content

Add message template formatting to DataAnnotations validation attributes - #132764

Merged
ViveliDuCh merged 3 commits into
mainfrom
api-proposal/dataannotations-format-message
Aug 27, 2026
Merged

Add message template formatting to DataAnnotations validation attributes#132764
ViveliDuCh merged 3 commits into
mainfrom
api-proposal/dataannotations-format-message

Conversation

@ViveliDuCh

Copy link
Copy Markdown
Member

Summary

Adds the approved ValidationAttribute.FormatMessage API so callers can supply externally localized composite-format strings while each validation attribute remains responsible for providing its placeholder arguments.

Changes

  • Add ValidationAttribute.FormatMessage([StringSyntax("CompositeFormat")] string format, string name).
  • Route the base FormatErrorMessage implementation through the new method.
  • Add overrides for CompareAttribute, FileExtensionsAttribute, LengthAttribute, MaxLengthAttribute, MinLengthAttribute, RangeAttribute, RegularExpressionAttribute, and StringLengthAttribute.
  • Preserve existing placeholder ordering and CurrentCulture formatting.
  • Add coverage for supplied formats, virtual dispatch, culture-sensitive formatting, invalid formats, and null arguments.

Existing FormatErrorMessage behavior remains unchanged.

Testing

  • dotnet build — succeeded with 0 warnings and 0 errors.
  • dotnet build /t:test .\tests\System.ComponentModel.Annotations.Tests.csproj — 1,008 passed, 0 failed, 0 skipped.

Fixes #132605

Note

This pull request description was generated with GitHub Copilot.

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 3 pipeline(s).
13 pipeline(s) were filtered out due to trigger conditions.
There may be pipelines that require an authorized user to comment /azp run to run.

@dotnet-policy-service

Copy link
Copy Markdown
Contributor

Tagging subscribers to this area: @dotnet/area-system-componentmodel-dataannotations
See info in area-owners.md if you want to be subscribed.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Adds a new public formatting primitive to DataAnnotations validation attributes so callers can supply an external composite-format template while each attribute remains responsible for projecting its own placeholder arguments.

Changes:

  • Add ValidationAttribute.FormatMessage([StringSyntax("CompositeFormat")] string format, string name) and route the base FormatErrorMessage implementation through it.
  • Override FormatMessage in built-in attributes that require additional placeholders (e.g., {1}, {2}), preserving existing argument ordering and CurrentCulture formatting behavior.
  • Add/extend tests to cover supplied formats, virtual dispatch, culture-sensitive formatting, and invalid/null formats.

Reviewed changes

Copilot reviewed 19 out of 19 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
src/libraries/System.ComponentModel.Annotations/src/System/ComponentModel/DataAnnotations/ValidationAttribute.cs Introduces FormatMessage and updates base FormatErrorMessage to delegate through it.
src/libraries/System.ComponentModel.Annotations/src/System/ComponentModel/DataAnnotations/CompareAttribute.cs Overrides FormatMessage to supply the other-property display name argument.
src/libraries/System.ComponentModel.Annotations/src/System/ComponentModel/DataAnnotations/FileExtensionsAttribute.cs Overrides FormatMessage to supply normalized/dot-prefixed extensions.
src/libraries/System.ComponentModel.Annotations/src/System/ComponentModel/DataAnnotations/LengthAttribute.cs Overrides FormatMessage to supply min/max length placeholders.
src/libraries/System.ComponentModel.Annotations/src/System/ComponentModel/DataAnnotations/MaxLengthAttribute.cs Overrides FormatMessage to supply the max length placeholder.
src/libraries/System.ComponentModel.Annotations/src/System/ComponentModel/DataAnnotations/MinLengthAttribute.cs Overrides FormatMessage to supply the min length placeholder.
src/libraries/System.ComponentModel.Annotations/src/System/ComponentModel/DataAnnotations/RangeAttribute.cs Overrides FormatMessage to supply converted min/max placeholders.
src/libraries/System.ComponentModel.Annotations/src/System/ComponentModel/DataAnnotations/RegularExpressionAttribute.cs Overrides FormatMessage to supply the regex pattern placeholder.
src/libraries/System.ComponentModel.Annotations/src/System/ComponentModel/DataAnnotations/StringLengthAttribute.cs Overrides FormatMessage to supply maximum/minimum length placeholders and keeps default-template selection in FormatErrorMessage.
src/libraries/System.ComponentModel.Annotations/ref/System.ComponentModel.Annotations.cs Updates public surface area (ref) to include the new virtual and related overrides.
src/libraries/System.ComponentModel.Annotations/tests/System/ComponentModel/DataAnnotations/ValidationAttributeTests.cs Adds base-level tests for FormatMessage, null/invalid format behavior, and FormatErrorMessage virtual dispatch.
src/libraries/System.ComponentModel.Annotations/tests/System/ComponentModel/DataAnnotations/CompareAttributeTests.cs Adds coverage for CompareAttribute.FormatMessage argument projection and display-name behavior.
src/libraries/System.ComponentModel.Annotations/tests/System/ComponentModel/DataAnnotations/FileExtensionsAttributeTests.cs Adds coverage for FileExtensionsAttribute.FormatMessage using normalized extensions.
src/libraries/System.ComponentModel.Annotations/tests/System/ComponentModel/DataAnnotations/LengthAttributeTests.cs Adds coverage for LengthAttribute.FormatMessage placeholder projection.
src/libraries/System.ComponentModel.Annotations/tests/System/ComponentModel/DataAnnotations/MaxLengthAttributeTests.cs Adds coverage for MaxLengthAttribute.FormatMessage placeholder projection.
src/libraries/System.ComponentModel.Annotations/tests/System/ComponentModel/DataAnnotations/MinLengthAttributeTests.cs Adds coverage for MinLengthAttribute.FormatMessage placeholder projection.
src/libraries/System.ComponentModel.Annotations/tests/System/ComponentModel/DataAnnotations/RangeAttributeTests.cs Adds coverage for RangeAttribute.FormatMessage conversion and culture-sensitive formatting.
src/libraries/System.ComponentModel.Annotations/tests/System/ComponentModel/DataAnnotations/RegularExpressionAttributeTests.cs Adds coverage for RegularExpressionAttribute.FormatMessage supplying the pattern.
src/libraries/System.ComponentModel.Annotations/tests/System/ComponentModel/DataAnnotations/StringLengthAttributeTests.cs Adds coverage for StringLengthAttribute.FormatMessage placeholder projection and FormatErrorMessage behavior.

Add the approved ValidationAttribute.FormatMessage API for caller-supplied composite formats and project built-in attribute arguments through overrides.

Cover culture, virtual dispatch, error paths, and source/ref naming consistency.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 524df8bb-0555-4425-b73f-bc8340d0dfc2
Copilot AI review requested due to automatic review settings August 25, 2026 21:54
@ViveliDuCh
ViveliDuCh force-pushed the api-proposal/dataannotations-format-message branch from db016ee to c3ab07b Compare August 25, 2026 21:54

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

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

@tarekgh

tarekgh commented Aug 25, 2026

Copy link
Copy Markdown
Member

Should we also update the validation attribute replicas emitted by Microsoft.Extensions.Options/gen/Emitter.cs: CompareAttribute, LengthAttribute, MaxLengthAttribute, MinLengthAttribute, and RangeAttribute? They currently inherit the base FormatMessage, which supplies only {0}. When the target exposes the new API, these replicas should conditionally override FormatMessage with the same [StringSyntax(CompositeFormat)] annotation and attribute-specific arguments. Otherwise, they do not preserve the new built-in attribute contract.

Copilot AI review requested due to automatic review settings August 26, 2026 02:07

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

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

- Detect FormatMessage support from target compilation symbols
- Preserve attribute-specific arguments in generated replicas
- Share Range initialization between validation and formatting
- Add deterministic baselines and runtime regression coverage

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 524df8bb-0555-4425-b73f-bc8340d0dfc2
Copilot AI review requested due to automatic review settings August 26, 2026 04:51
@ViveliDuCh
ViveliDuCh force-pushed the api-proposal/dataannotations-format-message branch from 6ec2050 to 43ba3c4 Compare August 26, 2026 04:51

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

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

Comment thread src/libraries/Microsoft.Extensions.Options/gen/Emitter.cs Outdated

@oroztocil oroztocil 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.

Looks good.

I don't have a strong opinion about the added argument null checks. They are redundant, but also mean the exception is thrown at the level of the public contract. Considering the existing FormatErrorMessage did not have them, I would probably remove them from FormatMessage too.

Rely on string.Format to validate null format strings, use a valid RangeAttribute in null-format coverage, and update generated baselines.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 524df8bb-0555-4425-b73f-bc8340d0dfc2
Copilot AI review requested due to automatic review settings August 26, 2026 15:54

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

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

@tarekgh tarekgh 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.

LGTM, Thanks!

@ViveliDuCh

Copy link
Copy Markdown
Member Author

/ba-g Remaining unclassified failures are the CompositeMLDsaCngTests Windows failures tracked by known issue #132830, unrelated to this PR.

@ViveliDuCh
ViveliDuCh disabled auto-merge August 27, 2026 19:29
@ViveliDuCh
ViveliDuCh merged commit c365a0b into main Aug 27, 2026
78 of 80 checks passed
@ViveliDuCh
ViveliDuCh deleted the api-proposal/dataannotations-format-message branch August 27, 2026 19:30
@ViveliDuCh

Copy link
Copy Markdown
Member Author

/backport to release/11.0

@github-actions

Copy link
Copy Markdown
Contributor

Started backporting to release/11.0 (link to workflow run)

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.

[API Proposal] Message template formatting support for DataAnnotations validation attributes

5 participants