Skip to content

Remove DataAnnotations' ValidationContext from MEV public API#67549

Open
Youssef1313 wants to merge 5 commits into
mainfrom
dev/ygerges/refactor-validation
Open

Remove DataAnnotations' ValidationContext from MEV public API#67549
Youssef1313 wants to merge 5 commits into
mainfrom
dev/ygerges/refactor-validation

Conversation

@Youssef1313

@Youssef1313 Youssef1313 commented Jul 1, 2026

Copy link
Copy Markdown
Member

Fixes #67033
Fixes #67004
Fixes #67550

@Youssef1313 Youssef1313 force-pushed the dev/ygerges/refactor-validation branch 2 times, most recently from 691e402 to f1b2170 Compare July 1, 2026 20:30
@Youssef1313 Youssef1313 force-pushed the dev/ygerges/refactor-validation branch 6 times, most recently from c4802fe to 20c9328 Compare July 2, 2026 11:19
@Youssef1313 Youssef1313 force-pushed the dev/ygerges/refactor-validation branch 3 times, most recently from 5e84a5c to 48a92bf Compare July 4, 2026 05:02
@Youssef1313 Youssef1313 marked this pull request as ready for review July 9, 2026 17:42
Copilot AI review requested due to automatic review settings July 9, 2026 17:42
@Youssef1313 Youssef1313 requested a review from a team as a code owner July 9, 2026 17:42

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

This PR removes System.ComponentModel.DataAnnotations.ValidationContext from the Microsoft.Extensions.Validation public surface by replacing it with a ServiceProvider on ValidateContext, and refactors the validation pipeline to construct ValidationContext internally where needed. It also updates Minimal APIs, Blazor Forms integration, tests, and benchmarks to use the new API shape.

Changes:

  • Replace ValidateContext.ValidationContext with ValidateContext.ServiceProvider and make ValidationOptions init-only.
  • Refactor attribute validation to pass ValidationContext/display name explicitly through the pipeline (properties, parameters, and type-level validation).
  • Update integrations (Minimal API endpoint filter, Blazor EditContext DataAnnotations) plus tests/benchmarks for the new API.

Reviewed changes

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

Show a summary per file
File Description
src/Validation/src/ValidateContext.cs Replaces public ValidationContext with ServiceProvider; refactors attribute validation plumbing.
src/Validation/src/ValidateContextMutableState.cs Removes mutable state that previously mirrored ValidationContext display/member metadata.
src/Validation/src/IValidationErrorReporter.cs Updates error reporting contract to carry display name and member name explicitly.
src/Validation/src/ValidatableTypeInfo.cs Refactors type-level validation to work without storing ValidationContext on ValidateContext.
src/Validation/src/ValidatablePropertyInfo.cs Creates per-property ValidationContext from the containing object and passes display name explicitly.
src/Validation/src/ValidatableParameterInfo.cs Creates per-parameter ValidationContext (now derived from value + ServiceProvider) and passes display name explicitly.
src/Validation/src/PublicAPI.Unshipped.txt Records public API removals/additions (ValidationContext removal, ServiceProvider + init-only ValidationOptions).
src/Http/Routing/src/ValidationEndpointFilterFactory.cs Updates Minimal API validation filter to use ServiceProvider instead of creating/storing ValidationContext.
src/Http/Http/perf/Microbenchmarks/ValidatableTypesBenchmark.cs Updates benchmark setup to populate ServiceProvider.
src/Components/Forms/src/EditContextDataAnnotationsExtensions.cs Updates Blazor Forms integration to populate ServiceProvider instead of ValidationContext.
src/Validation/test/Microsoft.Extensions.Validation.Tests/ValidationLocalizationIntegrationTests.cs Updates tests to use ServiceProvider API.
src/Validation/test/Microsoft.Extensions.Validation.Tests/ValidatableTypeInfoTests.cs Updates tests to use ServiceProvider API.
src/Validation/test/Microsoft.Extensions.Validation.Tests/ValidatableParameterInfoTests.cs Updates tests to use ServiceProvider API.
src/Validation/test/Microsoft.Extensions.Validation.Tests/RuntimeValidatableParameterInfoResolverTests.cs Updates tests to use ServiceProvider API.
src/Validation/test/Microsoft.Extensions.Validation.Tests/DisplayNameInfoTests.cs Updates tests to use ServiceProvider API.
src/Validation/test/Microsoft.Extensions.Validation.Tests/AsyncValidationTests.cs Updates async validation tests to use ServiceProvider API.
src/Validation/Localization/test/ValidationLocalizationPipelineTests.cs Updates localization pipeline tests to use ServiceProvider API.
src/Validation/test/Microsoft.Extensions.Validation.GeneratorTests/ValidationsGenerator.ValidatableType.cs Updates generator tests to use ServiceProvider API.
src/Validation/test/Microsoft.Extensions.Validation.GeneratorTests/ValidationsGenerator.SkipValidation.cs Updates generator tests to use ServiceProvider API.
src/Validation/test/Microsoft.Extensions.Validation.GeneratorTests/ValidationsGenerator.ClassAttributes.cs Updates generator tests to use ServiceProvider API.

Comment thread src/Validation/src/ValidateContext.cs
return attribute.GetValidationResult(value, validationContext);
}

if (attribute.IsValid(value))

@halter73 halter73 Jul 9, 2026

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.

I think this call ValidationAttribute.IsValid(object? value, ValidationContext validationContext) with a null ValidationContext despite the fact that the parameter is marked non-nullable. This means the attribute has no way to access the IServiceProvider from the ValidationContext iff the value is null.

https://github.com/dotnet/runtime/blob/a991d279bd4e8f0aadf0a685f60d6bcafaebaca3/src/libraries/System.ComponentModel.Annotations/src/System/ComponentModel/DataAnnotations/ValidationAttribute.cs#L385

I know it's gross to pass in new object() to represent null, but I think for the attributes in particular, that's probably what we should do. We could request an API change to ValidationContext in the runtime to support null ObjectInstances, but I doubt there will be much of any appetite assuming all the code that already reads it assuming it cannot be null.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Yup, it's passing null.

This code will be reachable only when we have a "null" value to validate, for which we previously skipped the validation completely.

I didn't like much using new object() to represent null. It feels like a workaround to me and we are constructing a malformed ValidationContext, but happy to re-consider if you think that is a better approach. In this case, it will be defeating one of the reasons for considering the API change, but I think the API shape to remove ValidationContext from ValidateContext is still a good thing to do regardless :)

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Note: I expect most realistic use cases to be able to decide the validation of a "null" without needing anything from ValidationContext.

I'm trying to respect the design of ValidationContext as much as possible.

@Youssef1313 Youssef1313 requested a review from halter73 July 9, 2026 19:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

4 participants