Uh oh!
There was an error while loading. Please reload this page.
Add message template formatting to DataAnnotations validation attributes - #132764
Conversation
|
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. |
Tagging subscribers to this area: @dotnet/area-system-componentmodel-dataannotations |
There was a problem hiding this comment.
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 baseFormatErrorMessageimplementation through it. - Override
FormatMessagein built-in attributes that require additional placeholders (e.g.,{1},{2}), preserving existing argument ordering andCurrentCultureformatting 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. |
Uh oh!
There was an error while loading. Please reload this page.
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
db016ee to
c3ab07bComparetarekgh
commented
Aug 25, 2026
Should we also update the validation attribute replicas emitted by |
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
- 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
6ec2050 to
43ba3c4CompareUh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
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
ViveliDuCh
commented
Aug 27, 2026
/ba-g Remaining unclassified failures are the |
Uh oh!
There was an error while loading. Please reload this page.
ViveliDuCh
commented
Aug 27, 2026
/backport to release/11.0 |
Started backporting to |
…idation attributes (#132853) Backport of #132764 to `release/11.0`. API proposal: #132605 /cc @jeffhandley@oroztocil ## Customer Impact - [x] Customer reported - [ ] Found internally .NET 11 introduces first-class localization support in `Microsoft.Extensions.Validation`, consumed by Minimal APIs and Blazor. However, DataAnnotations does not expose a shared way for a caller to supply a localized message template while allowing each validation attribute to provide its own placeholder arguments. Without this change, the .NET 11 localization implementation must retain generated per-attribute formatting switches, other hosts cannot reuse the same primitive, and duplicated formatting knowledge can diverge from the real attribute behavior. One existing example is `FileExtensionsAttribute`, where the attribute supplies normalized, dot-prefixed extensions while duplicated upper-layer formatters have supplied the raw property value. The customer scenario has been requested repeatedly: - dotnet/aspnetcore#4848 - dotnet/aspnetcore#12158 - #72469 - dotnet/aspnetcore#66392 This backport adds the API-approved `ValidationAttribute.FormatMessage` primitive and preserves the attribute-specific formatting contract for built-in attributes and Options source-generated replicas. We believe this meets the .NET 11 RC2 bug bar as: - Significant customer feedback on a feature new in the release. - A significantly incomplete message-presentation scenario in DataAnnotations that affects the new .NET 11 validation stack, including localization in MEV, Minimal APIs, and Blazor. ## Regression - [ ] Yes - [x] No This is not a regression from .NET 10. The API and the first-class `Microsoft.Extensions.Validation` localization scenario are new in .NET 11. ## Testing On `main`: - `System.ComponentModel.Annotations` built successfully. - `System.ComponentModel.Annotations.Tests`: 1,008 passed, 0 failed. - `Microsoft.Extensions.Options` built successfully. - `Microsoft.Extensions.Options.Tests`: 177 net11 tests and 158 net481 tests passed. - `Microsoft.Extensions.Options.SourceGeneration.Unit.Tests`: 103 net11 tests and 82 net481 tests passed, with one expected conditional skip. - `Microsoft.Extensions.Options.SourceGeneration.Tests`: 68 net11 tests and 68 net481 tests passed. - Generated replicas were compiled and executed for C# 10 and C# 11. - The .NET Framework generated output remains unchanged. The same component tests and release-branch CI will validate the backport on `release/11.0`. ## Risk Low-to-moderate. The change adds an API-reviewed public virtual method and explicit overrides on the built-in attributes that require additional format arguments. It is additive and removes no existing surface. Existing `FormatErrorMessage` behavior, argument ordering, and `CurrentCulture` formatting remain unchanged. The Options source generator emits matching overrides only when the target compilation exposes the new API, leaving down-level and .NET Framework output unchanged. The main implementation risks are public virtual dispatch and source-generator parity. These are mitigated by: - API approval in #132605. - Technical review and approval on #132764. - Source/ref signature checks. - Direct tests of virtual dispatch and every built-in argument mapping. - Compile-load-invoke tests for generated replicas. - Complete net11 and net481 source-generator test coverage. No package references, dependencies, or package-authoring project settings change. > [!NOTE] > This pull request description was generated with GitHub Copilot. Co-authored-by: Viviana Dueñas <50237907+ViveliDuCh@users.noreply.github.com> Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 524df8bb-0555-4425-b73f-bc8340d0dfc2
Summary
Adds the approved
ValidationAttribute.FormatMessageAPI so callers can supply externally localized composite-format strings while each validation attribute remains responsible for providing its placeholder arguments.Changes
ValidationAttribute.FormatMessage([StringSyntax("CompositeFormat")] string format, string name).FormatErrorMessageimplementation through the new method.CompareAttribute,FileExtensionsAttribute,LengthAttribute,MaxLengthAttribute,MinLengthAttribute,RangeAttribute,RegularExpressionAttribute, andStringLengthAttribute.CurrentCultureformatting.Existing
FormatErrorMessagebehavior 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.