diff --git a/aspnetcore/blazor/components/class-libraries-and-static-server-side-rendering.md b/aspnetcore/blazor/components/class-libraries-and-static-server-side-rendering.md index 4cc2a55bfea5..e8a6075fd3e3 100644 --- a/aspnetcore/blazor/components/class-libraries-and-static-server-side-rendering.md +++ b/aspnetcore/blazor/components/class-libraries-and-static-server-side-rendering.md @@ -29,7 +29,7 @@ All existing components can still be used with static SSR. However, the cost of †There's a special exception for the `@onsubmit` event handler for forms, which is always functional, regardless of render mode. -This is equivalent to how components behave during [prerendering](xref:blazor/fundamentals/index#client-and-server-rendering-concepts), before a Blazor circuit or the .NET WebAssembly runtime is started. +This is equivalent to how components behave during [prerendering](xref:blazor/fundamentals/index#client-and-server-rendering-concepts), before Blazor's SignalR circuit or the .NET WebAssembly runtime is started. For components whose only role is to produce read-only DOM content, these behaviors for static SSR are completely sufficient. However, library authors must consider what approach to take when including interactive components in their libraries. diff --git a/aspnetcore/blazor/components/integration.md b/aspnetcore/blazor/components/integration.md index 08222773c383..2f5bd5e3b838 100644 --- a/aspnetcore/blazor/components/integration.md +++ b/aspnetcore/blazor/components/integration.md @@ -536,7 +536,7 @@ The persisted prerendered state is transferred to the client, where it's used to ## Prerendered state size and SignalR message size limit -A large prerendered state size may exceed the SignalR circuit message size limit, which results in the following: +A large prerendered state size may exceed Blazor's SignalR circuit message size limit, which results in the following: * The SignalR circuit fails to initialize with an error on the client: :::no-loc text="Circuit host not initialized."::: * The reconnection UI on the client appears when the circuit fails. Recovery isn't possible. @@ -1055,7 +1055,7 @@ The persisted prerendered state is transferred to the client, where it's used to ## Prerendered state size and SignalR message size limit -A large prerendered state size may exceed the SignalR circuit message size limit, which results in the following: +A large prerendered state size may exceed Blazor's SignalR circuit message size limit, which results in the following: * The SignalR circuit fails to initialize with an error on the client: :::no-loc text="Circuit host not initialized."::: * The reconnection UI on the client appears when the circuit fails. Recovery isn't possible. @@ -1487,7 +1487,7 @@ For more information, see in potential cases where loss of Blazor's SignalR circuit prevents JS interop calls and results an unhandled exception. + +For more information, see the following resources: + +* [JavaScript isolation in JavaScript modules](xref:blazor/js-interop/call-javascript-from-dotnet#javascript-isolation-in-javascript-modules) +* [JavaScript interop calls without a circuit](xref:blazor/js-interop/index#javascript-interop-calls-without-a-circuit) + ## Cancelable background work Components often perform long-running background work, such as making network calls () and interacting with databases. It's desirable to stop the background work to conserve system resources in several situations. For example, background asynchronous operations don't automatically stop when a user navigates away from a component. diff --git a/aspnetcore/blazor/components/render-modes.md b/aspnetcore/blazor/components/render-modes.md index 6ae9f541080f..7d7d5a587f00 100644 --- a/aspnetcore/blazor/components/render-modes.md +++ b/aspnetcore/blazor/components/render-modes.md @@ -535,7 +535,7 @@ In the following example, the `SharedMessage` component is interactive over a Si In the following example, both `SharedMessage` components are prerendered and appear when the page is displayed in the browser. -* The first `SharedMessage` component with interactive server-side rendering (interactive SSR) is interactive after the SignalR circuit is established. +* The first `SharedMessage` component with interactive server-side rendering (interactive SSR) is interactive after Blazor's SignalR circuit is established. * The second `SharedMessage` component with client-side rendering (CSR) is interactive *after* the Blazor app bundle is downloaded and the .NET runtime is active on the client. `RenderMode7.razor`: diff --git a/aspnetcore/blazor/fundamentals/signalr.md b/aspnetcore/blazor/fundamentals/signalr.md index ad02ffa840eb..eda5461f5a28 100644 --- a/aspnetcore/blazor/fundamentals/signalr.md +++ b/aspnetcore/blazor/fundamentals/signalr.md @@ -162,7 +162,7 @@ If prerendering is configured, prerendering occurs before the client connection ## Prerendered state size and SignalR message size limit -A large prerendered state size may exceed the SignalR circuit message size limit, which results in the following: +A large prerendered state size may exceed Blazor's SignalR circuit message size limit, which results in the following: * The SignalR circuit fails to initialize with an error on the client: :::no-loc text="Circuit host not initialized."::: * The reconnection UI on the client appears when the circuit fails. Recovery isn't possible. @@ -768,25 +768,25 @@ Circuit activity handlers also provide an approach for accessing scoped Blazor s :::moniker range=">= aspnetcore-8.0" -Configure the manual start of a Blazor app's SignalR circuit in the `App.razor` file of a Blazor Web App: +Configure the manual start of Blazor's SignalR circuit in the `App.razor` file of a Blazor Web App: :::moniker-end :::moniker range=">= aspnetcore-7.0 < aspnetcore-8.0" -Configure the manual start of a Blazor app's SignalR circuit in the `Pages/_Host.cshtml` file (Blazor Server): +Configure the manual start of Blazor's SignalR circuit in the `Pages/_Host.cshtml` file (Blazor Server): :::moniker-end :::moniker range=">= aspnetcore-6.0 < aspnetcore-7.0" -Configure the manual start of a Blazor app's SignalR circuit in the `Pages/_Layout.cshtml` file (Blazor Server): +Configure the manual start of Blazor's SignalR circuit in the `Pages/_Layout.cshtml` file (Blazor Server): :::moniker-end :::moniker range="< aspnetcore-6.0" -Configure the manual start of a Blazor app's SignalR circuit in the `Pages/_Host.cshtml` file (Blazor Server): +Configure the manual start of Blazor's SignalR circuit in the `Pages/_Host.cshtml` file (Blazor Server): :::moniker-end @@ -1394,9 +1394,9 @@ protected override async Task OnInitializedAsync() :::moniker range=">= aspnetcore-5.0" -## Disconnect the Blazor circuit from the client +## Disconnect Blazor's SignalR circuit from the client -A Blazor circuit is disconnected when the [`unload` page event](https://developer.mozilla.org/docs/Web/API/Window/unload_event) is triggered. To disconnect the circuit for other scenarios on the client, invoke `Blazor.disconnect` in the appropriate event handler. In the following example, the circuit is disconnected when the page is hidden ([`pagehide` event](https://developer.mozilla.org/docs/Web/API/Window/pagehide_event)): +Blazor's SignalR circuit is disconnected when the [`unload` page event](https://developer.mozilla.org/docs/Web/API/Window/unload_event) is triggered. To disconnect the circuit for other scenarios on the client, invoke `Blazor.disconnect` in the appropriate event handler. In the following example, the circuit is disconnected when the page is hidden ([`pagehide` event](https://developer.mozilla.org/docs/Web/API/Window/pagehide_event)): ```javascript window.addEventListener('pagehide', () => { diff --git a/aspnetcore/blazor/hybrid/static-files.md b/aspnetcore/blazor/hybrid/static-files.md index 7656256f0e7f..1e1e5b10922a 100644 --- a/aspnetcore/blazor/hybrid/static-files.md +++ b/aspnetcore/blazor/hybrid/static-files.md @@ -294,7 +294,13 @@ In a Razor component: { if (module is not null) { - await module.DisposeAsync(); + try + { + await module.DisposeAsync(); + } + catch (JSDisconnectedException) + { + } } } } diff --git a/aspnetcore/blazor/includes/js-interop/circuit-disconnection.md b/aspnetcore/blazor/includes/js-interop/circuit-disconnection.md deleted file mode 100644 index f7166ce492ed..000000000000 --- a/aspnetcore/blazor/includes/js-interop/circuit-disconnection.md +++ /dev/null @@ -1,42 +0,0 @@ -*This section only applies to server-side components.* - -JavaScript (JS) interop calls can't be issued after a SignalR circuit is disconnected. Without a circuit during component disposal or at any other time that a circuit doesn't exist, the following method calls fail and log a message that the circuit is disconnected as a : - -* JS interop method calls - * - * - * ) -* `Dispose`/`DisposeAsync` calls on any . - -In order to avoid logging or to log custom information, catch the exception in a [`try-catch`](/dotnet/csharp/language-reference/keywords/try-catch) statement. - -For the following component disposal example: - -* The component implements . -* `objInstance` is an . -* is caught and not logged. -* Optionally, you can log custom information in the `catch` statement at whatever log level you prefer. The following example doesn't log custom information. The code assumes that the developer doesn't care about when or where circuits are disconnected during component disposal. - -```csharp -async ValueTask IAsyncDisposable.DisposeAsync() -{ - try - { - if (objInstance is not null) - { - await objInstance.DisposeAsync(); - } - } - catch (JSDisconnectedException) - { - } -} -``` - -If you must clean up your own JS objects or execute other JS code on the client after a circuit is lost, use the [`MutationObserver`](https://developer.mozilla.org/docs/Web/API/MutationObserver) pattern in JS on the client. The `MutationObserver` pattern allows you to execute JS code when an element is removed from the DOM. - -For more information, see the following articles: - -* : Includes a code example of the `MutationObserver` pattern. -* : The *JavaScript interop* section discusses error handling in JS interop scenarios. -* : The *Component disposal with `IDisposable` and `IAsyncDisposable`* section describes how to implement disposal patterns in Razor components. diff --git a/aspnetcore/blazor/includes/js-interop/js-collocation.md b/aspnetcore/blazor/includes/js-interop/js-collocation.md index 0b2004e64f59..fbc33d311c8e 100644 --- a/aspnetcore/blazor/includes/js-interop/js-collocation.md +++ b/aspnetcore/blazor/includes/js-interop/js-collocation.md @@ -130,7 +130,13 @@ The following `JsCollocation2` component's `OnAfterRenderAsync` method loads a J { if (module is not null) { - await module.DisposeAsync(); + try + { + await module.DisposeAsync(); + } + catch (JSDisconnectedException) + { + } } } } diff --git a/aspnetcore/blazor/includes/js-interop/synchronous-js-interop-call-js.md b/aspnetcore/blazor/includes/js-interop/synchronous-js-interop-call-js.md index 7280a71a9ff4..9e02f71e216c 100644 --- a/aspnetcore/blazor/includes/js-interop/synchronous-js-interop-call-js.md +++ b/aspnetcore/blazor/includes/js-interop/synchronous-js-interop-call-js.md @@ -47,7 +47,13 @@ When working with in ASP.NET Core { if (module is not null) { - await module.DisposeAsync(); + try + { + await module.DisposeAsync(); + } + catch (JSDisconnectedException) + { + } } } } diff --git a/aspnetcore/blazor/javascript-interoperability/call-dotnet-from-javascript.md b/aspnetcore/blazor/javascript-interoperability/call-dotnet-from-javascript.md index 1a228b4003d0..4824c1d35d83 100644 --- a/aspnetcore/blazor/javascript-interoperability/call-dotnet-from-javascript.md +++ b/aspnetcore/blazor/javascript-interoperability/call-dotnet-from-javascript.md @@ -563,7 +563,13 @@ In the following component, the `Trigger JS function` buttons call JS functions { if (module is not null) { - await module.DisposeAsync(); + try + { + await module.DisposeAsync(); + } + catch (JSDisconnectedException) + { + } } dotNetHelper?.Dispose(); diff --git a/aspnetcore/blazor/javascript-interoperability/call-javascript-from-dotnet.md b/aspnetcore/blazor/javascript-interoperability/call-javascript-from-dotnet.md index 4f7c061c9924..957450b76d1a 100644 --- a/aspnetcore/blazor/javascript-interoperability/call-javascript-from-dotnet.md +++ b/aspnetcore/blazor/javascript-interoperability/call-javascript-from-dotnet.md @@ -517,7 +517,48 @@ In the preceding example, the `{CONDITION}` placeholder represents a conditional For browser compatibility, see [Can I use: JavaScript modules: dynamic import](https://caniuse.com/es6-module-dynamic-import). -For example, the following JS module exports a JS function for showing a [browser window prompt](https://developer.mozilla.org/docs/Web/API/Window/prompt). Place the following JS code in an external JS file. +In server-side scenarios, JS interop calls can't be issued after Blazor's SignalR circuit is disconnected. Without a circuit during component disposal or at any other time that a circuit doesn't exist, the following method calls fail and log a message that the circuit is disconnected as a : + +* JS interop method calls + * + * + * ) +* `Dispose`/`DisposeAsync` calls on any . + +In order to avoid logging or to log custom information in server-side Blazor, catch the exception in a [`try-catch`](/dotnet/csharp/language-reference/keywords/try-catch) statement. + +For the following component disposal example: + +* The server-side component implements . +* `module` is an for a JS module. +* is caught and not logged. +* Optionally, you can log custom information in the `catch` statement at whatever log level you prefer. The following example doesn't log custom information. The code assumes that the developer doesn't care about when or where circuits are disconnected during component disposal. + +```csharp +async ValueTask IAsyncDisposable.DisposeAsync() +{ + try + { + if (module is not null) + { + await module.DisposeAsync(); + } + } + catch (JSDisconnectedException) + { + } +} +``` + +If you must clean up your own JS objects or execute other JS code on the client after a circuit is lost in a server-side Blazor app, use the [`MutationObserver`](https://developer.mozilla.org/docs/Web/API/MutationObserver) pattern in JS on the client. The `MutationObserver` pattern allows you to execute JS code when an element is removed from the DOM. + +For more information, see the following articles: + +* : Includes a code example of the `MutationObserver` pattern. +* : The *JavaScript interop* section discusses error handling in JS interop scenarios. +* : The *Component disposal with `IDisposable` and `IAsyncDisposable`* section describes how to implement disposal patterns in Razor components. + +The following JS module exports a JS function for showing a [browser window prompt](https://developer.mozilla.org/docs/Web/API/Window/prompt). Place the following JS code in an external JS file. `wwwroot/scripts.js`: @@ -1069,7 +1110,7 @@ In the preceding example: * The `{TIMEOUT}` placeholder is a (for example, `TimeSpan.FromSeconds(80)`). * The `{ID}` placeholder is the identifier for the function to invoke. For example, the value `someScope.someFunction` invokes the function `window.someScope.someFunction`. -Although a common cause of JS interop failures are network failures with server-side components, per-invocation timeouts can be set for JS interop calls for client-side components. Although no SignalR circuit exists for a client-side component, JS interop calls might fail for other reasons that apply. +Although a common cause of JS interop failures are network failures with server-side components, per-invocation timeouts can be set for JS interop calls for client-side components. Although no Blazor-SignalR circuit exists for a client-side component, JS interop calls might fail for other reasons that apply. For more information on resource exhaustion, see . diff --git a/aspnetcore/blazor/javascript-interoperability/index.md b/aspnetcore/blazor/javascript-interoperability/index.md index 6c94afbced8c..543b4d2b76d4 100644 --- a/aspnetcore/blazor/javascript-interoperability/index.md +++ b/aspnetcore/blazor/javascript-interoperability/index.md @@ -155,7 +155,13 @@ export function addHandlers() { { if (module is not null) { - await module.DisposeAsync(); + try + { + await module.DisposeAsync(); + } + catch (JSDisconnectedException) + { + } } } } @@ -259,7 +265,13 @@ In the following example, the `DOMCleanup` component: { if (module is not null) { - await module.DisposeAsync(); + try + { + await module.DisposeAsync(); + } + catch (JSDisconnectedException) + { + } } } } @@ -303,7 +315,7 @@ window.DOMCleanup = DOMCleanup; *This section only applies to server-side apps.* -JavaScript (JS) interop calls can't be issued after a SignalR circuit is disconnected. Without a circuit during component disposal or at any other time that a circuit doesn't exist, the following method calls fail and log a message that the circuit is disconnected as a : +JavaScript (JS) interop calls can't be issued after Blazor's SignalR circuit is disconnected. Without a circuit during component disposal or at any other time that a circuit doesn't exist, the following method calls fail and log a message that the circuit is disconnected as a : * JS interop method calls * @@ -315,8 +327,8 @@ In order to avoid logging or For the following component disposal example: -* The component implements . -* `objInstance` is an . +* The server-side component implements . +* `module` is an for a JS module. * is caught and not logged. * Optionally, you can log custom information in the `catch` statement at whatever log level you prefer. The following example doesn't log custom information because it assumes the developer doesn't care about when or where circuits are disconnected during component disposal. @@ -325,9 +337,9 @@ async ValueTask IAsyncDisposable.DisposeAsync() { try { - if (objInstance is not null) + if (module is not null) { - await objInstance.DisposeAsync(); + await module.DisposeAsync(); } } catch (JSDisconnectedException) @@ -336,7 +348,7 @@ async ValueTask IAsyncDisposable.DisposeAsync() } ``` -If you must clean up your own JS objects or execute other JS code on the client after a circuit is lost, use the [`MutationObserver`](https://developer.mozilla.org/docs/Web/API/MutationObserver) pattern in JS on the client. The [`MutationObserver`](https://developer.mozilla.org/docs/Web/API/MutationObserver) pattern allows you to run a function when an element is removed from the DOM. +If you must clean up your own JS objects or execute other JS code on the client after a circuit is lost in a server-side Blazor app, use the [`MutationObserver`](https://developer.mozilla.org/docs/Web/API/MutationObserver) pattern in JS on the client. The [`MutationObserver`](https://developer.mozilla.org/docs/Web/API/MutationObserver) pattern allows you to run a function when an element is removed from the DOM. For more information, see the following articles: diff --git a/aspnetcore/blazor/javascript-interoperability/location-of-javascript.md b/aspnetcore/blazor/javascript-interoperability/location-of-javascript.md index 8c8802ca8596..14f3ec3d270c 100644 --- a/aspnetcore/blazor/javascript-interoperability/location-of-javascript.md +++ b/aspnetcore/blazor/javascript-interoperability/location-of-javascript.md @@ -193,14 +193,9 @@ JS isolation provides the following benefits: * Imported JS no longer pollutes the global namespace. * Consumers of a library and components aren't required to import the related JS. -For more information, see . +Trap in potential cases where loss of Blazor's SignalR circuit prevents a JS interop call from disposing a module, which results an unhandled exception. -[Dynamic import with the `import()` operator](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Operators/import) is supported with ASP.NET Core and Blazor: +For more information, see the following resources: -```javascript -if ({CONDITION}) import("/additionalModule.js"); -``` - -In the preceding example, the `{CONDITION}` placeholder represents a conditional check to determine if the module should be loaded. - -For browser compatibility, see [Can I use: JavaScript modules: dynamic import](https://caniuse.com/es6-module-dynamic-import). +* [JavaScript isolation in JavaScript modules](xref:blazor/js-interop/call-javascript-from-dotnet#javascript-isolation-in-javascript-modules) +* [JavaScript interop calls without a circuit](xref:blazor/js-interop/index#javascript-interop-calls-without-a-circuit) diff --git a/aspnetcore/blazor/security/includes/httpcontext.md b/aspnetcore/blazor/security/includes/httpcontext.md index c8ada2942cd0..8a8077d1cba7 100644 --- a/aspnetcore/blazor/security/includes/httpcontext.md +++ b/aspnetcore/blazor/security/includes/httpcontext.md @@ -21,6 +21,6 @@ For scenarios where the is required The recommended approach for passing request state to the Blazor app is through root component parameters during the app's initial rendering. Alternatively, the app can copy the data into a scoped service in the root component's initialization lifecycle event for use across the app. For more information, see . -A critical aspect of server-side Blazor security is that the user attached to a given circuit might become updated at some point after the Blazor circuit is established but the ***isn't updated***. For more information on addressing this situation with custom services, see . +A critical aspect of server-side Blazor security is that the user attached to a given circuit might become updated at some point after Blazor's SignalR circuit is established but the ***isn't updated***. For more information on addressing this situation with custom services, see . :::moniker-end diff --git a/aspnetcore/blazor/security/server/index.md b/aspnetcore/blazor/security/server/index.md index 83f32d7800f1..7cff19b1384c 100644 --- a/aspnetcore/blazor/security/server/index.md +++ b/aspnetcore/blazor/security/server/index.md @@ -20,7 +20,7 @@ The authentication context is only established when the app starts, which is whe If the app must capture users for custom services or react to updates to the user, see . -Blazor differs from a traditional server-rendered web apps that make new HTTP requests with cookies on every page navigation. Authentication is checked during navigation events. However, cookies aren't involved. Cookies are only sent when making an HTTP request to a server, which isn't what happens when the user navigates in a Blazor app. During navigation, the user's authentication state is checked within the Blazor circuit, which you can update at any time on the server using a revalidating `AuthenticationStateProvider`](#additional-authentication-state-providers). +Blazor differs from a traditional server-rendered web apps that make new HTTP requests with cookies on every page navigation. Authentication is checked during navigation events. However, cookies aren't involved. Cookies are only sent when making an HTTP request to a server, which isn't what happens when the user navigates in a Blazor app. During navigation, the user's authentication state is checked within Blazor's SignalR circuit, which you can update at any time on the server using a revalidating `AuthenticationStateProvider`](#additional-authentication-state-providers). > [!IMPORTANT] > Implementing a custom `NavigationManager` to achieve authentication validation during navigation isn't recommended. If the app must execute custom authentication state logic during navigation, use a [custom `AuthenticationStateProvider`](xref:blazor/security/authentication-state#implement-a-custom-authenticationstateprovider). diff --git a/aspnetcore/includes/out-of-support.md b/aspnetcore/includes/out-of-support.md index 684454080bbf..5be552f28089 100644 --- a/aspnetcore/includes/out-of-support.md +++ b/aspnetcore/includes/out-of-support.md @@ -1,3 +1,2 @@ > [!WARNING] -> This version of ASP.NET Core is no longer supported. For more information, see [.NET and .NET Core Support Policy](https://dotnet.microsoft.com/platform/support/policy/dotnet-core). For the current release, see the [.NET 8 version of this article](?view=aspnetcore-8.0&preserve-view=true). - +> This version of ASP.NET Core is no longer supported. For more information, see the [.NET and .NET Core Support Policy](https://dotnet.microsoft.com/platform/support/policy/dotnet-core). For the current release, see the [.NET 9 version of this article](?view=aspnetcore-9.0&preserve-view=true).