diff --git a/release-notes/10.0/preview/preview3/aspnetcore.md b/release-notes/10.0/preview/preview3/aspnetcore.md index ea6c93966f..316c01225e 100644 --- a/release-notes/10.0/preview/preview3/aspnetcore.md +++ b/release-notes/10.0/preview/preview3/aspnetcore.md @@ -2,7 +2,14 @@ Here's a summary of what's new in ASP.NET Core in this preview release: -- [Feature](#feature) +- [Declarative model for persisting state from components and services](#declarative-model-for-persisting-state-from-components-and-services) +- [Reference fingerprinted static web assets in standalone Blazor WebAssembly apps](#reference-fingerprinted-static-web-assets-in-standalone-blazor-webassembly-apps) +- [`HttpClient` response streaming enabled by default on WebAssembly](#httpclient-response-streaming-enabled-by-default-on-webassembly) +- [`DisableMatchAllIgnoresLeftUriPart` app context switch renamed to `EnableMatchAllForQueryStringAndFragment`](#disablematchallignoreslefturipart-app-context-switch-renamed-to-enablementchallofthequerystringandfragment) +- [Set the environment at build-time for standalone Blazor WebAssembly apps](#set-the-environment-at-build-time-for-standalone-blazor-webassembly-apps) +- [Validation support in minimal APIs](#validation-support-in-minimal-apis) +- [OpenAPI support enabled by default in the ASP.NET Core Web API (native AOT) template](#openapi-support-enabled-by-default-in-the-aspnet-core-web-api-native-aot-template) +- [Support for Server-Sent Events (SSE)](#support-for-server-sent-events-sse) ASP.NET Core updates in .NET 10: @@ -10,6 +17,256 @@ ASP.NET Core updates in .NET 10: - [Breaking changes](https://docs.microsoft.com/dotnet/core/compatibility/10.0#aspnet-core) - [Roadmap](https://github.com/dotnet/aspnetcore/issues/59443) -## Feature +## Declarative model for persisting state from components and services + +You can now declaratively specify state to persist from components and services using the `SupplyParameterFromPersistentComponentState` attribute. Properties with this attribute will automatically be persisted using the `PersistentComponentState` service during prerendering and then loaded when the component renders interactively or the service is instantiated. + +Previously, persisting state from a component during prerendering using the `PersistentComponentState` service involved a significant amount of code: + +```razor +@page "/movies" +@inject IMovieService MovieService +@inject PersistentComponentState ApplicationState +@implements IDisposable + +Movies + +

Movies

+ +@if (MoviesList == null) +{ +

Loading...

+} +else +{ + + + + + + +} + +@code { + public List? MoviesList { get; set; } + private PersistingComponentStateSubscription? persistingSubscription; + + protected override async Task OnInitializedAsync() + { + if (!ApplicationState.TryTakeFromJson>("movies", out var movies)) + { + MoviesList = await MovieService.GetMoviesAsync(); + } + else + { + MoviesList = movies; + } + + persistingSubscription = ApplicationState.RegisterOnPersisting(() => + { + ApplicationState.PersistAsJson("movies", MoviesList); + return Task.CompletedTask; + }); + } + + public void Dispose() => persistingSubscription?.Dispose(); +} +``` + +This code can now be simplified using the new declarative model: + +```razor +@page "/movies" +@inject IMovieService MovieService + +Movies + +

Movies

+ +@if (MoviesList == null) +{ +

Loading...

+} +else +{ + + + + + + +} + +@code { + [SupplyParameterFromPersistentComponentState] + public List? MoviesList { get; set; } + + protected override async Task OnInitializedAsync() + { + MoviesList ??= await MovieService.GetMoviesAsync(); + } +} +``` + +## Reference fingerprinted static web assets in standalone Blazor WebAssembly apps + +Standalone Blazor WebAssembly apps can now reference framework static web assets using either a generated import map or a fingerprinted URL. The import map and fingerprinted URLs are generated during the build process when the `true` property is specified in the project file. + +**blazorwasm.csproj** + +```diff + + + net10.0 + enable + enable ++ true + + +``` + +To specify where the import map should be generated, add an empty `` element to your *index.html* file. To generate fingerprinted URLs for referenced static web assets, use the `#[.{fingerprint}]` placeholder. + +**index.html** + +```diff + + + + + + + Codestin Search App + + .... ++ + + + +
+ + + + +
+
+ +
+ An unhandled error has occurred. + Reload + 🗙 +
+- ++ + + + +``` + +## `HttpClient` response streaming enabled by default on WebAssembly + +Response streaming is now enabled by default for `HttpClient` in Blazor WebAssembly. This change improves performance and reduces memory usage when handling large responses. However, it also means the response stream no longer supports synchronous operations because it is no longer a `MemoryStream`. If your code requires using synchronous operations, you can opt-out of response streaming for an individual request using the `SetBrowserResponseStreamingEnabled` extension method on the response message: + +```csharp +requestMessage.SetBrowserResponseStreamingEnabled(false); +``` + +## `DisableMatchAllIgnoresLeftUriPart` app context switch renamed to `EnableMatchAllForQueryStringAndFragment` + +The `Microsoft.AspNetCore.Components.Routing.NavLink.DisableMatchAllIgnoresLeftUriPart` app context switch was renamed to `Microsoft.AspNetCore.Components.Routing.NavLink.EnableMatchAllForQueryStringAndFragment`. + +## Set the environment at build-time for standalone Blazor WebAssembly apps + +You can now specify the environment for a standalone Blazor WebAssembly app at build-time using the `` property in the client app's project file (`.csproj`). In .NET 10, the `Blazor-Environment` header is no longer generated or used for setting the client environment. + +The following example sets the app's environment to `Staging`: + +```xml +Staging +``` + +The default environments applied to the app are: + +* `Development` for build. +* `Production` for publish. + +## Validation support in minimal APIs + +Support for validation in minimal APIs is now available. This feature allows you to request validation of data sent to your API endpoints. When validation is enabled, the ASP.NET Core runtime performs any validations defined on query, header, and route parameters, as well as on the request body. Validations can be defined using attributes in the `System.ComponentModel.DataAnnotations` namespace. + +Developers can customize the behavior of the validation system by: + +- creating custom [ValidationAttribute](https://learn.microsoft.com/dotnet/api/system.componentmodel.dataannotations.validationattribute) implementations +- implementing the [IValidatableObject](https://learn.microsoft.com/dotnet/api/system.componentmodel.dataannotations.ivalidatableobject) interface for complex validation logic + +When validation fails, the runtime returns a 400 Bad Request response with details of the validation errors. + +To enable built-in validation support for minimal APIs, call the `AddValidation` extension method to register the required services into the service container for your application. + +```csharp +builder.Services.AddValidation(); +``` + +The implementation automatically discovers types that are defined in minimal API handlers or as base types of types defined in minimal API handlers. Validation is performed on these types by an endpoint filter added to each endpoint. + +Validation can be disabled for specific endpoints by using the `DisableValidation` extension method. + +```csharp +app.MapPost("/products", + ([EvenNumber(ErrorMessage = "Product ID must be even")] int productId, [Required] string name) + => TypedResults.Ok(productId)) + .DisableValidation(); +``` + +## OpenAPI support enabled by default in the ASP.NET Core Web API (native AOT) template + +The ASP.NET Core Web API (native AOT) project template now has OpenAPI document generation support enabled by default using the Microsoft.AspNetCore.OpenApi package. This support can be disabled if desired, using the `--no-openapi` flag when creating a new project from the command-line interface. + +Thank you [@sander1095](https://github.com/sander1095) for this contribution! + +## Support for Server-Sent Events (SSE) + +ASP.NET Core now supports returning a `ServerSentEvents` result using the `TypedResults.ServerSentEvents` API. This feature is supported in both minimal APIs and controller-based apps. + +Server-Sent Events (SSE) is a server push technology that allows a server to send a stream of event messages to a client over a single HTTP connection. In .NET the event messages are represented as [SseItem](https://learn.microsoft.com/dotnet/api/system.net.serversentevents.sseitem-1) objects, which may contain an event type, an ID, and a data payload of type `T`. + +The TypedResults class includes a new static `ServerSentEvents` method for returning a `ServerSentEvents` result. The first parameter to this method is an `IAsyncEnumerable>` that represents the stream of event messages to be sent to the client. + +The following example illustrates how to use the `TypedResults.ServerSentEvents` API to return a stream of heart rate events as JSON objects to the client: + +```csharp +app.MapGet("/json-item", (CancellationToken cancellationToken) => +{ + async IAsyncEnumerable GetHeartRate( + [EnumeratorCancellation] CancellationToken cancellationToken) + { + while (!cancellationToken.IsCancellationRequested) + { + var heartRate = Random.Shared.Next(60, 100); + yield return HeartRateEvent.Create(heartRate); + await Task.Delay(2000, cancellationToken); + } + } + + return TypedResults.ServerSentEvents(GetHeartRate(cancellationToken), eventType: "heartRate"); +}); +``` + +## Community contributors + +Thank you contributors! ❤️ + +- [@NSTom](https://github.com/dotnet/aspnetcore/pulls?q=is%3Apr+is%3Amerged+milestone%3A10.0-preview3+author%3ANSTom) +- [@Varorbc](https://github.com/dotnet/aspnetcore/pulls?q=is%3Apr+is%3Amerged+milestone%3A10.0-preview3+author%3AVarorbc) +- [@Youssef1313](https://github.com/dotnet/aspnetcore/pulls?q=is%3Apr+is%3Amerged+milestone%3A10.0-preview3+author%3AYoussef1313) +- [@alexbeeston](https://github.com/dotnet/aspnetcore/pulls?q=is%3Apr+is%3Amerged+milestone%3A10.0-preview3+author%3Aalexbeeston) +- [@benhopkinstech](https://github.com/dotnet/aspnetcore/pulls?q=is%3Apr+is%3Amerged+milestone%3A10.0-preview3+author%3Abenhopkinstech) +- [@jnjudge1](https://github.com/dotnet/aspnetcore/pulls?q=is%3Apr+is%3Amerged+milestone%3A10.0-preview3+author%3Ajnjudge1) +- [@lextm](https://github.com/dotnet/aspnetcore/pulls?q=is%3Apr+is%3Amerged+milestone%3A10.0-preview3+author%3Alextm) +- [@mapedersen](https://github.com/dotnet/aspnetcore/pulls?q=is%3Apr+is%3Amerged+milestone%3A10.0-preview3+author%3Amapedersen) +- [@nidaca](https://github.com/dotnet/aspnetcore/pulls?q=is%3Apr+is%3Amerged+milestone%3A10.0-preview3+author%3Anidaca) +- [@sander1095](https://github.com/dotnet/aspnetcore/pulls?q=is%3Apr+is%3Amerged+milestone%3A10.0-preview3+author%3Asander1095) +- [@shethaadit](https://github.com/dotnet/aspnetcore/pulls?q=is%3Apr+is%3Amerged+milestone%3A10.0-preview3+author%3Ashethaadit) +- [@smnsht](https://github.com/dotnet/aspnetcore/pulls?q=is%3Apr+is%3Amerged+milestone%3A10.0-preview3+author%3Asmnsht) +- [@xt0rted](https://github.com/dotnet/aspnetcore/pulls?q=is%3Apr+is%3Amerged+milestone%3A10.0-preview3+author%3Axt0rted) -Something about the feature