From c9dabc008f70ddf385ef2cf4754d18b6d6bba82c Mon Sep 17 00:00:00 2001 From: Luke Latham <1622880+guardrex@users.noreply.github.com> Date: Thu, 22 May 2025 09:20:23 -0400 Subject: [PATCH 1/2] Add section and update cross-links (#35511) --- .../cascading-values-and-parameters.md | 28 +++++++++++++++---- aspnetcore/blazor/components/render-modes.md | 4 +-- aspnetcore/blazor/state-management.md | 2 +- aspnetcore/migration/70-80.md | 2 +- aspnetcore/release-notes/aspnetcore-8.0.md | 5 +++- 5 files changed, 30 insertions(+), 11 deletions(-) diff --git a/aspnetcore/blazor/components/cascading-values-and-parameters.md b/aspnetcore/blazor/components/cascading-values-and-parameters.md index 01913ef7460e..780924102d61 100644 --- a/aspnetcore/blazor/components/cascading-values-and-parameters.md +++ b/aspnetcore/blazor/components/cascading-values-and-parameters.md @@ -94,6 +94,8 @@ builder.Services.AddCascadingValue(sp => > > Avoid using to register a component type as a cascading value. Instead, wrap the `...` in the `Routes` component (`Components/Routes.razor`) with the component and adopt global interactive server-side rendering (interactive SSR). For an example, see the [`CascadingValue` component](#cascadingvalue-component) section. +## Root-level cascading values with notifications + Calling to issue update notifications can be used to signal multiple Razor component subscribers that a cascading value has changed. Notifications aren't possible for subscribers that adopt static server-side rendering (static SSR), so subscribers must adopt an interactive render mode. In the following example: @@ -103,6 +105,9 @@ In the following example: Keep in mind for production code that any change in state (any property value change of the class) causes all subscribed components to rerender, regardless of which part of the state they use. We recommend creating granular classes, cascading them separately with specific subscriptions to ensure that only components subscribed to a specific portion of the application state are affected by changes. +> [!NOTE] +> For a Blazor Web App solution consisting of server and client (`.Client`) projects, the following `NotifyingDalek.cs` file is placed in the `.Client` project. + `NotifyingDalek.cs`: ```csharp @@ -143,6 +148,9 @@ public class NotifyingDalek : INotifyPropertyChanged The following `CascadingStateServiceCollectionExtensions` creates a from a type that implements . +> [!NOTE] +> For a Blazor Web App solution consisting of server and client (`.Client`) projects, the following `CascadingStateServiceCollectionExtensions.cs` file is placed in the `.Client` project. + `CascadingStateServiceCollectionExtensions.cs`: ```csharp @@ -192,17 +200,14 @@ public static class CascadingStateServiceCollectionExtensions The type's (`HandlePropertyChanged`) calls the 's method to notify subscribers that the cascading value has changed. The is discarded when calling because the call only represents the duration of the dispatch to the synchronous context. Exceptions are handled internally by dispatching them to the renderer within the context of whichever component threw when receiving the update. This is the same way that exceptions are processed with a , which isn't notified about exceptions that happen inside notification recipients. The event handler is disconnected in the `Dispose` method to prevent a memory leak. -In the `Program` file†, `NotifyingDalek` is passed to create a with an initial `Unit` value of 888 units: +In the `Program` file, `NotifyingDalek` is passed to create a with an initial `Unit` value of 888 units: ```csharp builder.Services.AddNotifyingCascadingValue(new NotifyingDalek() { Units = 888 }); ``` > [!NOTE] -> †For Blazor Web App solutions consisting of server and client (`.Client`) projects: -> -> * The preceding `NotifyingDalek.cs` and `CascadingStateServiceCollectionExtensions.cs` files are placed in the `.Client` project. -> * The preceding code is placed into each project's `Program` file. +> For a Blazor Web App solution consisting of server and client (`.Client`) projects, the preceding code is placed into each project's `Program` file. The following component is used to demonstrate how changing the value of `NotifyingDalek.Units` notifies subscribers. @@ -275,6 +280,16 @@ To demonstrate multiple subscriber notifications, the following `DaleksMain` com ``` +Add a navigation link to the `DaleksMain` component in `NavMenu.razor`: + +```razor + +``` + Because the 's type in this example (`NotifyingDalek`) is a class type, you can meet virtually any state management feature specification requirement. However, subscriptions create overhead and reduce performance, so benchmark the performance of this approach in your app and compare it to other [state management approaches](xref:blazor/state-management) before adopting it in a production app with constrained processing and memory resources. Any change in state (any property value change of the class) causes all subscribed components to rerender, regardless of which part of the state they use. **Avoid creating a single large class representing the entire global application state.** Instead, create granular classes and cascade them separately with specific subscriptions to cascading parameters, ensuring that only components subscribed to a specific portion of the application state are affected by changes. @@ -409,6 +424,7 @@ Blazor Web Apps provide alternative approaches for cascading values that apply m For more information, see the following sections of this article: * [Root-level cascading values](#root-level-cascading-values) +* [Root-level cascading values with notifications](#root-level-cascading-values-with-notifications) * [Cascading values/parameters and render mode boundaries](#cascading-valuesparameters-and-render-mode-boundaries) :::moniker-end @@ -507,7 +523,7 @@ Cascading parameters aren't JSON-serializable because the typical usage patterns Recommendations: -* If you need to make state available to all interactive components as a cascading parameter, we recommend using [root-level cascading values](#root-level-cascading-values). A factory pattern is available, and the app can emit updated values after app startup. Root-level cascading values are available to all components, including interactive components, since they're processed as DI services. +* If you need to make state available to all interactive components as a cascading parameter, we recommend using [root-level cascading values](#root-level-cascading-values) or [root-level cascading values with notifications](#root-level-cascading-values-with-notifications). A factory pattern is available, and the app can emit updated values after app startup. Root-level cascading values are available to all components, including interactive components, since they're processed as DI services. * For component library authors, you can create an extension method for library consumers similar to the following: diff --git a/aspnetcore/blazor/components/render-modes.md b/aspnetcore/blazor/components/render-modes.md index c5c6d322e40e..f06dbbe70124 100644 --- a/aspnetcore/blazor/components/render-modes.md +++ b/aspnetcore/blazor/components/render-modes.md @@ -974,7 +974,7 @@ To address this scenario, inject the service in a new imports file placed in the * * * -* [Cascading values/parameters and render mode boundaries](xref:blazor/components/cascading-values-and-parameters#cascading-valuesparameters-and-render-mode-boundaries): Also see the [Root-level cascading parameters](xref:blazor/components/cascading-values-and-parameters#root-level-cascading-parameters) section earlier in the article. +* [Cascading values/parameters and render mode boundaries](xref:blazor/components/cascading-values-and-parameters#cascading-valuesparameters-and-render-mode-boundaries): Also see the [Root-level cascading values](xref:blazor/components/cascading-values-and-parameters#root-level-cascading-values) and [Root-level cascading values with notifications](xref:blazor/components/cascading-values-and-parameters#root-level-cascading-values-with-notifications) sections earlier in the article. * * [Secure data in Blazor Web Apps with Interactive Auto rendering](xref:blazor/security/index#secure-data-in-blazor-web-apps-with-interactive-auto-rendering) @@ -983,7 +983,7 @@ To address this scenario, inject the service in a new imports file placed in the :::moniker range="< aspnetcore-9.0" * -* [Cascading values/parameters and render mode boundaries](xref:blazor/components/cascading-values-and-parameters#cascading-valuesparameters-and-render-mode-boundaries): Also see the [Root-level cascading parameters](xref:blazor/components/cascading-values-and-parameters#root-level-cascading-parameters) section earlier in the article. +* [Cascading values/parameters and render mode boundaries](xref:blazor/components/cascading-values-and-parameters#cascading-valuesparameters-and-render-mode-boundaries): Also see the [Root-level cascading values](xref:blazor/components/cascading-values-and-parameters#root-level-cascading-values) and [Root-level cascading values with notifications](xref:blazor/components/cascading-values-and-parameters#root-level-cascading-values-with-notifications) sections earlier in the article. * * [Secure data in Blazor Web Apps with Interactive Auto rendering](xref:blazor/security/index#secure-data-in-blazor-web-apps-with-interactive-auto-rendering) diff --git a/aspnetcore/blazor/state-management.md b/aspnetcore/blazor/state-management.md index 9e252c93869b..34b4b2bd5523 100644 --- a/aspnetcore/blazor/state-management.md +++ b/aspnetcore/blazor/state-management.md @@ -863,7 +863,7 @@ Use [cascading values and parameters](xref:blazor/components/cascading-values-an :::moniker range=">= aspnetcore-8.0" -Root-level cascading values with a permit Razor component subscriber notifications of changed cascading values. For more information and a working example, see the `NotifyingDalek` example in . +Root-level cascading values with a permit Razor component subscriber notifications of changed cascading values. For more information and a working example, see the `NotifyingDalek` example in . :::moniker-end diff --git a/aspnetcore/migration/70-80.md b/aspnetcore/migration/70-80.md index 6890aea29048..eab2027bd89c 100644 --- a/aspnetcore/migration/70-80.md +++ b/aspnetcore/migration/70-80.md @@ -495,7 +495,7 @@ Cascading parameters don't pass data across render mode boundaries, and layouts The two approaches for migration are: -* (*Recommended*) Pass the state as a root-level cascading value. For more information, see [Root-level cascading values](xref:blazor/components/cascading-values-and-parameters#root-level-cascading-values). +* (*Recommended*) Pass the state as a root-level cascading value. For more information, see the guidance on [root-level cascading values](xref:blazor/components/cascading-values-and-parameters#root-level-cascading-values) and [root-level cascading values with notifications](xref:blazor/components/cascading-values-and-parameters#root-level-cascading-values-with-notifications). * Wrap the router in the `Routes` component with the [`CascadingValue`](xref:Microsoft.AspNetCore.Components.CascadingValue%601) component and make the `Routes` component interactively rendered. For an example, see [`CascadingValue` component](xref:blazor/components/cascading-values-and-parameters?view=aspnetcore-8.0&preserve-view=true#cascadingvalue-component). For more information, see [Cascading values/parameters and render mode boundaries](xref:blazor/components/cascading-values-and-parameters?view=aspnetcore-8.0&preserve-view=true#cascading-valuesparameters-and-render-mode-boundaries). diff --git a/aspnetcore/release-notes/aspnetcore-8.0.md b/aspnetcore/release-notes/aspnetcore-8.0.md index 15044ecaac80..388a076dd128 100644 --- a/aspnetcore/release-notes/aspnetcore-8.0.md +++ b/aspnetcore/release-notes/aspnetcore-8.0.md @@ -179,7 +179,10 @@ For more information, see . +For more information, see the following resources: + +* [Root-level cascading values](xref:blazor/components/cascading-values-and-parameters?view=aspnetcore-8.0&preserve-view=true#root-level-cascading-values) +* [Root-level cascading values with notifications](xref:blazor/components/cascading-values-and-parameters?view=aspnetcore-8.0&preserve-view=true#root-level-cascading-values-with-notifications) ### Virtualize empty content From 9a9d45edbf824d37a97266d8a39e926626b62e9e Mon Sep 17 00:00:00 2001 From: Luke Latham <1622880+guardrex@users.noreply.github.com> Date: Thu, 22 May 2025 10:55:30 -0400 Subject: [PATCH 2/2] Version out example for 8.0 (#35514) --- aspnetcore/blazor/fundamentals/startup.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/aspnetcore/blazor/fundamentals/startup.md b/aspnetcore/blazor/fundamentals/startup.md index 05904cc0ac77..9e93a4c3dae2 100644 --- a/aspnetcore/blazor/fundamentals/startup.md +++ b/aspnetcore/blazor/fundamentals/startup.md @@ -676,6 +676,10 @@ In a component that adopts Interactive WebAssembly rendering, wrap the component } ``` +:::moniker-end + +:::moniker range=">= aspnetcore-9.0" + #### Global Interactive WebAssembly rendering with prerendering *This scenario applies to global Interactive WebAssembly rendering with prerendering (`@rendermode="InteractiveWebAssembly"` on the `HeadOutlet` and `Routes` components in the `App` component).* @@ -722,6 +726,10 @@ In `Layout/MainLayout.razor`: + ``` +:::moniker-end + +:::moniker range=">= aspnetcore-8.0" + #### Global Interactive WebAssembly rendering without prerendering *This scenario applies to global Interactive WebAssembly rendering without prerendering (`@rendermode="new InteractiveWebAssemblyRenderMode(prerender: false)"` on the `HeadOutlet` and `Routes` components in the `App` component).*