惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

C
Check Point Blog
GbyAI
GbyAI
酷 壳 – CoolShell
酷 壳 – CoolShell
博客园 - 叶小钗
U
Unit 42
Engineering at Meta
Engineering at Meta
aimingoo的专栏
aimingoo的专栏
Y
Y Combinator Blog
Google DeepMind News
Google DeepMind News
Vercel News
Vercel News
美团技术团队
雷峰网
雷峰网
Recent Announcements
Recent Announcements
有赞技术团队
有赞技术团队
D
DataBreaches.Net
H
Hackread – Cybersecurity News, Data Breaches, AI and More
Apple Machine Learning Research
Apple Machine Learning Research
J
Java Code Geeks
罗磊的独立博客
MyScale Blog
MyScale Blog
博客园_首页
IT之家
IT之家
F
Fortinet All Blogs
博客园 - Franky

DEV Community

Authentication Security Deep Dive: From Brute Force to Salted Hashing (With Java Examples) Why AI Systems Don’t Fail — They Drift Spilling beans for how i learn for exam😁"Reinforcement Learning Cheat Sheet" I Replaced Chrome with Safari for AI Browser Automation. Here's What Broke (and What Finally Worked) How Python Borrows Other People's Work The $40 Architecture: Processing 1 Billion API Requests with 99.99% Uptime Vibe Coding: A Workflow Guide (From Zero to SaaS) Most webhook security guides protect the wrong side. The scary part is delivery. Headless CMS for TanStack Start: Build a Blog with Cosmic EU Age Verification App "Hacked in 2 Minutes" — What Actually Happened Comfy Cloud’s delete function does not actually remove files Running AI Models on GPU Cloud Servers: A Beginner Guide Event-driven media intelligence with AWS Step Functions and Bedrock I scored 500 AI prompts across 8 quality dimensions — here's what broke How to Call Google Gemini API from Next.js (Free Tier, No Backend Needed) The Portal Protocol: Reclaiming Human Connection in the Age of AI How to Fix Your Team's Scattered Knowledge Problem With a Self-Hosted Forum Intro to tc Cloud Functors: A Graph-First Mental Model for the Modern Cloud Designing Multi-Tenant Backends With Both Ownership and Team Access I Built a Neumorphic CSS Library with 77+ Components — Here's What I Learned PostgreSQL Performance Optimization: Why Connection Pooling Is Critical at Scale Cómo construí un SaaS multi-rubro para gestionar expensas en Argentina con FastAPI + Vue 3 🚀 I Built an Ethical Hacking Scanner Tool – Open Source Project I Replaced /usage and /context in Claude Code With a Single Statusline A Pythonic Way to Handle Emails (IMAP/SMTP) with Auto-Discovery and AI-Ready Design I Collected 8.9 Million Polymarket Price Points — Here's What I Found About How Markets Really Move EcoTrack AI — Carbon Footprint Tracker & Dashboard Everyone's Using AI. No One Agrees How. 5 self-hosted ebook managers worth trying in 2026 Building Your First AI Agent with LangChain: From Chatbot to Autonomous Assistant
Blazor SSR Gets Client-Side Validation in .NET 11 Preview...
Vikrant Bagal · 2026-06-13 · via DEV Community

Blazor SSR Gets Client-Side Validation in .NET 11 Preview 5

If you've built Blazor Server-Side Rendering (SSR) forms, you know the pain: a user fills out a form, hits submit, the form posts to the server, the server runs validation, and only then does the user see the "This field is required" message next to the empty email field.

That round-trip latency adds up. It breaks the immediacy users expect from modern web apps.

.NET 11 Preview 5 fixes this. Blazor SSR forms now get instant, in-browser validation feedback — no server required. The server renders your validation rules as metadata, and Blazor's JavaScript enforces them client-side. Same DataAnnotationsValidator component you already use. Zero code changes needed.

Let's break down how it works.


Before .NET 11: The SSR Validation Gap

In .NET 8 and 9, Blazor SSR rendered HTML on the server and sent it down. Validation only ran server-side — on form submission. If a field was invalid, the whole form posted to the server, came back with validation messages, and re-rendered.

Interactive Blazor modes (Server, WebAssembly, Auto) had instant client-side validation because an active SignalR circuit or WASM runtime ran the validation logic locally. But SSR mode — the simplest, most performant option — was left out.

The result? Developers who chose SSR Blazor for its simplicity had to choose between:

  • Accepting the laggy validation UX
  • Adding a second JavaScript validation library (and maintaining two validation rulesets)
  • Re-architecting to use an interactive render mode

None of these are great options.


What Changed in .NET 11 Preview 5

The .NET team shipped two PRs (#66441 and #66420) that bring unobtrusive client-side validation to Blazor SSR forms.

The key insight: The .NET model stays the single source of truth. On form render, the server serializes your DataAnnotations validation rules into HTML metadata attributes. Blazor's JavaScript reads those attributes and applies them client-side — the same approach ASP.NET MVC has used for years with jquery.validate.unobtrusive.

How It Works

  1. Server renders metadata — When an <EditForm> with <DataAnnotationsValidator /> renders in SSR mode, the server emits data-val-* attributes for each field's validation rules (required, string length, regex, compare, email, etc.)

  2. Client enforces — Blazor's built-in JavaScript intercepts form submission and validates fields against the metadata. If a field fails, it shows the ValidationMessage immediately — no POST needed.

  3. Server re-validates on submit — When the form does post to the server (after passing client-side validation), the server validates again as a safety net. Defense in depth.

What You Need

Nothing. The feature is enabled by default for all SSR forms that include the <DataAnnotationsValidator /> component. Both enhanced forms (Enhance) and non-enhanced forms work.


Code Example: Registration Form (SSR)

Here's a standard Blazor SSR registration form with DataAnnotationsValidator. This exact code works with or without client-side validation in .NET 11 Preview 5:

@page "/register"
@using System.ComponentModel.DataAnnotations

<EditForm Model="Model" Enhance FormName="registration" OnValidSubmit="HandleValidSubmit">
    <DataAnnotationsValidator />

    <div>
        <label for="Email">Email</label>
        <InputText @bind-Value="Model!.Email" id="Email" />
        <ValidationMessage For="() => Model!.Email" />
    </div>

    <div>
        <label for="Password">Password</label>
        <InputText @bind-Value="Model!.Password" id="Password" type="password" />
        <ValidationMessage For="() => Model!.Password" />
    </div>

    <div>
        <label for="ConfirmPassword">Confirm Password</label>
        <InputText @bind-Value="Model!.ConfirmPassword" id="ConfirmPassword" type="password" />
        <ValidationMessage For="() => Model!.ConfirmPassword" />
    </div>

    <button type="submit">Register</button>
</EditForm>

@code {
    [SupplyParameterFromForm]
    private RegistrationModel? Model { get; set; }

    protected override void OnInitialized() => Model ??= new();

    private void HandleValidSubmit()
    {
        // Form is valid — process registration
    }
}

public class RegistrationModel
{
    [Required]
    [EmailAddress]
    public string? Email { get; set; }

    [Required]
    [StringLength(100, MinimumLength = 8)]
    public string? Password { get; set; }

    [Required]
    [Compare("Password")]
    [Display(Name = "Confirm Password")]
    public string? ConfirmPassword { get; set; }
}

In .NET 11 Preview 5, when this form renders, the server emits something like:

<input type="email" id="Email"
       data-val="true"
       data-val-required="The Email field is required."
       data-val-email="The Email field is not a valid email address." />

<span data-valmsg-for="Email" data-valmsg-replace="true"></span>

<input type="password" id="Password"
       data-val="true"
       data-val-required="The Password field is required."
       data-val-length="The Password must be at least 8 characters."
       data-val-length-max="100"
       data-val-length-min="8" />

The JS intercepts the submit, runs these rules on field blur and on submit, and the validation messages appear instantly.


What About Enhanced Forms?

Blazor SSR enhanced forms (those with the Enhance attribute on <EditForm>) use form enhancement — the form posts via fetch and patches the DOM with the response. In previous releases, the validation experience was:

  1. User fills form
  2. User clicks submit
  3. Form posts via fetch
  4. Server validates
  5. Response patches the DOM with validation errors

With .NET 11 Preview 5, enhanced forms also get client-side validation as a first pass — the form validates locally before the fetch even fires. This means:

  • Before .NET 11 P5: Submit → fetch (latency) → validation feedback
  • After .NET 11 P5: Instant validation → submit → fetch → server re-validation

Non-enhanced forms work identically — just without the fetch patching.


Bonus: Async Form Validation

Preview 5 also ships the building blocks for async validation in Blazor forms. You can now register per-field async validation tasks via EditContext.AddValidationTask:

@implements IDisposable

<EditForm EditContext="editContext" OnSubmit="HandleSubmit">
    <InputText @bind-Value="model.Username" />
    @if (editContext.IsValidationPending(() => model.Username))
    {
        <span>Checking availability...</span>
    }
    <ValidationMessage For="() => model.Username" />
    <button type="submit">Register</button>
</EditForm>

@code {
    [Inject] public UserService Users { get; set; } = default!;

    private readonly RegistrationModel model = new();
    private EditContext editContext = default!;
    private ValidationMessageStore messages = default!;

    protected override void OnInitialized()
    {
        editContext = new EditContext(model);
        messages = new ValidationMessageStore(editContext);

        editContext.OnFieldChanged += (_, e) =>
        {
            if (e.FieldIdentifier.FieldName == nameof(model.Username))
            {
                var cts = new CancellationTokenSource();
                editContext.AddValidationTask(e.FieldIdentifier,
                    CheckAsync(e.FieldIdentifier, model.Username, cts.Token), cts);
            }
        };
    }

    private async Task CheckAsync(FieldIdentifier field, string value, CancellationToken ct)
    {
        messages.Clear(field);
        if (await Users.IsUsernameTakenAsync(value, ct))
        {
            messages.Add(field, "Username is taken.");
        }
        editContext.NotifyValidationStateChanged();
    }

    private async Task HandleSubmit() => await editContext.ValidateAsync();

    public void Dispose() => messages?.Clear();
}

The framework tracks pending tasks, cancels superseded ones (when the user types again), and exposes IsValidationPending(field) and IsValidationFaulted(field) for the UI to show spinner states.

Note: The full built-in async validation experience will land in a later preview once the new async DataAnnotations APIs ship. But the foundation is here now.


Bonus: Localized Validation Errors

Preview 5 also adds first-class localization support for validation messages in Blazor forms and Minimal API endpoints:

builder.Services.AddValidation()
    .AddValidationLocalization<ValidationMessages>();

This resolves localized strings from RESX files (or a custom IStringLocalizerFactory) using the ErrorMessage values as keys. You can also configure a programmatic strategy:

builder.Services.AddValidation()
    .AddValidationLocalization<ValidationMessages>(options =>
    {
        options.ErrorMessageKeyProvider = ctx =>
            ctx.Attribute.ErrorMessage ?? $"{ctx.Attribute.GetType().Name}_Error";
    });

Now your [Required] attribute automatically picks up the right language without changing a line of Razor code.


Migration Guide

If you have existing Blazor SSR forms in a .NET 8, 9, or 10 project:

  1. Upgrade the SDK to .NET 11 Preview 5+ (dotnet --version should show 11.0.100-preview.5.*)
  2. Set LangVersion to preview in your .csproj:
<PropertyGroup>
    <TargetFramework>net11.0</TargetFramework>
    <LangVersion>preview</LangVersion>
</PropertyGroup>

  1. That's it. If you use <DataAnnotationsValidator /> in your SSR forms, client-side validation is now active. Test by tabbing off a required field without filling it — you should see the validation message instantly.

Existing Enhanced Forms

Enhanced forms (Enhance) get the same client-side validation automatically. No changes needed.


What This Means for Blazor Developers

This is a meaningful step forward for Blazor SSR. The biggest critique of SSR forms was the validation UX gap compared to interactive modes. With client-side validation, SSR Blazor forms now feel as responsive as traditional JavaScript frameworks — without requiring JavaScript interop, a separate validation library, or giving up the simplicity of static server rendering.

Who benefits most:

  • SSR-first Blazor apps — Public-facing sites, content-heavy apps, and pages where interactivity overhead isn't justified
  • Progressively enhanced forms — Forms that work without JavaScript but feel instant with it
  • Teams migrating from MVC/Razor Pages — The unobtrusive validation pattern will feel familiar
  • Multi-lingual apps — Localized validation messages are now a built-in concern, not an afterthought

Summary

Feature .NET 10 .NET 11 Preview 5
SSR client-side validation ❌ Server-only ✅ Instant in-browser
Async form validation ✅ Building blocks shipped
Localized validation Partial ✅ First-class via AddValidationLocalization
QuickGrid SSR ✅ Sort/page without interactivity
SupplyParameterFromSession ✅ Session-backed component state
Dev setup DevServer ✅ New Gateway dev server

.NET 11 Preview 5 turns Blazor SSR into a viable option for form-heavy applications by closing the validation UX gap. The .NET model stays the source of truth, your existing DataAnnotationsValidator components work unchanged, and the result is instant visual feedback for your users.


Have you tried Blazor SSR in production? Does client-side validation change the calculus for your next project? Drop a comment — I'd love to hear your take.

This post was written with .NET 11 Preview 5. Features may change before the final release.