diff --git a/aspnetcore/blazor/components/prerender.md b/aspnetcore/blazor/components/prerender.md index 06732f2de0e4..dbd31cbf94d4 100644 --- a/aspnetcore/blazor/components/prerender.md +++ b/aspnetcore/blazor/components/prerender.md @@ -202,7 +202,7 @@ 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. -* The `AddPersistentService` 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: +* 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. @@ -231,7 +231,8 @@ public class CounterService In `Program.cs`: ```csharp -builder.Services.AddPersistentService(RenderMode.InteractiveAuto); +builder.Services.RegisterPersistentService( + RenderMode.InteractiveAuto); ``` Serialized properties are identified from the actual service instance: diff --git a/aspnetcore/blazor/components/rendering.md b/aspnetcore/blazor/components/rendering.md index 756d63ca619d..95616c94a95d 100644 --- a/aspnetcore/blazor/components/rendering.md +++ b/aspnetcore/blazor/components/rendering.md @@ -53,6 +53,32 @@ Streaming rendering requires the server to avoid buffering the output. The respo To stream content updates when using static server-side rendering (static SSR) or prerendering, apply the [`[StreamRendering]` attribute](xref:Microsoft.AspNetCore.Components.StreamRenderingAttribute) in .NET 9 or later (use `[StreamRendering(true)]` in .NET 8) to the component. Streaming rendering must be explicitly enabled because streamed updates may cause content on the page to shift. Components without the attribute automatically adopt streaming rendering if the parent component uses the feature. Pass `false` to the attribute in a child component to disable the feature at that point and further down the component subtree. The attribute is functional when applied to components supplied by a [Razor class library](xref:blazor/components/class-libraries). +:::moniker-end + +:::moniker range=">= aspnetcore-10.0" + +If [enhanced navigation](xref:blazor/fundamentals/routing#enhanced-navigation-and-form-handling) is active, streaming rendering renders [Not Found responses](xref:blazor/fundamentals/routing#not-found-responses) 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](xref:blazor/fundamentals/routing#not-found-responses) (`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): + +* 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. + +Non-streaming `NavigationManager.NotFound` content rendering uses (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). + +[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. + +:::moniker-end + +:::moniker range=">= aspnetcore-8.0" + The following example is based on the `Weather` component in an app created from the [Blazor Web App project template](xref:blazor/project-structure#blazor-web-app). The call to simulates retrieving weather data asynchronously. The component initially renders placeholder content ("`Loading...`") without waiting for the asynchronous delay to complete. When the asynchronous delay completes and the weather data content is generated, the content is streamed to the response and patched into the weather forecast table. `Weather.razor`: diff --git a/aspnetcore/blazor/forms/validation.md b/aspnetcore/blazor/forms/validation.md index d7afa0977288..bc055d2ad2cd 100644 --- a/aspnetcore/blazor/forms/validation.md +++ b/aspnetcore/blazor/forms/validation.md @@ -1557,12 +1557,108 @@ The doesn't work w :::moniker-end -## Nested models, collection types, and complex types +:::moniker range=">= aspnetcore-10.0" + +## Nested objects and collection types + +Blazor form validation includes support for validating properties of nested objects and collection items with the built-in . + +To create a validated form, use a component inside an component, just as before. + +To opt into the nested objects and collection types validation feature: + + + +1. Call the `AddValidation` extension method in the `Program` file where services are registered. +2. Declare the form model types in a C# class file, not in a Razor component (`.razor`). +3. Annotate the root form model type with the `[ValidatableType]` attribute. + +Without following the preceding steps, form validation behavior doesn't include nested model and collection type validation. + + + +The following example demonstrates customer orders with the improved form validation (details omitted for brevity): + +In `Program.cs`, call `AddValidation` on the service collection: + +```csharp +builder.Services.AddValidation(); +``` + +In the following `Order` class, the `[ValidatableType]` attribute is required on the top-level model type. The other types are discovered automatically. `OrderItem` and `ShippingAddress` aren't shown for brevity, but nested and collection validation works the same way in those types if they were shown. + +`Order.cs`: + +```csharp +[ValidatableType] +public class Order +{ + public Customer Customer { get; set; } = new(); + public List OrderItems { get; set; } = []; +} + +public class Customer +{ + [Required(ErrorMessage = "Name is required.")] + public string? FullName { get; set; } + + [Required(ErrorMessage = "Email is required.")] + public string? Email { get; set; } + + public ShippingAddress ShippingAddress { get; set; } = new(); +} +``` + +In the following `OrderPage` component, the component is present in the component. + +`OrderPage.razor`: + +```razor + + + +

Customer Details

+
+ + +
+ + // ... form continues ... +
+ +@code { + public Order? Model { get; set; } + + protected override void OnInitialized() => Model ??= new(); +} +``` + +The requirement to declare the model types outside of Razor components (`.razor` files) is due to the fact that both the new validation feature and the Razor compiler itself are using a source generator. Currently, output of one source generator can't be used as an input for another source generator. + +## Complex types + +Blazor provides support for validating form input using data annotations with the built-in . However, the only validates top-level properties of the model bound to the form that aren't complex-type properties. + +To validate the bound model's entire object graph, including complex-type properties, use the `ObjectGraphDataAnnotationsValidator` provided by the *experimental* [`Microsoft.AspNetCore.Components.DataAnnotations.Validation`](https://www.nuget.org/packages/Microsoft.AspNetCore.Components.DataAnnotations.Validation) package. + +> [!NOTE] +> The `ObjectGraphDataAnnotationsValidator` isn't compatible with [nested objects and collection types validation](#nested-objects-and-collection-types), but it's capable of validating nested objects and collection types on its own. + +:::moniker-end + +:::moniker range="< aspnetcore-10.0" + +## Nested objects, collection types, and complex types Blazor provides support for validating form input using data annotations with the built-in . However, the only validates top-level properties of the model bound to the form that aren't collection- or complex-type properties. To validate the bound model's entire object graph, including collection- and complex-type properties, use the `ObjectGraphDataAnnotationsValidator` provided by the *experimental* [`Microsoft.AspNetCore.Components.DataAnnotations.Validation`](https://www.nuget.org/packages/Microsoft.AspNetCore.Components.DataAnnotations.Validation) package: +:::moniker-end + ```razor diff --git a/aspnetcore/blazor/fundamentals/routing.md b/aspnetcore/blazor/fundamentals/routing.md index 391bd075112c..39121f5273ac 100644 --- a/aspnetcore/blazor/fundamentals/routing.md +++ b/aspnetcore/blazor/fundamentals/routing.md @@ -708,14 +708,33 @@ For more information on component disposal, see -*In .NET 10 Preview 4, Not Found responses are only available for static SSR and global interactive rendering. Per-page/component rendering support is planned for Preview 5 in June, 2025.* - provides a `NotFound` method to handle scenarios where a requested resource isn't found during static server-side rendering (static SSR) or global interactive rendering: * **Static SSR**: Calling `NotFound` sets the HTTP status code to 404. -* **Streaming rendering**: Throws an exception if the response has already started. + * **Interactive rendering**: Signals the Blazor router ([`Router` component](xref:blazor/fundamentals/routing#route-templates)) to render Not Found content. +* **Streaming rendering**: If [enhanced navigation](xref:blazor/fundamentals/routing#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. + +> [!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): + +* 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. + +Non-streaming `NavigationManager.NotFound` content rendering uses (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). + +[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. + When a component is rendered statically (static SSR) and `NavigationManager.NotFound` is called, the 404 status code is set on the response: ```razor @@ -743,7 +762,7 @@ To provide Not Found content for global interactive rendering, use a Not Found p

Sorry! Nothing to show.

``` -Assign the `NotFound` component to the router's `NotFoundPage` parameter. `NotFoundPage` supports routing that can be used across re-execution middleware, including non-Blazor middleware. If the `NotFound` render fragment is defined together with `NotFoundPage`, the page has higher priority. +Assign the `NotFound` component to the router's `NotFoundPage` parameter. `NotFoundPage` supports routing that can be used across Status Code Pages Re-execution Middleware, including non-Blazor middleware. If the `NotFound` render fragment (`...`) is defined together with `NotFoundPage`, the page has higher priority. In the following example, the preceding `NotFound` component is present in the app's `Pages` folder and passed to the `NotFoundPage` parameter: @@ -779,7 +798,7 @@ You can use the `OnNotFound` event for notifications when `NotFound` is invoked. + Re-execution Middleware. --> In the following example for components that adopt [interactive server-side rendering (interactive SSR)](xref:blazor/fundamentals/index#client-and-server-rendering-concepts), custom content is rendered depending on where `OnNotFound` is called. If the event is triggered by the following `Movie` component when a movie isn't found on component initialization, a custom message states that the requested movie isn't found. If the event is triggered by the `User` component, a different message states that the user isn't found. diff --git a/aspnetcore/blazor/host-and-deploy/index.md b/aspnetcore/blazor/host-and-deploy/index.md index 14b64641e491..25f391be609e 100644 --- a/aspnetcore/blazor/host-and-deploy/index.md +++ b/aspnetcore/blazor/host-and-deploy/index.md @@ -106,6 +106,40 @@ For more information on *solutions*, see true +``` + +> [!IMPORTANT] +> This feature only produces the bundler-friendly output when publishing the app. + +The output isn't directly runnable in the browser, but it can be consumed by JS tools to bundle JS files with the rest of the developer-supplied scripts. + +When `WasmBundlerFriendlyBootConfig` is enabled, the produced JS contains `import` directives for all of the assets in the app, which makes the dependencies visible for the bundler. Many of the assets aren't loadable by the browser, but bundlers usually can be configured to recognize the assets by their file type to handle loading. For details on how to configure your bundler, refer to the bundler's documentation. + +> [!NOTE] +> Bundling build output should be possible by mapping imports to individual file locations using a JS bundler custom plugin. We don't provide such a plugin at the moment. + +> [!NOTE] +> Replacing the `files` plugin with `url`, all of the app's JS files, including the Blazor-WebAssembly runtime (base64 encoded in the JS), are bundled into the output. The size of the file is significantly larger (for example, 300% larger) than when the files are curated with the `files` plugin, so we don't recommend using the `url` plugin as a general practice when producing bundler-friendly output for JS bundler processing. + +The following sample apps are based on [Rollup](https://rollupjs.org/). Similar concepts apply when using other JS bundlers. + +Demonstration sample apps: + +* [Blazor WASM in a React application (`maraf/blazor-wasm-react` GitHub repository)](https://github.com/maraf/blazor-wasm-react) +* [.NET on WASM in a React component sample (`maraf/dotnet-wasm-react` GitHub repository)](https://github.com/maraf/dotnet-wasm-react) + +:::moniker-end + ## Blazor Server `MapFallbackToPage` configuration *This section only applies to Blazor Server apps. isn't supported in Blazor Web Apps and Blazor WebAssembly apps.* diff --git a/aspnetcore/blazor/host-and-deploy/server/index.md b/aspnetcore/blazor/host-and-deploy/server/index.md index e39724e52efc..70135ea17c6b 100644 --- a/aspnetcore/blazor/host-and-deploy/server/index.md +++ b/aspnetcore/blazor/host-and-deploy/server/index.md @@ -40,6 +40,23 @@ For guidance on building secure and scalable server-side Blazor apps, see the fo Each circuit uses approximately 250 KB of memory for a minimal *Hello World*-style app. The size of a circuit depends on the app's code and the state maintenance requirements associated with each component. We recommend that you measure resource demands during development for your app and infrastructure, but the following baseline can be a starting point in planning your deployment target: If you expect your app to support 5,000 concurrent users, consider budgeting at least 1.3 GB of server memory to the app (or ~273 KB per user). +:::moniker range=">= aspnetcore-10.0" + +## 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 (``): + +```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. + +:::moniker-end + ## SignalR configuration [SignalR's hosting and scaling conditions](xref:signalr/publish-to-azure-web-app) apply to Blazor apps that use SignalR. diff --git a/aspnetcore/blazor/host-and-deploy/webassembly/azure-static-web-apps.md b/aspnetcore/blazor/host-and-deploy/webassembly/azure-static-web-apps.md index 6fb9d181e2d6..4e9fb0156e1b 100644 --- a/aspnetcore/blazor/host-and-deploy/webassembly/azure-static-web-apps.md +++ b/aspnetcore/blazor/host-and-deploy/webassembly/azure-static-web-apps.md @@ -40,7 +40,7 @@ To deploy from Visual Studio, create a publish profile for Azure Static Web Apps 1. In the publish profile configuration, provide the **Subscription name**. Select an existing instance, or select **Create a new instance**. When creating a new instance in the Azure portal's **Create Static Web App** UI, set the **Deployment details** > **Source** to **Other**. Wait for the deployment to complete in the Azure portal before proceeding. -1. In the publish profile configuration, select the Azure Static Web Apps instance from the instance's resource group. Select **Finish** to create the publish profile. If Visual Studio prompts to install the Static Web Apps (SWA) CLI, install the CLI by following the prompts. The SWA CLI requires [NPM/Node.js (Visual Studio documentation)](/visualstudio/javascript/npm-package-management). +1. In the publish profile configuration, select the Azure Static Web Apps instance from the instance's resource group. Select **Finish** to create the publish profile. If Visual Studio prompts to install the Static Web Apps (SWA) CLI, install the CLI by following the prompts. The SWA CLI requires [npm/Node.js (Visual Studio documentation)](/visualstudio/javascript/npm-package-management). After the publish profile is created, deploy the app to the Azure Static Web Apps instance using the publish profile by selecting the **Publish** button. diff --git a/aspnetcore/blazor/host-and-deploy/webassembly/bundle-caching-and-integrity-check-failures.md b/aspnetcore/blazor/host-and-deploy/webassembly/bundle-caching-and-integrity-check-failures.md index 0bb3544f1e98..ab84368f003d 100644 --- a/aspnetcore/blazor/host-and-deploy/webassembly/bundle-caching-and-integrity-check-failures.md +++ b/aspnetcore/blazor/host-and-deploy/webassembly/bundle-caching-and-integrity-check-failures.md @@ -1,7 +1,7 @@ --- -title: ASP.NET Core Blazor WebAssembly .NET bundle caching and integrity check failures +title: ASP.NET Core Blazor WebAssembly caching and integrity check failures author: guardrex -description: Learn about WebAssembly .NET app and runtime bundle caching and how to resolve integrity check failures in Blazor WebAssembly apps. +description: Learn about asset caching for Blazor WebAssembly and how to resolve integrity check failures in Blazor WebAssembly apps. monikerRange: '>= aspnetcore-3.1' ms.author: wpickett ms.custom: mvc @@ -12,7 +12,7 @@ uid: blazor/host-and-deploy/webassembly/bundle-caching-and-integrity-check-failu [!INCLUDE[](~/includes/not-latest-version.md)] -This article explains how Blazor WebAssembly caches the WebAssembly .NET runtime and app bundle and how to diagnose and resolve integrity failures. +This article explains asset caching for Blazor WebAssembly and how to diagnose and resolve integrity failures. When a Blazor WebAssembly app loads in the browser, the app downloads boot resources from the server: @@ -20,13 +20,30 @@ When a Blazor WebAssembly app loads in the browser, the app downloads boot resou * .NET runtime and assemblies * Locale specific data -Except for Blazor's boot manifest file (`blazor.boot.json`) prior to the release of .NET 10†, WebAssembly .NET runtime and app bundle files are cached on clients. The Blazor boot configuration, inlined into `dotnet.js` in .NET 10 or later, contains a manifest of the files that make up the app that must be downloaded along with a hash of the file's content that's used to detect whether any of the boot resources have changed. Blazor caches downloaded files using the browser [Cache](https://developer.mozilla.org/docs/Web/API/Cache) API. +:::moniker range=">= aspnetcore-10.0" + +The Blazor boot configuration, inlined into `dotnet.js`, contains a fingerprinted manifest of the files that make up the app that must be downloaded along with a hash of each file's content. The app's files are preloaded and cached by the browser. > [!NOTE] -> †If upgrading an app to .NET 10 or later and the app relies on the `blazor.boot.json` manifest file for custom processing, we recommend collecting the information directly from the build. +> †In .NET 10 or later, the `blazor.boot.json` manifest file is no longer present. If upgrading an app that relies on the manifest file for custom processing, we recommend collecting the information directly from the build. + +When Blazor WebAssembly downloads an app's startup files, it instructs the browser to perform integrity checks on the responses. Blazor sends SHA-256 hash values for DLL (`.dll`), WebAssembly (`.wasm`), and other files. The file hashes of cached files are compared to the hashes in the boot configuration. An error is generated by the browser if any downloaded file's integrity check fails. + +For more information, see the following sections of the *Fundamentals: Static files* article: + +* [Preloaded Blazor framework static assets](xref:blazor/fundamentals/static-files#preloaded-blazor-framework-static-assets) +* [Fingerprint client-side static assets in standalone Blazor WebAssembly apps](xref:blazor/fundamentals/static-files#fingerprint-client-side-static-assets-in-standalone-blazor-webassembly-apps) + +:::moniker-end + +:::moniker range="< aspnetcore-10.0" + +Except for Blazor's boot manifest file (`blazor.boot.json`), WebAssembly .NET runtime and app bundle files are cached on clients. The Blazor boot configuration contains a manifest of the files that make up the app that must be downloaded along with a hash of the file's content that's used to detect whether any of the boot resources have changed. Blazor caches downloaded files using the browser [Cache](https://developer.mozilla.org/docs/Web/API/Cache) API. When Blazor WebAssembly downloads an app's startup files, it instructs the browser to perform integrity checks on the responses. Blazor sends SHA-256 hash values for DLL (`.dll`), WebAssembly (`.wasm`), and other files in the Blazor boot configuration, which isn't cached on clients. The file hashes of cached files are compared to the hashes in the Blazor boot configuration. For cached files with a matching hash, Blazor uses the cached files. Otherwise, files are requested from the server. After a file is downloaded, its hash is checked again for integrity validation. An error is generated by the browser if any downloaded file's integrity check fails. +:::moniker-end + Blazor's algorithm for managing file integrity: * Ensures that the app doesn't risk loading an inconsistent set of files, for example if a new deployment is applied to your web server while the user is in the process of downloading the application files. Inconsistent files can result in a malfunctioning app. @@ -145,6 +162,14 @@ In most cases, don't disable integrity checking. Disabling integrity checking do There may be cases where the web server can't be relied upon to return consistent responses, and you have no choice but to temporarily disable integrity checks until the underlying problem is resolved. +:::moniker range=">= aspnetcore-10.0" + +To disable integrity checks, [manually load client-side boot resources](xref:blazor/fundamentals/startup#load-client-side-boot-resources) and avoid passing the `integrity` parameter to the `fetch` call. + +:::moniker-end + +:::moniker range="< aspnetcore-10.0" + To disable integrity checks, add the following to a property group in the Blazor WebAssembly app's project file (`.csproj`): ```xml @@ -153,10 +178,12 @@ To disable integrity checks, add the following to a property group in the Blazor `BlazorCacheBootResources` also disables Blazor's default behavior of caching the `.dll`, `.wasm`, and other files based on their SHA-256 hashes because the property indicates that the SHA-256 hashes can't be relied upon for correctness. Even with this setting, the browser's normal HTTP cache may still cache those files, but whether or not this happens depends on your web server configuration and the `cache-control` headers that it serves. +:::moniker-end + > [!NOTE] > The `BlazorCacheBootResources` property doesn't disable integrity checks for [Progressive Web Applications (PWAs)](xref:blazor/progressive-web-app/index). For guidance pertaining to PWAs, see the [Disable integrity checking for PWAs](#disable-integrity-checking-for-pwas) section. -We can't provide an exhaustive list of scenarios where disabling integrity checking is required. Servers can answer a request in arbitrary ways outside of the scope of the Blazor framework. The framework provides the `BlazorCacheBootResources` setting to make the app runnable at the cost of *losing a guarantee of integrity that the app can provide*. Again, we don't recommend disabling integrity checking, especially for production deployments. Developers should seek to solve the underlying integrity problem that's causing integrity checking to fail. +We can't provide an exhaustive list of scenarios where disabling integrity checking is required. Servers can answer a request in arbitrary ways outside of the scope of the Blazor framework. The framework permits the preceding approach to make the app runnable at the cost of *losing a guarantee of integrity that the app can provide*. Again, we don't recommend disabling integrity checking, especially for production deployments. Developers should seek to solve the underlying integrity problem that's causing integrity checking to fail. A few general cases that can cause integrity issues are: diff --git a/aspnetcore/blazor/host-and-deploy/webassembly/http-caching-issues.md b/aspnetcore/blazor/host-and-deploy/webassembly/http-caching-issues.md index e730cddce1d9..7f18a7198b1b 100644 --- a/aspnetcore/blazor/host-and-deploy/webassembly/http-caching-issues.md +++ b/aspnetcore/blazor/host-and-deploy/webassembly/http-caching-issues.md @@ -54,6 +54,8 @@ Usually the source of cache state problems is limited to the HTTP browser cache, You can optionally include the `storage` directive to clear local storage caches at the same time that you're clearing the HTTP browser cache. However, apps that use client storage might experience a loss of important information if the `storage` directive is used. +:::moniker range="< aspnetcore-10.0" + ### Append a query string to the Blazor script tag If none of the previous recommended actions are effective, possible to use for your deployment, or apply to your app, consider temporarily appending a query string to the Blazor script's `