Skip to content

Commit affa60b

Browse files
committed
Address PR review feedback
- Rewrite Blazor validation sections (SSR client-side, async, localization) per @oroztocil's suggestions - Update TOC entries to match new section titles - Rewrite #65650 OpenAPI paragraph per @mikekistler's suggestion (and drop the leaked vscode-file URL) - Remove @cincuranet from community contributors per @Youssef1313 (not a community contributor) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent 02cb625 commit affa60b

1 file changed

Lines changed: 88 additions & 39 deletions

File tree

release-notes/11.0/preview/preview5/aspnetcore.md

Lines changed: 88 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@
22

33
.NET 11 Preview 5 includes new ASP.NET Core features and improvements:
44

5-
- [Blazor SSR forms validate in the browser](#blazor-ssr-forms-validate-in-the-browser)
6-
- [Blazor forms support async validation](#blazor-forms-support-async-validation)
7-
- [Validation supports resource-based localization](#validation-supports-resource-based-localization)
5+
- [Blazor SSR supports client-side validation](#blazor-ssr-supports-client-side-validation)
6+
- [Blazor supports async form validation](#blazor-supports-async-form-validation)
7+
- [Blazor and Minimal APIs support localized validation errors](#blazor-and-minimal-apis-support-error-localization)
88
- [QuickGrid works without interactivity](#quickgrid-works-without-interactivity)
99
- [Blazor WebAssembly preserves server culture](#blazor-webassembly-preserves-server-culture)
1010
- [SupplyParameterFromSession for Blazor](#supplyparameterfromsession-for-blazor)
@@ -20,43 +20,63 @@ ASP.NET Core updates in .NET 11:
2020

2121
<!-- Verified against Microsoft.AspNetCore.App.Ref@11.0.0-preview.5.26276.113, Microsoft.AspNetCore.Components.WebAssembly.Server@11.0.0-preview.5.26276.113, and Microsoft.AspNetCore.Components.QuickGrid@11.0.0-preview.5.26276.113. -->
2222

23-
## Blazor SSR forms validate in the browser
23+
## Blazor SSR supports client-side validation
2424

25-
Blazor SSR forms now render client-side validation metadata from `System.ComponentModel.DataAnnotations` attributes and include a small JavaScript validator that reads the generated `data-val-*` attributes ([dotnet/aspnetcore #66441](https://github.com/dotnet/aspnetcore/pull/66441), [dotnet/aspnetcore #66420](https://github.com/dotnet/aspnetcore/pull/66420)). Static SSR forms that already use `DataAnnotationsValidator` can show validation messages before posting back to the server. The .NET model remains the source of truth for validation rules, and the browser gets the same instant feedback pattern used by MVC unobtrusive validation.
25+
Blazor SSR forms now get instant, in-browser validation feedback without a server round-trip, matching the experience provided by interactive Blazor apps and MVC apps with unobtrusive validation ([dotnet/aspnetcore #66441](https://github.com/dotnet/aspnetcore/pull/66441), [dotnet/aspnetcore #66420](https://github.com/dotnet/aspnetcore/pull/66420)). The .NET model remains the single source of truth for validation rules. The server renders metadata for the validation rules which are then enforced by the Blazor JS code on the client-side.
2626

27-
```razor
28-
@page "/subscribe"
29-
@using System.ComponentModel.DataAnnotations
27+
The feature is enabled by default for all SSR forms that include the `DataAnnotationsValidator` component. Both enhanced and non-enhanced forms are supported.
3028

31-
<EditForm Model="Model" FormName="subscribe" OnValidSubmit="SubscribeAsync">
29+
```csharp
30+
<EditForm Model="Model" Enhance FormName="registration" OnValidSubmit="HandleValidSubmit">
3231
<DataAnnotationsValidator />
3332

34-
<label>
35-
Email
36-
<InputText @bind-Value="Model.Email" />
37-
</label>
38-
<ValidationMessage For="() => Model.Email" />
39-
40-
<button type="submit">Subscribe</button>
33+
<div>
34+
<label for="Email">Email</label>
35+
<InputText @bind-Value="Model.Email" id="Email" />
36+
<ValidationMessage For="@(() => Model.Email)" />
37+
</div>
38+
39+
<div>
40+
<label for="Password">Password</label>
41+
<InputText @bind-Value="Model.Password" id="Password" type="password" />
42+
<ValidationMessage For="@(() => Model.Password)" />
43+
</div>
44+
45+
<div>
46+
<label for="ConfirmPassword">Confirm Password</label>
47+
<InputText @bind-Value="Model.ConfirmPassword" id="ConfirmPassword" type="password" />
48+
<ValidationMessage For="@(() => Model.ConfirmPassword)" />
49+
</div>
50+
51+
<div>
52+
<button type="submit" id="submit-btn">Register</button>
53+
</div>
4154
</EditForm>
55+
```
4256

43-
@code {
44-
private SubscribeForm Model { get; } = new();
45-
46-
private Task SubscribeAsync() => Task.CompletedTask;
47-
48-
private sealed class SubscribeForm
49-
{
50-
[Required]
51-
[EmailAddress]
52-
public string? Email { get; set; }
53-
}
57+
```csharp
58+
public class RegistrationModel
59+
{
60+
[Required]
61+
[EmailAddress]
62+
public string Email { get; set; }
63+
64+
[Required]
65+
[StringLength(100, MinimumLength = 8)]
66+
public string Password { get; set; }
67+
68+
[Required]
69+
[Compare("Password")]
70+
[Display(Name = "Confirm Password")]
71+
public string ConfirmPassword { get; set; }
5472
}
5573
```
5674

57-
## Blazor forms support async validation
75+
## Blazor supports async form validation
76+
77+
Blazor forms get support for async validation rules such as database lookups or remote API calls ([dotnet/aspnetcore #66526](https://github.com/dotnet/aspnetcore/pull/66526)). In any rendering mode, `EditForm` submit validation now properly awaits async validators end-to-end. In interactive modes, validator components can register per-field async tasks via `EditContext.AddValidationTask`. The framework tracks them, cancels superseded tasks, and exposes progress status via `IsValidationPending(field)` and `IsValidationFaulted(field)`.
5878
59-
Blazor forms now support asynchronous validation rules without leaving the `EditContext` model ([dotnet/aspnetcore #66526](https://github.com/dotnet/aspnetcore/pull/66526)). `EditContext.AddValidationTask(FieldIdentifier, Task, CancellationTokenSource)` registers an in-flight check that the framework tracks per field, cancels when superseded, and surfaces through new `IsValidationPending`, `IsValidationFaulted`, and `IsValidationSuperseded` queries. `OnValidationRequestedAsync` lets submit handlers await the same pipeline before reporting overall validity, so async uniqueness, server lookups, and remote calls participate in the standard `ValidationMessageStore`/`ValidationSummary` flow.
79+
While Preview 5 ships the building blocks for Blazor forms, the full built-in async validation experience will be enabled when the new asynchronous `DataAnnotations` APIs are released in a later Preview. These APIs will be fully supported by the existing `DataAnnotationsValidator` component.
6080

6181
```razor
6282
<EditForm EditContext="editContext" OnSubmit="HandleSubmit">
@@ -105,27 +125,57 @@ Blazor forms now support asynchronous validation rules without leaving the `Edit
105125
}
106126
```
107127

108-
## Validation supports resource-based localization
128+
## Blazor and Minimal APIs support error localization
109129

110-
`Microsoft.Extensions.Validation` now ships with built-in localization that flows through Blazor's `DataAnnotationsValidator` and minimal APIs that opt into the new validation pipeline ([dotnet/aspnetcore #66646](https://github.com/dotnet/aspnetcore/pull/66646)). `AddValidationLocalization<TResource>()` registers an `IValidationLocalizer` that resolves `[Display(Name = ...)]` values and `ValidationAttribute.ErrorMessage` keys against an `IStringLocalizer<TResource>` backed by `.resx` files. The same model produces the same display names and validation messages on the server, in the rendered HTML for client-side validation, and in localized API error responses.
130+
Validation of Blazor forms and Minimal API endpoints gets first-class support for localization of error messages and property names ([dotnet/aspnetcore #66646](https://github.com/dotnet/aspnetcore/pull/66646)). By default, localization uses language-specific RESX files deployed as part of the assembly.
111131
112132
```csharp
113-
builder.Services.AddLocalization();
114-
builder.Services.AddValidation();
115-
builder.Services.AddValidationLocalization<ValidationMessages>();
133+
builder.Services.AddValidation()
134+
.AddValidationLocalization<ValidationMessages>();
135+
// Resolves to ValidationMessages.en.resx, ValidationMessages.es.resx, ...
116136
```
117137

118138
```csharp
119139
[ValidatableType]
120140
public class ContactModel
121141
{
122-
[Required(ErrorMessage = nameof(ValidationMessages.RequiredError))]
123-
[EmailAddress(ErrorMessage = nameof(ValidationMessages.EmailError))]
124-
[Display(Name = nameof(ValidationMessages.ContactEmail))]
142+
// Values of ErrorMessage are used as localization keys.
143+
[Required(ErrorMessage = "RequiredError")]
144+
[EmailAddress(ErrorMessage = "EmailError")]
145+
[Display(Name = "ContactEmail")]
125146
public string? Email { get; set; }
126147
}
127148
```
128149

150+
Applications can also register custom `IStringLocalizerFactory` implementations to read the localized strings from other sources such as databases or JSON files. User registered type takes precedence over the default RESX localization.
151+
152+
```csharp
153+
builder.Services.AddValidation()
154+
.AddValidationLocalization();
155+
builder.Services.AddSingleton<IStringLocalizerFactory, DbStringLocalizerFactory>();
156+
```
157+
158+
Applications can also configure a programmatic strategy for localization, removing the need to specify localization keys on every validation attribute.
159+
160+
```csharp
161+
builder.Services.AddValidation()
162+
.AddValidationLocalization<ValidationMessages>(options =>
163+
{
164+
options.ErrorMessageKeyProvider = ctx =>
165+
ctx.Attribute.ErrorMessage ?? $"{ctx.Attribute.GetType().Name}_Error";
166+
});
167+
```
168+
169+
```csharp
170+
[ValidatableType]
171+
public class ContactModel
172+
{
173+
// Looks-up localized string for 'RequiredAttribute_Error' automatically.
174+
[Required]
175+
public string? Username { get; set; }
176+
}
177+
```
178+
129179
## QuickGrid works without interactivity
130180

131181
`QuickGrid` sorting and pagination now work in statically rendered Blazor SSR pages ([dotnet/aspnetcore #65451](https://github.com/dotnet/aspnetcore/pull/65451)). When the grid is not interactive, sortable headers and paginator controls render as enhanced forms that update URL query-string state instead of relying on `@onclick` handlers. Users can sort, page, refresh, and share links without an interactive circuit or WebAssembly runtime.
@@ -228,7 +278,7 @@ app.MapGet("/orders", (OrderStatus status) => Results.Ok(status));
228278

229279
With this configuration, a body schema can still describe `OrderStatus.PendingReview` as `pending-review`, while the query parameter schema describes the accepted value as `PendingReview`.
230280

231-
MVC controllers and minimal APIs can now declare multiple `[ProducesResponseType]` attributes (or `.Produces<T>` calls) for the same status code ([dotnet/aspnetcore #65650](https://github.com/dotnet/aspnetcore/pull/65650)). Prior releases collapsed each status code to a single response type and quietly dropped the rest, which made polymorphic results impossible to describe accurately. `ApiExplorer` now preserves every declared response type with deterministic ordering, and the generated OpenAPI document carries all of them so generated clients can model every shape an endpoint can return.
281+
Minimal API endpoints can support multiple `Produces<T>()` extension methods for the same status codefor example, to specify that a 200 response may arrive as `application/json` or `text/plain` with different schemas ([dotnet/aspnetcore #65650](https://github.com/dotnet/aspnetcore/pull/65650)). The same support applies to MVC controllers via multiple `[ProducesResponseType]` attributes. In prior releases the framework collapsed each status code to a single response type and silently dropped the rest, making it impossible to describe endpoints that serve multiple content types. ApiExplorer now preserves every declared response type with deterministic ordering, and the generated OpenAPI document emits separate content entries per media type—or an `anyOf` schema when multiple types share the same content type—so generated clients can accurately model every shape an endpoint returns.
232282
233283
Thank you [@marcominerva](https://github.com/marcominerva) for the array schema reference contribution!
234284
@@ -264,7 +314,6 @@ Thank you [@marcominerva](https://github.com/marcominerva) for the array schema
264314

265315
Thank you contributors! ❤️
266316

267-
- [@cincuranet](https://github.com/dotnet/aspnetcore/pulls?q=is%3Apr+is%3Amerged+author%3Acincuranet+milestone%3A11.0-preview5)
268317
- [@EduardF1](https://github.com/dotnet/aspnetcore/pulls?q=is%3Apr+is%3Amerged+author%3AEduardF1+milestone%3A11.0-preview5)
269318
- [@marcominerva](https://github.com/dotnet/aspnetcore/pulls?q=is%3Apr+is%3Amerged+author%3Amarcominerva+milestone%3A11.0-preview5)
270319
- [@martincostello](https://github.com/dotnet/aspnetcore/pulls?q=is%3Apr+is%3Amerged+author%3Amartincostello+milestone%3A11.0-preview5)

0 commit comments

Comments
 (0)