Skip to content

Conversation

@oroztocil
Copy link
Member

@oroztocil oroztocil commented Aug 25, 2025

Currently, when you have a type that is validated only with the IValidatbleObject method (i.e. the type has no validation attributes or properties with validation attributes), then the validation source generator does not create the necessary code for that type. This leads to the validation rule being ignored during run-time.

This PR changes the logic in ValidationsGenerator.ExtractValidatableTypes so that such types get their validation code properly emitted.

Fixes #63394

@oroztocil oroztocil requested review from captainsafia and Copilot and removed request for Copilot August 25, 2025 14:43
@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 Aug 25, 2025
@oroztocil oroztocil added feature-validation Issues related to model validation in minimal and controller-based APIs area-blazor Includes: Blazor, Razor Components area-minimal Includes minimal APIs, endpoint filters, parameter binding, request delegate generator etc and removed needs-area-label Used by the dotnet-issue-labeler to label those issues which couldn't be triaged automatically labels Aug 25, 2025
Copilot AI review requested due to automatic review settings August 25, 2025 14:49
Copy link
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

This PR fixes a bug where types implementing IValidatableObject without any validation attributes were not having their validation code generated by the source generator. The fix ensures that such types are properly included in the validation code generation process.

Key changes:

  • Modified the type extraction logic to consider IValidatableObject interface implementation
  • Added a new helper method to check for IValidatableObject interface
  • Updated well-known types to include IValidatableObject

Reviewed Changes

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

File Description
ValidationsGenerator.TypesParser.cs Added logic to check for IValidatableObject interface and include it in type-level validation detection
WellKnownTypeData.cs Added IValidatableObject to the well-known types enum and names array
ValidationsGenerator.IValidatableObject.cs Added comprehensive test case to verify the fix works for both base and derived classes
ValidatableInfoResolver.g.verified.cs Generated test snapshot showing expected output for types with only IValidatableObject validation

@oroztocil oroztocil requested a review from a team August 25, 2025 14:50
@javiercn
Copy link
Member

/backport to release/10.0

@github-actions
Copy link
Contributor

Started backporting to release/10.0: https://github.com/dotnet/aspnetcore/actions/runs/17212498300

visitedTypes.Add(typeSymbol);

var hasValidationAttributes = HasValidationAttributes(typeSymbol, wellKnownTypes);
var hasTypeLevelValidation = HasValidationAttributes(typeSymbol, wellKnownTypes) || HasIValidatableObjectInterface(typeSymbol, wellKnownTypes);
Copy link
Member

Choose a reason for hiding this comment

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

nit: the name is clearer as hasValidationAttributes. hasTypeLevelValidation makes it look like its not considering properties.

Copy link
Member Author

@oroztocil oroztocil Aug 25, 2025

Choose a reason for hiding this comment

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

This is a result of a partial check that gets ORed in a larger disjunction at the end of the method with other checks (the other checks need to be done because they also collect some data as out params so the logic cannot reasonably short-circuit). Property attributes are handled in one of the other checks.

hasValidationAttributes referred to class attributes, hasTypeLevelValidation now means the type either has class attributes or implements IValidatableObject.

Copy link
Member

@javiercn javiercn left a comment

Choose a reason for hiding this comment

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

Change looks good, but I defer to @captainsafia for the final review.

visitedTypes.Add(typeSymbol);

var hasValidationAttributes = HasValidationAttributes(typeSymbol, wellKnownTypes);
var hasTypeLevelValidation = HasValidationAttributes(typeSymbol, wellKnownTypes) || HasIValidatableObjectInterface(typeSymbol, wellKnownTypes);
Copy link
Member

Choose a reason for hiding this comment

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

Consider using the ImplementsInterface method here to do the check.

Copy link
Member Author

Choose a reason for hiding this comment

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

Thanks, replaced

WebApplication app = builder. Build();
app.MapPost("/base", (BaseClass model) => Results.Ok(model));
app.MapPost("/derived", (DerivedClass model) => Results.Ok(model));
Copy link
Member

Choose a reason for hiding this comment

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

We should add a case that validates that a class with a property that only implements IValidatableObject also works. I don't anticipate that this will require any code changes since the recursion already handles that.

Copy link
Member Author

Choose a reason for hiding this comment

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

Agreed, added the test case

Copy link
Member

@captainsafia captainsafia left a comment

Choose a reason for hiding this comment

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

LGTM overall. I don't have any blocking comments but left a note inline about additional tests.

@oroztocil
Copy link
Member Author

/backport to release/10.0

@github-actions
Copy link
Contributor

Started backporting to release/10.0: https://github.com/dotnet/aspnetcore/actions/runs/17234547157


internal static bool HasIValidatableObjectInterface(ITypeSymbol typeSymbol, WellKnownTypes wellKnownTypes)
{
var validatableObjectSymbol = wellKnownTypes.Get(WellKnownTypeData.WellKnownType.System_ComponentModel_DataAnnotations_IValidatableObject);

Choose a reason for hiding this comment

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

nit: explicit type would have been nice for readability

using Microsoft.Extensions.Validation;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Routing;
using Microsoft.Extensions.DependencyInjection;

Choose a reason for hiding this comment

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

This is a lot of usings for a simple app.

Shouldn't the following be enough,

using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Routing;
using Microsoft.Extensions.DependencyInjection;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;

@oroztocil oroztocil merged commit 1c8a694 into main Aug 27, 2025
29 checks passed
@oroztocil oroztocil deleted the oroztocil/63394-fix-ivalidatableobject-info-emit branch August 27, 2025 09:36
@dotnet-policy-service dotnet-policy-service bot added this to the 11.0-preview1 milestone Aug 27, 2025
@oroztocil oroztocil modified the milestones: 11.0-preview1, 10.0-rc2 Aug 28, 2025
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 area-minimal Includes minimal APIs, endpoint filters, parameter binding, request delegate generator etc feature-validation Issues related to model validation in minimal and controller-based APIs

Projects

None yet

Development

Successfully merging this pull request may close these issues.

ASP.NET Core 10.0: Built-in Validation with IValidatableObject

5 participants