From 31e70d03d6d055d1775439794535e549e312f64b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Rozto=C4=8Dil?= Date: Wed, 23 Sep 2026 13:03:25 +0200 Subject: [PATCH 1/3] Add minor hints, improve phrasing --- aspnetcore/blazor/forms/binding.md | 4 +++- aspnetcore/blazor/forms/validation.md | 20 ++++++++++++++++++-- 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/aspnetcore/blazor/forms/binding.md b/aspnetcore/blazor/forms/binding.md index 3c0bab64f5c2..c85da982c459 100644 --- a/aspnetcore/blazor/forms/binding.md +++ b/aspnetcore/blazor/forms/binding.md @@ -5,7 +5,7 @@ author: guardrex description: Learn how to use binding in Blazor forms. monikerRange: '>= aspnetcore-3.1' ms.author: wpickett -ms.date: 09/22/2026 +ms.date: 09/23/2026 uid: blazor/forms/binding --- # ASP.NET Core Blazor forms binding @@ -58,6 +58,8 @@ Assignment to parameter of `EditForm`, the form creates a new `EditContext`. The new context starts with no modified fields or validation messages. When an `EditContext` is supplied explicitly, create and assign a new context to reset the state. + ## Context binding Assignment to : diff --git a/aspnetcore/blazor/forms/validation.md b/aspnetcore/blazor/forms/validation.md index 0b41751841fe..39a789fd4c6c 100644 --- a/aspnetcore/blazor/forms/validation.md +++ b/aspnetcore/blazor/forms/validation.md @@ -5,7 +5,7 @@ author: guardrex description: Learn how to use validation in Blazor forms. monikerRange: '>= aspnetcore-3.1' ms.author: wpickett -ms.date: 09/22/2026 +ms.date: 09/23/2026 uid: blazor/forms/validation --- # ASP.NET Core Blazor forms validation @@ -246,7 +246,7 @@ Custom attributes can resolve registered services through . Don't assign both `Model` and `EditContext` to the same form. +`EditForm` creates an `EditContext` automatically when its `Model` parameter is assigned. To use validation APIs directly, create the context yourself and assign it to the parameter of `EditForm`. Don't assign both `Model` and `EditContext` to the same form. Custom validation commonly uses: @@ -360,6 +360,8 @@ Use to displa ``` +The `For` expression identifies the field by its model instance and property. Blazor represents this identity with a , so properties with the same name on different model instances are treated as different fields. Using an expression instead of a string also allows refactoring tools to update the property reference. + Use to display messages for the form: ```razor @@ -474,6 +476,20 @@ editContext.SetFieldCssClassProvider( For custom input markup, call to obtain the class selected by the current provider. +When an `EditForm` is assigned a model, its child content receives the generated `EditContext`. Capture the context through the `Context` parameter and call `FieldCssClass` to apply the field's classes to surrounding markup: + +```razor + + + +
+ + +
+
+``` + :::moniker-end From a17ddc3e27e13ae7cbf0ac973889773a64dc3e0e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Rozto=C4=8Dil?= Date: Wed, 23 Sep 2026 16:14:23 +0200 Subject: [PATCH 2/3] Add AsyncValidationAttribute example, add form reset guidance --- aspnetcore/blazor/forms/binding.md | 2 +- aspnetcore/fundamentals/validation.md | 49 +++++++++++++++++++++++++++ 2 files changed, 50 insertions(+), 1 deletion(-) diff --git a/aspnetcore/blazor/forms/binding.md b/aspnetcore/blazor/forms/binding.md index c85da982c459..4c5c30d64ada 100644 --- a/aspnetcore/blazor/forms/binding.md +++ b/aspnetcore/blazor/forms/binding.md @@ -58,7 +58,7 @@ Assignment to parameter of `EditForm`, the form creates a new `EditContext`. The new context starts with no modified fields or validation messages. When an `EditContext` is supplied explicitly, create and assign a new context to reset the state. +When a different object instance is assigned to the parameter of `EditForm`, the form creates a new `EditContext`. The new context starts with no modified fields or validation messages. ## Context binding diff --git a/aspnetcore/fundamentals/validation.md b/aspnetcore/fundamentals/validation.md index fc6082ed5fcd..40ce051d94a9 100644 --- a/aspnetcore/fundamentals/validation.md +++ b/aspnetcore/fundamentals/validation.md @@ -270,6 +270,55 @@ Blazor form validation calls the asynchronous path for per-field validation and If your implementation can't support the synchronous path, throw . +The following example performs property-level asynchronous validation with a custom `AsyncValidationAttribute`. The attribute uses a hypothetical `IUserService` to check whether an email address is already registered. Empty values are left to , and the cancellation token is passed to the asynchronous operation: + +```csharp +using System.ComponentModel.DataAnnotations; +using Microsoft.Extensions.DependencyInjection; + +public sealed class UniqueEmailAttribute : AsyncValidationAttribute +{ + public UniqueEmailAttribute() + { + ErrorMessage = "Email is already registered."; + } + + protected override async Task IsValidAsync( + object? value, + ValidationContext validationContext, + CancellationToken cancellationToken) + { + if (value is not string email || string.IsNullOrWhiteSpace(email)) + { + return ValidationResult.Success; + } + + var userService = + validationContext.GetRequiredService(); + + return await userService.IsEmailExistsAsync( + email, cancellationToken) + ? new ValidationResult( + FormatErrorMessage(validationContext.DisplayName), + [validationContext.MemberName!]) + : ValidationResult.Success; + } + + protected override ValidationResult? IsValid( + object? value, ValidationContext validationContext) + { + throw new InvalidOperationException( + "Synchronous validation isn't supported."); + } +} + +public class RegistrationModel +{ + [Required, EmailAddress, UniqueEmail] + public string Email { get; set; } = string.Empty; +} +``` + The following example shows object-level asynchronous validation with `IAsyncValidatableObject`. It uses a hypothetical `IUserService` to check a database for an existing email address. Because the rule requires asynchronous I/O, the required synchronous `Validate` implementation throws . ```csharp From 8a1d92274031fa8571008f9bbe03174641c4b31e Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 23 Sep 2026 14:57:05 +0000 Subject: [PATCH 3/3] Fix spacing and update ms.date per review feedback Co-authored-by: oroztocil <79744616+oroztocil@users.noreply.github.com> --- aspnetcore/blazor/forms/validation.md | 2 +- aspnetcore/fundamentals/validation.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/aspnetcore/blazor/forms/validation.md b/aspnetcore/blazor/forms/validation.md index 39a789fd4c6c..3eeb77ef6b0a 100644 --- a/aspnetcore/blazor/forms/validation.md +++ b/aspnetcore/blazor/forms/validation.md @@ -476,7 +476,7 @@ editContext.SetFieldCssClassProvider( For custom input markup, call to obtain the class selected by the current provider. -When an `EditForm` is assigned a model, its child content receives the generated `EditContext`. Capture the context through the `Context` parameter and call `FieldCssClass` to apply the field's classes to surrounding markup: +When an `EditForm` is assigned a model, its child content receives the generated `EditContext`. Capture the context through the `Context` parameter and call `FieldCssClass` to apply the field's classes to surrounding markup: ```razor diff --git a/aspnetcore/fundamentals/validation.md b/aspnetcore/fundamentals/validation.md index 40ce051d94a9..24bec0b67a0c 100644 --- a/aspnetcore/fundamentals/validation.md +++ b/aspnetcore/fundamentals/validation.md @@ -5,7 +5,7 @@ author: Youssef1313 description: Use Microsoft.Extensions.Validation in ASP.NET Core to validate models. monikerRange: '>= aspnetcore-10.0' ms.author: ygerges -ms.date: 09/22/2026 +ms.date: 09/23/2026 uid: fundamentals/validation --- # Validation in ASP.NET Core