From 67e80f598dd18b3ab8a3b10f2161296d5aaf9ea8 Mon Sep 17 00:00:00 2001
From: guardrex <1622880+guardrex@users.noreply.github.com>
Date: Mon, 11 Aug 2025 07:16:09 -0400
Subject: [PATCH 01/16] Rename LinkPreload to ResourcePreloader
---
aspnetcore/blazor/host-and-deploy/server/index.md | 6 +++---
aspnetcore/release-notes/aspnetcore-10/includes/blazor.md | 6 +++---
2 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/aspnetcore/blazor/host-and-deploy/server/index.md b/aspnetcore/blazor/host-and-deploy/server/index.md
index 70135ea17c6b..91b1851d0596 100644
--- a/aspnetcore/blazor/host-and-deploy/server/index.md
+++ b/aspnetcore/blazor/host-and-deploy/server/index.md
@@ -44,16 +44,16 @@ Each circuit uses approximately 250 KB of memory for a minimal *Hello World*-sty
## Blazor WebAssembly static asset preloading
-The `LinkPreload` component in the `App` component's head content (`App.razor`) is used to reference Blazor static assets. The component is placed after the base URL tag (``):
+The `ResourcePreloader` component in the `App` component's head content (`App.razor`) is used to reference Blazor static assets. The component is placed after the base URL tag (``):
```razor
-
+
```
A Razor component is used instead of `` elements because:
* The component permits the base URL (`` tag's `href` attribute value) to correctly identify the root of the Blazor app within an ASP.NET Core app.
-* The feature can be removed by removing the `LinkPreload` component tag from the `App` component. This is helpful in cases where the app is using a [`loadBootResource` callback](xref:blazor/fundamentals/startup#load-client-side-boot-resources) to modify URLs.
+* The feature can be removed by removing the `ResourcePreloader` component tag from the `App` component. This is helpful in cases where the app is using a [`loadBootResource` callback](xref:blazor/fundamentals/startup#load-client-side-boot-resources) to modify URLs.
:::moniker-end
diff --git a/aspnetcore/release-notes/aspnetcore-10/includes/blazor.md b/aspnetcore/release-notes/aspnetcore-10/includes/blazor.md
index 9858b1617a1c..b010c485d377 100644
--- a/aspnetcore/release-notes/aspnetcore-10/includes/blazor.md
+++ b/aspnetcore/release-notes/aspnetcore-10/includes/blazor.md
@@ -450,17 +450,17 @@ For more information, see ` headers with a `LinkPreload` component (``) for preloading WebAssembly assets in Blazor Web Apps. This permits the app base path configuration (``) to correctly identify the app's root.
+We replaced `` headers with a `ResourcePreloader` component (``) for preloading WebAssembly assets in Blazor Web Apps. This permits the app base path configuration (``) to correctly identify the app's root.
Removing the component disables the feature if the app is using a [`loadBootResource` callback](xref:blazor/fundamentals/startup?view=aspnetcore-10.0#load-client-side-boot-resources) to modify URLs.
-The Blazor Web App template adopts the feature by default in .NET 10, and apps upgrading to .NET 10 can implement the feature by placing the `LinkPreload` component after the base URL tag (``) in the `App` component's head content (`App.razor`):
+The Blazor Web App template adopts the feature by default in .NET 10, and apps upgrading to .NET 10 can implement the feature by placing the `ResourcePreloader` component after the base URL tag (``) in the `App` component's head content (`App.razor`):
```diff
...
-+
++
...
```
From 4ed3a92849b5fb175235fd4295bb6c32a49fe6d1 Mon Sep 17 00:00:00 2001
From: guardrex <1622880+guardrex@users.noreply.github.com>
Date: Mon, 11 Aug 2025 07:25:41 -0400
Subject: [PATCH 02/16] Updated API names for Blazor state persistence
---
aspnetcore/blazor/components/integration.md | 6 ++---
aspnetcore/blazor/components/lifecycle.md | 2 +-
aspnetcore/blazor/security/index.md | 2 +-
.../prerendered-state-persistence.md | 20 ++++++++--------
aspnetcore/blazor/state-management/server.md | 24 ++++++++-----------
.../aspnetcore-10/includes/blazor.md | 4 ++--
6 files changed, 27 insertions(+), 31 deletions(-)
diff --git a/aspnetcore/blazor/components/integration.md b/aspnetcore/blazor/components/integration.md
index 72c0a53eb978..e7b46bca8214 100644
--- a/aspnetcore/blazor/components/integration.md
+++ b/aspnetcore/blazor/components/integration.md
@@ -408,13 +408,13 @@ In `Pages/_Host.cshtml` of Blazor apps that are `ServerPrerendered` in a Blazor
-Decide what state to persist using the service. The `[SupplyParameterFromPersistentComponentState]` attribute applied to a property registers a callback to persist the state during prerendering and loads it when the component renders interactively or the service is instantiated.
+Decide what state to persist using the service. The `[PersistentState]` attribute applied to a property registers a callback to persist the state during prerendering and loads it when the component renders interactively or the service is instantiated.
In the following example, the `{TYPE}` placeholder represents the type of data to persist (for example, `WeatherForecast[]`).
```razor
@code {
- [SupplyParameterFromPersistentComponentState]
+ [PersistentState]
public {TYPE} Data { get; set; }
protected override async Task OnInitializedAsync()
@@ -469,7 +469,7 @@ else
}
@code {
- [SupplyParameterFromPersistentComponentState]
+ [PersistentState]
public WeatherForecast[]? Forecasts { get; set; }
protected override async Task OnInitializedAsync()
diff --git a/aspnetcore/blazor/components/lifecycle.md b/aspnetcore/blazor/components/lifecycle.md
index d88af2350852..6c49c45fa941 100644
--- a/aspnetcore/blazor/components/lifecycle.md
+++ b/aspnetcore/blazor/components/lifecycle.md
@@ -636,7 +636,7 @@ else
}
@code {
- [SupplyParameterFromPersistentComponentState]
+ [PersistentState]
public string? Data { get; set; }
protected override async Task OnInitializedAsync()
diff --git a/aspnetcore/blazor/security/index.md b/aspnetcore/blazor/security/index.md
index 6db6e394b680..e60d283f4cff 100644
--- a/aspnetcore/blazor/security/index.md
+++ b/aspnetcore/blazor/security/index.md
@@ -676,7 +676,7 @@ else
}
@code {
- [SupplyParameterFromPersistentComponentState]
+ [PersistentState]
public IEnumerable? Forecasts { get; set; }
protected override async Task OnInitializedAsync()
diff --git a/aspnetcore/blazor/state-management/prerendered-state-persistence.md b/aspnetcore/blazor/state-management/prerendered-state-persistence.md
index 79e791748901..857684e173ec 100644
--- a/aspnetcore/blazor/state-management/prerendered-state-persistence.md
+++ b/aspnetcore/blazor/state-management/prerendered-state-persistence.md
@@ -36,13 +36,13 @@ To retain the initial value of the counter during prerendering, Blazor supports
-To preserve prerendered state, use the `[SupplyParameterFromPersistentComponentState]` attribute to persist state in properties. Properties with this attribute are automatically persisted using the service during prerendering. The state is retrieved when the component renders interactively or the service is instantiated.
+To preserve prerendered state, use the `[PersistentState]` attribute to persist state in properties. Properties with this attribute are automatically persisted using the service during prerendering. The state is retrieved when the component renders interactively or the service is instantiated.
By default, properties are serialized using the serializer with default settings and persisted in the prerendered HTML. Serialization isn't trimmer safe and requires preservation of the types used. For more information, see .
The following counter component persists counter state during prerendering and retrieves the state to initialize the component:
-* The `[SupplyParameterFromPersistentComponentState]` attribute is applied to the `CounterState` type (`State`).
+* The `[PersistentState]` attribute is applied to the `CounterState` type (`State`).
* The counter's state is assigned when `null` in `OnInitialized` and restored automatically when the component renders interactively.
`PrerenderedCounter2.razor`:
@@ -60,7 +60,7 @@ The following counter component persists counter state during prerendering and r
@code {
- [SupplyParameterFromPersistentComponentState]
+ [PersistentState]
public CounterState? State { get; set; }
protected override void OnInitialized()
@@ -109,7 +109,7 @@ The following counter component persists counter state during prerendering and r
@code {
- [SupplyParameterFromPersistentComponentState]
+ [PersistentState]
public int? CurrentCount { get; set; }
protected override void OnInitialized()
@@ -142,7 +142,7 @@ When the component executes, `CurrentCount` is only set once during prerendering
In the following example that serializes state for multiple components of the same type:
-* Properties annotated with the `[SupplyParameterFromPersistentComponentState]` attribute are serialized during prerendering.
+* Properties annotated with the `[PersistentState]` attribute are serialized during prerendering.
* The [`@key` directive attribute](xref:blazor/components/key#use-of-the-key-directive-attribute) is used to ensure that the state is correctly associated with the component instance.
* The `Element` property is initialized in the [`OnInitialized` lifecycle method](xref:blazor/components/lifecycle#component-initialization-oninitializedasync) to avoid null reference exceptions, similarly to how null references are avoided for query parameters and form data.
@@ -155,7 +155,7 @@ In the following example that serializes state for multiple components of the sa
@code {
- [SupplyParameterFromPersistentComponentState]
+ [PersistentState]
public State Element { get; set; }
protected override void OnInitialized()
@@ -188,12 +188,12 @@ In the following example that serializes state for multiple components of the sa
In the following example that serializes state for a dependency injection service:
-* Properties annotated with the `[SupplyParameterFromPersistentComponentState]` attribute are serialized during prerendering and deserialized when the app becomes interactive.
+* Properties annotated with the `[PersistentState]` attribute are serialized during prerendering and deserialized when the app becomes interactive.
* The extension method is used to register the service for persistence. The render mode is required because the render mode can't be inferred from the service type. Use any of the following values:
* `RenderMode.Server`: The service is available for the Interactive Server render mode.
* `RenderMode.Webassembly`: The service is available for the Interactive Webassembly render mode.
* `RenderMode.InteractiveAuto`: The service is available for both the Interactive Server and Interactive Webassembly render modes if a component renders in either of those modes.
-* The service is resolved during the initialization of an interactive render mode, and the properties annotated with the `[SupplyParameterFromPersistentComponentState]` attribute are deserialized.
+* The service is resolved during the initialization of an interactive render mode, and the properties annotated with the `[PersistentState]` attribute are deserialized.
> [!NOTE]
> Only persisting scoped services is supported.
@@ -205,7 +205,7 @@ In the following example that serializes state for a dependency injection servic
```csharp
public class CounterService
{
- [SupplyParameterFromPersistentComponentState]
+ [PersistentState]
public int CurrentCount { get; set; }
public void IncrementCount()
@@ -229,7 +229,7 @@ Serialized properties are identified from the actual service instance:
* Supports shared code in different assemblies.
* Results in each instance exposing the same properties.
-As an alternative to using the declarative model for persisting state with the `[SupplyParameterFromPersistentComponentState]` attribute, you can use the service directly, which offers greater flexibility for complex state persistence scenarios. Call to register a callback to persist the component state during prerendering. The state is retrieved when the component renders interactively. Make the call at the end of initialization code in order to avoid a potential race condition during app shutdown.
+As an alternative to using the declarative model for persisting state with the `[PersistentState]` attribute, you can use the service directly, which offers greater flexibility for complex state persistence scenarios. Call to register a callback to persist the component state during prerendering. The state is retrieved when the component renders interactively. Make the call at the end of initialization code in order to avoid a potential race condition during app shutdown.
The following counter component example persists counter state during prerendering and retrieves the state to initialize the component.
diff --git a/aspnetcore/blazor/state-management/server.md b/aspnetcore/blazor/state-management/server.md
index fc340a5997f6..2442e59cf01b 100644
--- a/aspnetcore/blazor/state-management/server.md
+++ b/aspnetcore/blazor/state-management/server.md
@@ -58,14 +58,10 @@ During server-side rendering, Blazor Web Apps can persist a user's session (circ
* Network interruptions
* Proactive resource management (pausing inactive circuits)
-
When the component executes, `CurrentCount` is only set once during prerendering. The value is restored when the component is rerendered. The following is example output.
From ee533ded393c2a54936adfc3cf9269e5b6cb70de Mon Sep 17 00:00:00 2001
From: guardrex <1622880+guardrex@users.noreply.github.com>
Date: Mon, 11 Aug 2025 10:10:49 -0400
Subject: [PATCH 04/16] Not Found updates
---
aspnetcore/blazor/components/layouts.md | 24 ++---
aspnetcore/blazor/components/render-modes.md | 14 ++-
aspnetcore/blazor/fundamentals/routing.md | 88 ++++++++++++++-----
.../aspnetcore-10/includes/blazor.md | 68 +++++++++++---
4 files changed, 141 insertions(+), 53 deletions(-)
diff --git a/aspnetcore/blazor/components/layouts.md b/aspnetcore/blazor/components/layouts.md
index 9ad6b6d89084..0c1ef4732a9b 100644
--- a/aspnetcore/blazor/components/layouts.md
+++ b/aspnetcore/blazor/components/layouts.md
@@ -304,31 +304,17 @@ Specifying the layout as a default layout in the component. You can use a in any Razor component. The following example sets a layout component named `ErrorLayout` for the `MainLayout` component's template (`...`).
+To set a layout for arbitrary Razor template content, specify the layout with a component. You can use a in any Razor component. The following example sets a layout component named `ErrorLayout` for the component that includes the following Razor markup.
```razor
-
-
- ...
-
-
-
-
Page not found
-
Sorry, there's nothing at this address.
-
-
-
+
+
Page not found
+
Sorry, there's nothing at this address.
+
```
You may need to identity the layout's namespace depending on the .NET version and type of Blazor app. For more information, see the [Make the layout namespace available](#make-the-layout-namespace-available) section.
-:::moniker range=">= aspnetcore-8.0"
-
-> [!IMPORTANT]
-> Blazor Web Apps don't use the parameter (`...` markup), but the parameter is supported for backward compatibility to avoid a breaking change in the framework. The server-side ASP.NET Core middleware pipeline processes requests on the server. Use server-side techniques to handle bad requests. For more information, see .
-
-:::moniker-end
-
:::moniker range="= aspnetcore-5.0"
[!INCLUDE[](~/blazor/includes/prefer-exact-matches.md)]
diff --git a/aspnetcore/blazor/components/render-modes.md b/aspnetcore/blazor/components/render-modes.md
index 94e3513cf3a8..40bc7c8150cb 100644
--- a/aspnetcore/blazor/components/render-modes.md
+++ b/aspnetcore/blazor/components/render-modes.md
@@ -339,11 +339,21 @@ In the following example, there's no designation for the component's render mode
If using the preceding component locally in a Blazor Web App, place the component in the server project's `Components/Pages` folder. The server project is the solution's project with a name that doesn't end in `.Client`. When the app is running, navigate to `/render-mode-1` in the browser's address bar.
+:::moniker range=">= aspnetcore-10.0"
+
+During static SSR, Razor component page requests are processed by server-side ASP.NET Core middleware pipeline request processing for authorization. Dedicated Blazor features for authorization aren't operational because Razor components aren't rendered during server-side request processing. Blazor router features in the `Routes` component that aren't available during static SSR include displaying [Not Authorized content (`...`)](xref:blazor/security/index#authorizeview-component) (). Blazor Web Apps typically process unauthorized requests on the server by [customizing the behavior of Authorization Middleware](xref:security/authorization/authorizationmiddlewareresulthandler).
+
+:::moniker-end
+
+:::moniker range="< aspnetcore-10.0"
+
During static SSR, Razor component page requests are processed by server-side ASP.NET Core middleware pipeline request processing for routing and authorization. Dedicated Blazor features for routing and authorization aren't operational because Razor components aren't rendered during server-side request processing. Blazor router features in the `Routes` component that aren't available during static SSR include displaying:
-* [Not authorized content (`...`)](xref:blazor/security/index#authorizeview-component) (): Blazor Web Apps typically process unauthorized requests on the server by [customizing the behavior of Authorization Middleware](xref:security/authorization/authorizationmiddlewareresulthandler).
+* [Not Authorized content (`...`)](xref:blazor/security/index#authorizeview-component) (): Blazor Web Apps typically process unauthorized requests on the server by [customizing the behavior of Authorization Middleware](xref:security/authorization/authorizationmiddlewareresulthandler).
+
+* [Not Found content (`...`)](xref:blazor/fundamentals/routing#provide-custom-content-when-content-isnt-found) (): Blazor Web Apps typically process bad URL requests on the server by either displaying the browser's built-in 404 UI or returning a custom 404 page (or other response) via ASP.NET Core middleware (for example, [`UseStatusCodePagesWithRedirects`](xref:fundamentals/error-handling#usestatuscodepageswithredirects) / [API documentation](xref:Microsoft.AspNetCore.Builder.StatusCodePagesExtensions.UseStatusCodePagesWithRedirects%2A)).
-* [Not found content (`...`)](xref:blazor/fundamentals/routing#provide-custom-content-when-content-isnt-found) (): Blazor Web Apps typically process bad URL requests on the server by either displaying the browser's built-in 404 UI or returning a custom 404 page (or other response) via ASP.NET Core middleware (for example, [`UseStatusCodePagesWithRedirects`](xref:fundamentals/error-handling#usestatuscodepageswithredirects) / [API documentation](xref:Microsoft.AspNetCore.Builder.StatusCodePagesExtensions.UseStatusCodePagesWithRedirects%2A)). For more information, see [Create simpler way to show Not Found 404 UI with Blazor (`dotnet/aspnetcore` #45654)](https://github.com/dotnet/aspnetcore/issues/45654).
+:::moniker-end
If the app exhibits root-level interactivity, server-side ASP.NET Core request processing isn't involved after the initial static SSR, which means that the preceding Blazor features work as expected.
diff --git a/aspnetcore/blazor/fundamentals/routing.md b/aspnetcore/blazor/fundamentals/routing.md
index 6cd3cc53ed30..475b7313c257 100644
--- a/aspnetcore/blazor/fundamentals/routing.md
+++ b/aspnetcore/blazor/fundamentals/routing.md
@@ -136,6 +136,8 @@ When the component navigat
:::moniker-end
+:::moniker range="< aspnetcore-10.0"
+
## Provide custom content when content isn't found
The component allows the app to specify custom content if content isn't found for the requested route.
@@ -153,14 +155,14 @@ Set custom content for the
Arbitrary items are supported as content of the parameter, such as other interactive components. To apply a default layout to content, see .
-:::moniker range=">= aspnetcore-8.0"
+Blazor Web Apps don't use the parameter (`...` markup), but the parameter is supported† for backward compatibility in .NET 8/9 to avoid a breaking change in the framework. The server-side ASP.NET Core middleware pipeline processes requests on the server. Use server-side techniques to handle bad requests.
-> [!IMPORTANT]
-> Blazor Web Apps don't use the parameter (`...` markup), but the parameter is supported† for backward compatibility to avoid a breaking change in the framework. The server-side ASP.NET Core middleware pipeline processes requests on the server. Use server-side techniques to handle bad requests.
->
-> †*Supported* in this context means that placing `...` markup doesn't result in an exception, but using the markup isn't effective either.
->
-> For more information, including a recommended approach for handling bad requests, see .
+†*Supported* in this context means that placing `...` markup doesn't result in an exception, but using the markup isn't effective either.
+
+For more information, see the following resources:
+
+*
+* [](#not-found-responses-using-navigationmanager-for-static-ssr-and-global-interactive-rendering) .
:::moniker-end
@@ -714,24 +716,22 @@ For more information on component disposal, see [!NOTE]
> The following discussion mentions that a Not Found Razor component can be assigned to the `Router` component's `NotFoundPage` parameter. The parameter works in concert with `NavigationManager.NotFound` and is described in more detail later in this section.
-Streaming rendering can only render components that have a route, such as a Not Found page assignment with the `Router` component's `NotFoundPage` parameter or a [Status Code Pages Re-execution Middleware page assignment](xref:fundamentals/error-handling#usestatuscodepageswithreexecute) (). The Not Found render fragment (`...`) and the `DefaultNotFound` 404 content ("`Not found`" plain text) don't have routes, so they can't be used during streaming rendering.
-
-Streaming `NavigationManager.NotFound` content rendering uses (in order):
+Streaming rendering can only render components that have a route, such as a [`NotFoundPage` assignment](#blazor-router-has-a-notfoundpage-parameter) (`NotFoundPage="..."`) or a [Status Code Pages Re-execution Middleware page assignment](xref:fundamentals/error-handling#usestatuscodepageswithreexecute) (). `DefaultNotFound` 404 content ("`Not found`" plain text) doesn't have a route, so it can't be used during streaming rendering.
-* A `NotFoundPage` passed to the `Router` component, if present.
-* A Status Code Pages Re-execution Middleware page, if configured.
-* No action if neither of the preceding approaches is adopted.
+> [!NOTE]
+> The Not Found render fragment (`...`) isn't supported in .NET 10 or later.
-Non-streaming `NavigationManager.NotFound` content rendering uses (in order):
+`NavigationManager.NotFound` content rendering uses the following, regardless if the response has started or not (in order):
-* A `NotFoundPage` passed to the `Router` component, if present.
-* Not Found render fragment content, if present. *Not recommended in .NET 10 or later.*
-* `DefaultNotFound` 404 content ("`Not found`" plain text).
+* If is set, render the contents of the assigned page.
+* If `Router.NotFoundPage` is set, render the assigned page.
+* A Status Code Pages Re-execution Middleware page, if configured.
+* No action if none of the preceding approaches are adopted.
[Status Code Pages Re-execution Middleware](xref:fundamentals/error-handling#usestatuscodepageswithreexecute) with takes precedence for browser-based address routing problems, such as an incorrect URL typed into the browser's address bar or selecting a link that has no endpoint in the app.
@@ -796,9 +796,53 @@ When a component is rendered with a global interactive render mode, calling `Not
You can use the `OnNotFound` event for notifications when `NotFound` is invoked. The event is only fired when `NotFound` is called, not for any 404 response. For example, setting `HttpContextAccessor.HttpContext.Response.StatusCode` to `404` doesn't trigger `NotFound`/`OnNotFound`.
-
+Apps that implement a custom router can also use `NavigationManager.NotFound`. The custom router can render Not Found content from two sources, depending on the state of the response:
+
+* Regardless of the response state, the re-execution path to the page can used by passing it to :
+
+ ```csharp
+ app.UseStatusCodePagesWithReExecute(
+ "/not-found", createScopeForStatusCodePages: true);
+ ```
+
+* When the response has started, the can be used by subscribing to the `OnNotFoundEvent` in the router:
+
+ ```razor
+ @code {
+ [CascadingParameter]
+ public HttpContext? HttpContext { get; set; }
+
+ private void OnNotFoundEvent(object sender, NotFoundEventArgs e)
+ {
+ // Only execute the logic if HTTP response has started,
+ // because setting NotFoundEventArgs.Path blocks re-execution
+ if (HttpContext?.Response.HasStarted == false)
+ {
+ return;
+ }
+
+ var type = typeof(CustomNotFoundPage);
+ var routeAttributes = type.GetCustomAttributes(typeof(RouteAttribute),
+ inherit: true);
+
+ if (routeAttributes.Length == 0)
+ {
+ throw new InvalidOperationException($"The type {type.FullName} " +
+ $"doesn't have a {typeof(RouteAttribute).FullName} applied.");
+ }
+
+ var routeAttribute = (RouteAttribute)routeAttributes[0];
+
+ if (routeAttribute.Template != null)
+ {
+ e.Path = routeAttribute.Template;
+ }
+ }
+ }
+ ```
+
+
+
In the following example components:
* The `NotFoundContext` service is injected, along with the .
diff --git a/aspnetcore/release-notes/aspnetcore-10/includes/blazor.md b/aspnetcore/release-notes/aspnetcore-10/includes/blazor.md
index 870b06fbf138..27901a8153cb 100644
--- a/aspnetcore/release-notes/aspnetcore-10/includes/blazor.md
+++ b/aspnetcore/release-notes/aspnetcore-10/includes/blazor.md
@@ -390,7 +390,9 @@ AppContext.SetSwitch(
### Blazor router has a `NotFoundPage` parameter
-Blazor now provides an improved way to display a "Not Found" page when navigating to a non-existent page. You can specify a page to render when `NavigationManager.NotFound` (described in the next section) is invoked by passing a page type to the `Router` component using the `NotFoundPage` parameter. This approach is recommended over using the [`NotFound` render fragment](xref:Microsoft.AspNetCore.Components.Routing.Router.NotFound%2A) (`...`), as it supports routing, works across code Status Code Pages Re-execution Middleware, and is compatible even with non-Blazor scenarios. If both a `NotFound` render fragment and `NotFoundPage` are defined, the page specified by `NotFoundPage` takes priority.
+Blazor now provides an improved way to display a "Not Found" page when navigating to a non-existent page. You can specify a page to render when `NavigationManager.NotFound` (described in the next section) is invoked by passing a page type to the `Router` component using the `NotFoundPage` parameter. The feature supports routing, works across code Status Code Pages Re-execution Middleware, and is compatible even with non-Blazor scenarios.
+
+The [`NotFound` render fragment](xref:Microsoft.AspNetCore.Components.Routing.Router.NotFound%2A) (`...`) isn't supported in .NET 10 or later.
```razor
@@ -416,19 +418,16 @@ The now includes a `Not
* **Streaming rendering**: If [enhanced navigation](xref:blazor/fundamentals/routing?view=aspnetcore-10.0#enhanced-navigation-and-form-handling) is active, [streaming rendering](xref:blazor/components/rendering#streaming-rendering) renders Not Found content without reloading the page. When enhanced navigation is blocked, the framework redirects to Not Found content with a page refresh.
-Streaming rendering can only render components that have a route, such as a [`NotFoundPage` assignment](#blazor-router-has-a-notfoundpage-parameter) (`NotFoundPage="..."`) or a [Status Code Pages Re-execution Middleware page assignment](xref:fundamentals/error-handling#usestatuscodepageswithreexecute) (). The Not Found render fragment (`...`) and the `DefaultNotFound` 404 content ("`Not found`" plain text) don't have routes, so they can't be used during streaming rendering.
-
-Streaming `NavigationManager.NotFound` content rendering uses (in order):
+Streaming rendering can only render components that have a route, such as a [`NotFoundPage` assignment](#blazor-router-has-a-notfoundpage-parameter) (`NotFoundPage="..."`) or a [Status Code Pages Re-execution Middleware page assignment](xref:fundamentals/error-handling#usestatuscodepageswithreexecute) (). `DefaultNotFound` 404 content ("`Not found`" plain text) doesn't have a route, so it can't be used during streaming rendering.
-* A `NotFoundPage` passed to the `Router` component, if present.
-* A Status Code Pages Re-execution Middleware page, if configured.
-* No action if neither of the preceding approaches is adopted.
+The Not Found render fragment (`...`) isn't supported in .NET 10 or later.
-Non-streaming `NavigationManager.NotFound` content rendering uses (in order):
+`NavigationManager.NotFound` content rendering uses the following, regardless if the response has started or not (in order):
-* A `NotFoundPage` passed to the `Router` component, if present.
-* Not Found render fragment content, if present. *Not recommended in .NET 10 or later.*
-* `DefaultNotFound` 404 content ("`Not found`" plain text).
+* If is set, render the contents of the assigned page.
+* If `Router.NotFoundPage` is set, render the assigned page.
+* A Status Code Pages Re-execution Middleware page, if configured.
+* No action if none of the preceding approaches are adopted.
[Status Code Pages Re-execution Middleware](xref:fundamentals/error-handling#usestatuscodepageswithreexecute) with takes precedence for browser-based address routing problems, such as an incorrect URL typed into the browser's address bar or selecting a link that has no endpoint in the app.
@@ -436,6 +435,53 @@ You can use the `NavigationManager.OnNotFound` event for notifications when `Not
For more information and examples, see .
+### Support for Not Found responses in apps without Blazor's router
+
+Apps that implement a custom router can use `NavigationManager.NotFound`. The custom router can render Not Found content from two sources, depending on the state of the response:
+
+* Regardless of the response state, the re-execution path to the page can used by passing it to :
+
+ ```csharp
+ app.UseStatusCodePagesWithReExecute(
+ "/not-found", createScopeForStatusCodePages: true);
+ ```
+
+* When the response has started, the can be used by subscribing to the `OnNotFoundEvent` in the router:
+
+ ```razor
+ @code {
+ [CascadingParameter]
+ public HttpContext? HttpContext { get; set; }
+
+ private void OnNotFoundEvent(object sender, NotFoundEventArgs e)
+ {
+ // Only execute the logic if HTTP response has started,
+ // because setting NotFoundEventArgs.Path blocks re-execution
+ if (HttpContext?.Response.HasStarted == false)
+ {
+ return;
+ }
+
+ var type = typeof(CustomNotFoundPage);
+ var routeAttributes = type.GetCustomAttributes(typeof(RouteAttribute),
+ inherit: true);
+
+ if (routeAttributes.Length == 0)
+ {
+ throw new InvalidOperationException($"The type {type.FullName} " +
+ $"doesn't have a {typeof(RouteAttribute).FullName} applied.");
+ }
+
+ var routeAttribute = (RouteAttribute)routeAttributes[0];
+
+ if (routeAttribute.Template != null)
+ {
+ e.Path = routeAttribute.Template;
+ }
+ }
+ }
+ ```
+
### Metrics and tracing
This release introduces comprehensive metrics and tracing capabilities for Blazor apps, providing detailed observability of the component lifecycle, navigation, event handling, and circuit management.
From 72fa67737c7ae2895cdbd97fa550d57642d796ab Mon Sep 17 00:00:00 2001
From: guardrex <1622880+guardrex@users.noreply.github.com>
Date: Mon, 11 Aug 2025 10:53:06 -0400
Subject: [PATCH 05/16] Hot Reload for WebAssembly
---
aspnetcore/client-side/dotnet-interop.md | 12 ++++++++++++
.../release-notes/aspnetcore-10/includes/blazor.md | 14 +++++++++++++-
2 files changed, 25 insertions(+), 1 deletion(-)
diff --git a/aspnetcore/client-side/dotnet-interop.md b/aspnetcore/client-side/dotnet-interop.md
index 7fd7c87e37d6..5a4f0dfc7bba 100644
--- a/aspnetcore/client-side/dotnet-interop.md
+++ b/aspnetcore/client-side/dotnet-interop.md
@@ -427,6 +427,18 @@ dotnet serve -d:bin/$(Configuration)/{TARGET FRAMEWORK}/publish
In the preceding example, the `{TARGET FRAMEWORK}` placeholder is the [target framework moniker](/dotnet/standard/frameworks).
+:::moniker range=">= aspnetcore-10.0"
+
+To enable [Hot Reload](xref:test/hot-reload) for WebAssembly, set the `WasmEnableHotReload` MSBuild property to `true` in the app's project file:
+
+```xml
+
+ true
+
+```
+
+:::moniker-end
+
### Node.js console app
You can create a console app with the `wasmconsole` template, which creates an app that runs under :::no-loc text="WASM"::: as a [Node.js](https://nodejs.org/) or [V8](https://developers.google.com/apps-script/guides/v8-runtime) console app:
diff --git a/aspnetcore/release-notes/aspnetcore-10/includes/blazor.md b/aspnetcore/release-notes/aspnetcore-10/includes/blazor.md
index 27901a8153cb..44e91f33c917 100644
--- a/aspnetcore/release-notes/aspnetcore-10/includes/blazor.md
+++ b/aspnetcore/release-notes/aspnetcore-10/includes/blazor.md
@@ -617,6 +617,18 @@ During server-side rendering, Blazor Web Apps can now persist a user's session (
* Network interruptions
* Proactive resource management (pausing inactive circuits)
-*[Enhanced navigation](xref:blazor/fundamentals/routing#enhanced-navigation-and-form-handling) with circuit state persistence isn't currently supported but planned for a future release.*
+*[Enhanced navigation](xref:blazor/fundamentals/routing?view=aspnetcore-10.0#enhanced-navigation-and-form-handling) with circuit state persistence isn't currently supported but planned for a future release.*
For more information, see .
+
+### Hot Reload for WebAssembly
+
+The SDK migrated to a general purpose [Hot Reload](xref:test/hot-reload) for WebAssembly. There's a new MSBuild property `WasmEnableHotReload` that's `true` by default for the `Debug` configuration (`Configuration == "Debug"`).
+
+Explicitly set the value to `true` in the app's project file to enable WebAssembly Hot Reload for other configurations, such as when [running .NET from JavaScript with an app created from the `wasmbrowser` template](xref:client-side/dotnet-interop?view=aspnetcore-10.0#browser-app):
+
+```xml
+
+ true
+
+```
From ed52fa660a60024d95b637931a15cfc97aa88ef4 Mon Sep 17 00:00:00 2001
From: guardrex <1622880+guardrex@users.noreply.github.com>
Date: Mon, 11 Aug 2025 11:06:33 -0400
Subject: [PATCH 06/16] PWA service worker registration to prevent caching
issues
---
.../blazor/progressive-web-app/index.md | 30 ++++++++++++++++---
.../aspnetcore-10/includes/blazor.md | 17 +++++++++++
2 files changed, 43 insertions(+), 4 deletions(-)
diff --git a/aspnetcore/blazor/progressive-web-app/index.md b/aspnetcore/blazor/progressive-web-app/index.md
index 57e9cd4581b8..7ecd728e9179 100644
--- a/aspnetcore/blazor/progressive-web-app/index.md
+++ b/aspnetcore/blazor/progressive-web-app/index.md
@@ -147,14 +147,36 @@ In the app's `wwwroot/index.html` file:
:::moniker-end
-* Add the following `
-