-
Notifications
You must be signed in to change notification settings - Fork 10.4k
Fix ValidatableTypeInfo to skip IValidatableObject validation when property validation fails #62623
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
Greetings human! You've submitted a PR that modifies code that is shared with https://github.com/dotnet/runtime . Please make sure you synchronize this code with the changes in that repo! |
Co-authored-by: captainsafia <[email protected]>
…operty validation fails Co-authored-by: captainsafia <[email protected]>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@copilot Looks good! One piece of feedback to address.
…internal and remove from PublicApi Co-authored-by: captainsafia <[email protected]>
@@ -586,6 +586,64 @@ public async Task Validate_IValidatableObject_WithZeroAndMultipleMemberNames_Beh | |||
}); | |||
} | |||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@copilot add a test like the following.
public class Address : IValidatableObject
{
[MinLength(5)]
public string Street { get; set; }
public bool WasValidateCalled { get; private set; }
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
WasValidateCalled = true;
yield return new ValidationResult("Address-level validation ran.");
}
}
[Fact]
public async Task DoesNotCallObjectValidation_WhenPropertyAttributeValidationFails()
{
// Arrange
var address = new Address { Street = "123" }; // Too short for MinLength(5)
var context = new ValidationContext(address);
var results = new List<ValidationResult>();
// Act
var isValid = Validator.TryValidateObject(address, context, results, validateAllProperties: true);
// Assert
Assert.Contains(results, r => r.ErrorMessage.Contains("minimum length of '5'"));
Assert.DoesNotContain(results, r => r.ErrorMessage == "Address-level validation ran.");
Assert.False(address.WasValidateCalled);
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added the test demonstrating the expected behavior using System.ComponentModel.DataAnnotations.Validator. The test verifies that IValidatableObject.Validate is not called when property validation fails, which matches the standard .NET validation behavior. (0934867)
…r behavior Co-authored-by: javiercn <[email protected]>
@@ -59,6 +59,16 @@ protected ValidatablePropertyInfo( | |||
|
|||
/// <inheritdoc /> | |||
public virtual async Task ValidateAsync(object? value, ValidateContext context, CancellationToken cancellationToken) | |||
{ | |||
await ValidatePropertyAttributesAsync(value, context, cancellationToken); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@copilot
Why are you ignoring the result here. The way the code is structured makes it seem as if you are running the object validation independent of whether the property validation failed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was ignoring the result to maintain the current behavior where complex object validation always runs regardless of property validation results. Complex object validation automatically handles null values and non-null objects should still be validated even if they fail property-level validation. I've clarified this intention with an explicit discard and comment explaining the rationale. (3e8c7fb)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I disagree
If any of the properties fails validation that itself might cause additional validation errors in the object independent of whether or not the property is null.
Compare your implementation to TryValidateObject in System.ComponentModel, the behavior should match
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You're absolutely right. I've updated the implementation to match System.ComponentModel.DataAnnotations.Validator behavior. Now complex object validation only runs if property validation succeeds, aligning with the standard .NET validation pattern where any property validation failure stops further validation. (e87c7fb)
… discard and comment Co-authored-by: javiercn <[email protected]>
…operty validation fails Co-authored-by: javiercn <[email protected]>
The current minimal API validation logic runs IValidatableObject validation even when property-level validation fails, which is inconsistent with the behavior of
System.ComponentModel.DataAnnotations.Validator
. This creates a breaking change for Blazor apps that opt into the new validation support.Problem
The original
System.ComponentModel.DataAnnotations.Validator
behavior stops validation if there are any property-level validation errors, as object-level validation may rely on properties already being valid. The new validation implementation was running both property and object-level validation regardless of property validation failures.Solution
This PR updates the
ValidatableTypeInfo
implementation to align with the originalSystem.ComponentModel.DataAnnotations
behavior:Changes Made
ValidatableTypeInfo.ValidateAsync
to separate property validation from object validationValidatePropertyAttributesAsync
andValidateComplexObjectsAsync
methods toValidatablePropertyInfo
Example
All tests pass, confirming the fix maintains backward compatibility while aligning with the expected validation behavior.
Fixes #62584.
💬 Share your feedback on Copilot coding agent for the chance to win a $200 gift card! Click here to start the survey.