Skip to content

Server validation with a validator component upgrade#37113

Open
guardrex wants to merge 12 commits into
mainfrom
guardrex/server-validation-example-upgrade
Open

Server validation with a validator component upgrade#37113
guardrex wants to merge 12 commits into
mainfrom
guardrex/server-validation-example-upgrade

Conversation

@guardrex

@guardrex guardrex commented May 6, 2026

Copy link
Copy Markdown
Collaborator

Fixes #36051

Ondřej ... Per your suggestion in #35972, the general idea is to replace the MVC controller with a Minimal API validation, including the unified validation experience.

To simplify the section, the content is versioned into >=10.0, >=8.0/<10.0, and <8.0 blocks. I think we only need to focus on the new guidance in the >=10.0 coverage at the top of the section. I haven't received any complaints (or death threats 💀😨😆) from our readers on our MVC controller-based guidance.


Internal previews

📄 File 🔗 Preview link
aspnetcore/blazor/forms/validation.md aspnetcore/blazor/forms/validation

@guardrex guardrex self-assigned this May 6, 2026
@guardrex guardrex marked this pull request as ready for review May 7, 2026 13:12
@guardrex guardrex requested a review from Copilot May 7, 2026 13:12

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

Updates the “Server validation with a validator component” guidance in validation.md to introduce a .NET 10+ flow that uses a Minimal API-based validation endpoint and splits the content into versioned blocks.

Changes:

  • Adds a new >= aspnetcore-10.0 section demonstrating server validation via a Minimal API and a client/server validator abstraction.
  • Reorganizes the existing guidance into >=8.0/<10.0 and <8.0 moniker blocks.
  • Introduces new sample code and updated narrative around client + server validation responsibilities.

Comment thread aspnetcore/blazor/forms/validation.md Outdated
Comment thread aspnetcore/blazor/forms/validation.md Outdated
Comment thread aspnetcore/blazor/forms/validation.md Outdated
Comment thread aspnetcore/blazor/forms/validation.md Outdated
Comment thread aspnetcore/blazor/forms/validation.md Outdated
Comment thread aspnetcore/blazor/forms/validation.md Outdated
Comment thread aspnetcore/blazor/forms/validation.md Outdated
@guardrex guardrex requested a review from oroztocil May 8, 2026 18:41
@oroztocil

Copy link
Copy Markdown
Member

Hi @guardrex, sorry for not getting to this sooner. I did read through the whole PR but a first general comment is that by using a validated Minimal API endpoint (instead of a MVC controller) I meant using the built-in validation feature we added in .NET 10 that you enable simply by calling builder.Services.AddValidation(). A built-in filter in the request pipeline then validates all the DataAnnotations attributes on the request parameters automatically (including nested properties of model classes).

That should significantly simplify the examples because you don't need to build and register any custom validators (the IFormValidator types in your example), you don't need to create ProblemDetails manually, etc.

@guardrex

This comment was marked as resolved.

@guardrex

This comment was marked as outdated.

@guardrex

This comment was marked as outdated.

@guardrex

guardrex commented May 20, 2026

Copy link
Copy Markdown
Collaborator Author

@oroztocil ... I confirmed that the server-side built-in validation (AddValidation) is working with the model.

When I removed the "Accommodation" field range (1-100000) DA validation from the BWA's StarshipModel class and placed a StarshipModel class in the backend Minimal API app with an "Accommodation" field range of 200000-1000000, it sent back a 400 with a problem details that was successfully used by the custom validation component to set the error on the form correctly ...

image

If I then correct that to get the built-in validation to pass but break the special check performed in code, it then also throws the 400 with the problem details showing the expected form result ...

image

AFAICT, what's on the PR is fine with perhaps a few more code improvements.

I also perform a quick test to confirm that a custom validation attribute in the Minimal API works well with the built-in validation. I'm sure it will work fine. Then, I'll add a quick remark (or a short section) to this PR on it.

Stand-by a bit longer ... making progress here! 🎉 ... and we might have some decent draft coverage to look at soon.

@guardrex

Copy link
Copy Markdown
Collaborator Author

It works! 🎉

In the Minimal API ...

using System.ComponentModel.DataAnnotations;

namespace MinimalApiJwt;

public class CustomValidator : ValidationAttribute
{
    protected override ValidationResult IsValid(object? value,
        ValidationContext validationContext)
    {
        if (value is not null)
        {
            var intValue = (int)value;

            if (intValue > 500000)
            {
                return ValidationResult.Success!;
            }
        }

        return new ValidationResult("Accommodation must be greater than 500000.",
            [validationContext.MemberName!]);
    }
}

In the StarshipModel class in the Minimal API ...

[CustomValidator]
public int MaximumAccommodation { get; set; }

Result when an invalid figure is provided ...

image

Correcting the figure, the validation passes ...

image

@guardrex

Copy link
Copy Markdown
Collaborator Author

@oroztocil ... Made a final round of updates to the draft content. I added some remarks (not a section) on custom validation attributes. It's ready for review now.

@guardrex guardrex requested a review from Copilot May 20, 2026 13:40

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 1 out of 1 changed files in this pull request and generated 5 comments.

Comments suppressed due to low confidence (1)

aspnetcore/blazor/forms/validation.md:680

  • This snippet includes using Microsoft.AspNetCore.Mvc; but doesn't use MVC types. In a .Client project, that using can be misleading and may not compile unless MVC packages are referenced. Remove the unused using.
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Forms;
using Microsoft.AspNetCore.Mvc;

namespace BlazorSample.Client;

Comment thread aspnetcore/blazor/forms/validation.md
Comment thread aspnetcore/blazor/forms/validation.md Outdated
Comment thread aspnetcore/blazor/forms/validation.md
Comment thread aspnetcore/blazor/forms/validation.md Outdated
Comment thread aspnetcore/blazor/forms/validation.md Outdated
Comment thread aspnetcore/blazor/forms/validation.md Outdated

Add an interface for a form validation service to the `.Client` project in the `Starship` folder. The interface is used to register a service for server validation on the server or client validation on the client.

`Starship/IFormValidator.cs`:

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.

Is it necessary to have the IFormValidator and the two implementations? If nothing else, the naming *Validator may confuse people who are accustomed to the DataAnnotationValidator (which is a component they insert into EditForm).

}
else

var request = new HttpRequestMessage(HttpMethod.Post,

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.

Why is the Server project delegating to a Minimal API endpoint if it can invoke the custom validation code directly? We could get rid of all the code involvingc IHttpContextAccessor, token passing, JSON de/seralization, and so on.

Comment thread aspnetcore/blazor/forms/validation.md Outdated
builder.Services.AddValidation();
```

Built-in validation automatically intercepts the endpoint request and validates the types that the endpoint receives. If the model fails validation, the framework returns a *400 - Bad Request* response with error details without executing the endpoint's code.

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.

Probably better to not mix the standard validation pattern with AddValidation and DataAnnotations validation attributes with the custom validation. Or if the intention is exactly to show how the custom validation can be added on top of the built-in one, then call this out explicitly somewhere here.


namespace BlazorSample.Client;

public class CustomValidation : ComponentBase

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.

Is it necessary to introduce the ClientValidation class that wraps work with the message store?

Comment thread aspnetcore/blazor/forms/validation.md Outdated

:::moniker-end

## Server validation with a validator component

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.

This example still seems overly complex. I appreciate the work that went into this but I am a big fan of docs that are minimal in showing only what is specific for the scenario being taught and omitting custom infrastructure and ceremonies.

First, can we find a different name for this section? I know there are precedents in the docs but I would move away from calling this "server validation". Maybe "remote validation"? The pattern here is basically what the MVC's Remote validation attribute did, only with more manual plumbing. Also, where is the validator component mentioned in the title? The ClientValidation class is just a wrapper for the message store.

Second, can we reorder the sections in the long Blazor forma validation article so that the docs flow from the most basic/standard/default scenarios to the more advanced/custom ones? For typical Blazor apps the order of complexity is roughly:

  1. Built-in validation rules using validation attributes and a DataAnnotationsValidator inside EditForm.
  2. Custom validation rules using custom validation attributes or IValidatableObject and a DataAnnotationsValidator inside EditForm.
  3. Information about AddValidation.
  4. Custom validation logic using the API of EditForm and EditContext.
  5. Only then something like this.

Thinking about it more, it might help us to break up this long article into one that cover 1-3 and another covering 5-6.

@guardrex

guardrex commented Jun 10, 2026

Copy link
Copy Markdown
Collaborator Author

cc: @danroth27 ... You might want to weigh in on this one. This is the section that @oroztocil and I are discussing for updates ...

Server validation with a validator component

What I have on this PR works 🎉, but the whole section might have outlived your desire to maintain it, falling into the "an advanced scenario for devs to work out on their own" bucket. 😄

BTW @oroztocil ... We're still waiting on getting the P5 PRs merged. Wade and I are on the case, and we'll get the P5 content live ASAP 🏃‍♂️.

I opened Improve section order and possibly split the article (dotnet/AspNetCore.Docs #37249). [BTW ... I'm going to be OOF for two weeks at the end of this month. If I'm invited back for FY27, I'll be back in early July. If not, this might fall to the docs folks to take over depending on how much work needs to be done here.]

WRT this section ...

I would move away from calling this "server validation". Maybe "remote validation"?

Yes ... I'll update the section heading. 👍

If nothing else, the naming *Validator may confuse people who are accustomed to the DataAnnotationValidator

Ok ... easy fix. 👍

Probably better to not mix the standard validation pattern with AddValidation and DataAnnotations validation attributes with the custom validation. Or if the intention is exactly to show how the custom validation can be added on top of the built-in one, then call this out explicitly somewhere here.

I think calling it out makes sense. The dev can decide to drop built-in validation if they're only looking to implement custom remote validation. I'm glad to see both working well together! It's pretty sweet IMO!

Why is the Server project delegating to a Minimal API endpoint if it can invoke the custom validation code directly?

Under this paradigm, the Minimal API is part of the use case. There would be several user-facing apps ... BWAs and perhaps other types of apps ... all hitting this other web API app/project for their centralized validation. Also, this is probably the most complicated scenario with the BWA adopting Interactive Auto rendering 😵😄, given that the BWA requires the two-service pattern for server/client rendering.

If a dev is only adopting SSR or CSR across their apps, this is an example that they can deconstruct down to a simpler remote validation scenario without the Interactive Auto rendering complexity.

This example still seems overly complex. I appreciate the work that went into this but I am a big fan of docs that are minimal in showing only what is specific for the scenario being taught and omitting custom infrastructure and ceremonies.

Yes, but it seems like a lot of new-to-.NET/new-to-Blazor/new-to-programming devs are going to be significantly challenged trying to do this on their own.

Of course, you could let me know that you feel this whole section's approach isn't welcome any longer for any of several reasons. Do you want to consider dropping the entire section? I leave it up to you and @danroth27 to let me know. 👂 I'll try to get it resolved either way before my OOF period starts on Tuesday.

@guardrex

guardrex commented Jun 12, 2026

Copy link
Copy Markdown
Collaborator Author

@oroztocil ... Updates on the last commit ...

  • Changed the following naming ...
    • IFormValidator to IFormValidation.
    • ClientFormValidator to ClientFormValidation
    • ServerFormValidator to ServerFormValidation
  • Refactored "server validation" into "remote validation" language throughout the section across versions, including in the section heading (Server validation with a validator component 👉 Remote validation with a validator component).

The overall paradigm is unchanged ... multiple BWAs and other apps hitting a Minimal API for validation. The Minimal API uses built-in and custom validation. The built-in validation aspect is called out both in the section's lead-in remarks and by an added remark near the AddValidation call explaining that it can be dropped (don't call AddValidation) if the dev only wants custom validation. The BWA goes with Interactive Auto because it's the most complicated case, and I think devs can deconstruct it if they're adopting non-Auto render modes.

Still ready to 💀 the entire section if you and @danroth27 prefer to label this an advanced case for devs to work out on their own. Otherwise tho, please check my 🦖 RexHacks!™ 🦖 for poor coding 🙈 ... but ... what's here seems to at least work 🎉.

Let's take up reordering the sections and probably breaking the article into two articles on the other issue that I opened in July if I'm still here 🤞🍀.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Server validation with a validator component upgrade

3 participants