From d1da4b63e20ca4dccc59afc09ac0a634e553e517 Mon Sep 17 00:00:00 2001 From: guardrex <1622880+guardrex@users.noreply.github.com> Date: Mon, 10 Apr 2023 19:30:12 -0400 Subject: [PATCH 01/10] Dispatch exceptions to the sync context --- aspnetcore/blazor/components/index.md | 83 +++++++++++++++++++++++++++ 1 file changed, 83 insertions(+) diff --git a/aspnetcore/blazor/components/index.md b/aspnetcore/blazor/components/index.md index 61bffbe5f7cc..d23be8fafcad 100644 --- a/aspnetcore/blazor/components/index.md +++ b/aspnetcore/blazor/components/index.md @@ -783,6 +783,89 @@ In the preceding example: > [!IMPORTANT] > If a Razor component defines an event that's triggered from a background thread, the component might be required to capture and restore the execution context () at the time the handler is registered. For more information, see [Calling `InvokeAsync(StateHasChanged)` causes page to fallback to default culture (dotnet/aspnetcore #28521)](https://github.com/dotnet/aspnetcore/issues/28521). +:::moniker range=">= aspnetcore-8.0" + +### Dispatch exceptions to Blazor's synchronization context + +Use `DispatchExceptionAsync` to process caught exceptions thrown outside of Blazor's synchronization context (for example, outside of Blazor's lifecycle events). This permits the app's code to treat the exceptions as through they're lifecycle method exceptions. Thereafter, Blazor's error handling approaches are supported, such as [error boundaries](xref:blazor/fundamentals/handle-errors#error-boundaries). + +To dispatch exceptions to Blazor's synchronization context, use a `try-catch` block to pass the exception to `DispatchExceptionAsync` and await the result: + +```csharp +try +{ + await InvokeAsync(() => + { + ... + }); +} +catch (Exception ex) +{ + await DispatchExceptionAsync(ex); +} +``` + +For an example use of `DispatchExceptionAsync` API, implement the timer notification example in the [Invoke component methods externally to update state](#invoke-component-methods-externally-to-update-state) section. The example uses a timer outside of Blazor's synchronization context, where an exception normally doesn't affect Blazor's error handling mechanisms, such as an [error boundary](xref:blazor/fundamentals/handle-errors#error-boundaries). + +First, change the code in `TimerService.cs` to create an artificial exception outside of Blazor's synchronization context. In the `while (await timer.WaitForNextTickAsync())` loop of `TimerService.cs`, throw an exception when the `elapsedCount` reaches a value of `2`: + +```csharp +if (elapsedCount == 2) +{ + throw new Exception("I threw an exception! Somebody help me!"); +} +``` + +Place an [error boundary](xref:blazor/fundamentals/handle-errors#error-boundaries) in the app's main layout. + +`Shared/MainLayout.razor`: + +```razor +
+ + + @Body + + + + + +
+``` + +Normally, the preceding error boundary doesn't react to unhandled exceptions thrown outside of Blazor's synchronization context. + +Change the `OnNotify` method of the `ReceiveNotification` component (`Pages/ReceiveNotification.razor`): + +* Wrap the call to `InvokeAsync` in a `try-catch` block. +* Pass any to `DispatchExceptionAsync` and await the result. + +```csharp +public async Task OnNotify(string key, int value) +{ + try + { + await InvokeAsync(() => + { + lastNotification = (key, value); + StateHasChanged(); + }); + } + catch (Exception ex) + { + await DispatchExceptionAsync(ex); + } +} +``` + +When the timer service executes and reaches a count of two, the unhandled exception is dispatched to the Razor component, which in turn triggers the error boundary to display the error content: + +> :::no-loc text="Oh, dear! Oh, my! - George Takei"::: + +:::moniker-end + ## Use `@key` to control the preservation of elements and components When rendering a list of elements or components and the elements or components subsequently change, Blazor must decide which of the previous elements or components are retained and how model objects should map to them. Normally, this process is automatic and sufficient for general rendering, but there are often cases where controlling the process using the [`@key`][5] directive attribute is required. From eabd9340957f703a950716b211148e02492195c5 Mon Sep 17 00:00:00 2001 From: guardrex <1622880+guardrex@users.noreply.github.com> Date: Mon, 10 Apr 2023 19:40:00 -0400 Subject: [PATCH 02/10] Updates --- aspnetcore/blazor/components/index.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/aspnetcore/blazor/components/index.md b/aspnetcore/blazor/components/index.md index d23be8fafcad..33b34d0ba8c7 100644 --- a/aspnetcore/blazor/components/index.md +++ b/aspnetcore/blazor/components/index.md @@ -783,10 +783,14 @@ In the preceding example: > [!IMPORTANT] > If a Razor component defines an event that's triggered from a background thread, the component might be required to capture and restore the execution context () at the time the handler is registered. For more information, see [Calling `InvokeAsync(StateHasChanged)` causes page to fallback to default culture (dotnet/aspnetcore #28521)](https://github.com/dotnet/aspnetcore/issues/28521). +:::moniker-end + :::moniker range=">= aspnetcore-8.0" ### Dispatch exceptions to Blazor's synchronization context + + Use `DispatchExceptionAsync` to process caught exceptions thrown outside of Blazor's synchronization context (for example, outside of Blazor's lifecycle events). This permits the app's code to treat the exceptions as through they're lifecycle method exceptions. Thereafter, Blazor's error handling approaches are supported, such as [error boundaries](xref:blazor/fundamentals/handle-errors#error-boundaries). To dispatch exceptions to Blazor's synchronization context, use a `try-catch` block to pass the exception to `DispatchExceptionAsync` and await the result: @@ -866,6 +870,8 @@ When the timer service executes and reaches a count of two, the unhandled except :::moniker-end +:::moniker range=">= aspnetcore-7.0" + ## Use `@key` to control the preservation of elements and components When rendering a list of elements or components and the elements or components subsequently change, Blazor must decide which of the previous elements or components are retained and how model objects should map to them. Normally, this process is automatic and sufficient for general rendering, but there are often cases where controlling the process using the [`@key`][5] directive attribute is required. From 14a49e132e70b0abf0c2025a2a66a4d2b411f79b Mon Sep 17 00:00:00 2001 From: guardrex <1622880+guardrex@users.noreply.github.com> Date: Tue, 11 Apr 2023 08:51:33 -0400 Subject: [PATCH 03/10] Updates --- aspnetcore/blazor/components/index.md | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/aspnetcore/blazor/components/index.md b/aspnetcore/blazor/components/index.md index 33b34d0ba8c7..5006cab74ef5 100644 --- a/aspnetcore/blazor/components/index.md +++ b/aspnetcore/blazor/components/index.md @@ -789,9 +789,10 @@ In the preceding example: ### Dispatch exceptions to Blazor's synchronization context - +Use `ComponentBase.DispatchExceptionAsync` in Razor components to process exceptions thrown outside of Blazor's synchronization context. This permits the app's code to treat the exceptions as through they're lifecycle method exceptions. Thereafter, Blazor's error handling mechanisms, such as [error boundaries](xref:blazor/fundamentals/handle-errors#error-boundaries), can process the exceptions. -Use `DispatchExceptionAsync` to process caught exceptions thrown outside of Blazor's synchronization context (for example, outside of Blazor's lifecycle events). This permits the app's code to treat the exceptions as through they're lifecycle method exceptions. Thereafter, Blazor's error handling approaches are supported, such as [error boundaries](xref:blazor/fundamentals/handle-errors#error-boundaries). +> [!NOTE] +> `ComponentBase.DispatchExceptionAsync` is used in Razor component files (`.razor`) that inherit from . When creating components that [implement directly](#component-classes), use `RenderHandle.DispatchExceptionAsync`. To dispatch exceptions to Blazor's synchronization context, use a `try-catch` block to pass the exception to `DispatchExceptionAsync` and await the result: @@ -809,9 +810,9 @@ catch (Exception ex) } ``` -For an example use of `DispatchExceptionAsync` API, implement the timer notification example in the [Invoke component methods externally to update state](#invoke-component-methods-externally-to-update-state) section. The example uses a timer outside of Blazor's synchronization context, where an exception normally doesn't affect Blazor's error handling mechanisms, such as an [error boundary](xref:blazor/fundamentals/handle-errors#error-boundaries). +For an example use of `DispatchExceptionAsync` API, implement the timer notification example in the [Invoke component methods externally to update state](#invoke-component-methods-externally-to-update-state) section. The example uses a timer outside of Blazor's synchronization context, where an exception normally doesn't reach Blazor's synchronization context and isn't processed by Blazor's error handling mechanisms, such as an [error boundary](xref:blazor/fundamentals/handle-errors#error-boundaries). -First, change the code in `TimerService.cs` to create an artificial exception outside of Blazor's synchronization context. In the `while (await timer.WaitForNextTickAsync())` loop of `TimerService.cs`, throw an exception when the `elapsedCount` reaches a value of `2`: +First, change the code in `TimerService.cs` to create an artificial exception outside of Blazor's synchronization context. In the `while` loop of `TimerService.cs`, throw an exception when the `elapsedCount` reaches a value of `2`: ```csharp if (elapsedCount == 2) @@ -839,11 +840,11 @@ Place an [error boundary](xref:blazor/fundamentals/handle-errors#error-boundarie ``` -Normally, the preceding error boundary doesn't react to unhandled exceptions thrown outside of Blazor's synchronization context. +Normally, the preceding error boundary doesn't react to unhandled exceptions thrown outside of Blazor's synchronization context. If you run the app at this point, the exception is thrown when the elapsed count reaches a value of two, but the error boundary doesn't show the error content. Change the `OnNotify` method of the `ReceiveNotification` component (`Pages/ReceiveNotification.razor`): -* Wrap the call to `InvokeAsync` in a `try-catch` block. +* Wrap the call to in a `try-catch` block. * Pass any to `DispatchExceptionAsync` and await the result. ```csharp From 9bee081b2ab07145552b5dbb438e225e2b82ea9a Mon Sep 17 00:00:00 2001 From: guardrex <1622880+guardrex@users.noreply.github.com> Date: Tue, 11 Apr 2023 09:05:49 -0400 Subject: [PATCH 04/10] Updates --- aspnetcore/blazor/components/index.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/aspnetcore/blazor/components/index.md b/aspnetcore/blazor/components/index.md index 5006cab74ef5..d6660764cf88 100644 --- a/aspnetcore/blazor/components/index.md +++ b/aspnetcore/blazor/components/index.md @@ -810,9 +810,9 @@ catch (Exception ex) } ``` -For an example use of `DispatchExceptionAsync` API, implement the timer notification example in the [Invoke component methods externally to update state](#invoke-component-methods-externally-to-update-state) section. The example uses a timer outside of Blazor's synchronization context, where an exception normally doesn't reach Blazor's synchronization context and isn't processed by Blazor's error handling mechanisms, such as an [error boundary](xref:blazor/fundamentals/handle-errors#error-boundaries). +For an example use of `DispatchExceptionAsync` API, implement the timer notification example in the [Invoke component methods externally to update state](#invoke-component-methods-externally-to-update-state) section. The example uses a timer outside of Blazor's synchronization context, where an unhandled exception normally doesn't reach Blazor's synchronization context and isn't processed by Blazor's error handling mechanisms, such as an [error boundary](xref:blazor/fundamentals/handle-errors#error-boundaries). -First, change the code in `TimerService.cs` to create an artificial exception outside of Blazor's synchronization context. In the `while` loop of `TimerService.cs`, throw an exception when the `elapsedCount` reaches a value of `2`: +First, change the code in `TimerService.cs` to create an artificial exception outside of Blazor's synchronization context. In the `while` loop of `TimerService.cs`, throw an exception when the `elapsedCount` reaches a value of two: ```csharp if (elapsedCount == 2) From 2ce23ee8db2d8fb3b02045885570895ca0acb061 Mon Sep 17 00:00:00 2001 From: Luke Latham <1622880+guardrex@users.noreply.github.com> Date: Wed, 19 Apr 2023 16:56:39 -0400 Subject: [PATCH 05/10] Update aspnetcore/blazor/components/index.md --- aspnetcore/blazor/components/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aspnetcore/blazor/components/index.md b/aspnetcore/blazor/components/index.md index d6660764cf88..b7c2e6d7f235 100644 --- a/aspnetcore/blazor/components/index.md +++ b/aspnetcore/blazor/components/index.md @@ -840,7 +840,7 @@ Place an [error boundary](xref:blazor/fundamentals/handle-errors#error-boundarie ``` -Normally, the preceding error boundary doesn't react to unhandled exceptions thrown outside of Blazor's synchronization context. If you run the app at this point, the exception is thrown when the elapsed count reaches a value of two, but the error boundary doesn't show the error content. +If you run the app at this point, the exception is thrown when the elapsed count reaches a value of two. However, the UI doesn't change. The error boundary doesn't show the error content. Change the `OnNotify` method of the `ReceiveNotification` component (`Pages/ReceiveNotification.razor`): From c322fef845754021264868c6ee86ce4f9cff6558 Mon Sep 17 00:00:00 2001 From: Luke Latham <1622880+guardrex@users.noreply.github.com> Date: Wed, 19 Apr 2023 17:03:37 -0400 Subject: [PATCH 06/10] Updates --- aspnetcore/blazor/components/index.md | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/aspnetcore/blazor/components/index.md b/aspnetcore/blazor/components/index.md index b7c2e6d7f235..302104716588 100644 --- a/aspnetcore/blazor/components/index.md +++ b/aspnetcore/blazor/components/index.md @@ -810,7 +810,13 @@ catch (Exception ex) } ``` -For an example use of `DispatchExceptionAsync` API, implement the timer notification example in the [Invoke component methods externally to update state](#invoke-component-methods-externally-to-update-state) section. The example uses a timer outside of Blazor's synchronization context, where an unhandled exception normally doesn't reach Blazor's synchronization context and isn't processed by Blazor's error handling mechanisms, such as an [error boundary](xref:blazor/fundamentals/handle-errors#error-boundaries). +For an example use of `DispatchExceptionAsync` API, implement the timer notification example in the [Invoke component methods externally to update state](#invoke-component-methods-externally-to-update-state) section. In a Blazor app, add the following files from the timer notification example and register the services in `Program.cs` as the text explains: + +* `TimerService.cs` +* `NotifierService.cs` +* `Pages/ReceiveNotifications.razor` + +The example uses a timer outside of Blazor's synchronization context, where an unhandled exception normally doesn't reach Blazor's synchronization context and isn't processed by Blazor's error handling mechanisms, such as an [error boundary](xref:blazor/fundamentals/handle-errors#error-boundaries). First, change the code in `TimerService.cs` to create an artificial exception outside of Blazor's synchronization context. In the `while` loop of `TimerService.cs`, throw an exception when the `elapsedCount` reaches a value of two: From cbdd4cde7634b8f1ce4ab50dfe5c9795fdd7207d Mon Sep 17 00:00:00 2001 From: guardrex <1622880+guardrex@users.noreply.github.com> Date: Mon, 8 May 2023 09:12:52 -0400 Subject: [PATCH 07/10] Updates --- aspnetcore/blazor/components/index.md | 92 +----------- .../blazor/fundamentals/handle-errors.md | 133 ++++++++++++++++++ 2 files changed, 134 insertions(+), 91 deletions(-) diff --git a/aspnetcore/blazor/components/index.md b/aspnetcore/blazor/components/index.md index 302104716588..f7d9d3fcac88 100644 --- a/aspnetcore/blazor/components/index.md +++ b/aspnetcore/blazor/components/index.md @@ -783,102 +783,12 @@ In the preceding example: > [!IMPORTANT] > If a Razor component defines an event that's triggered from a background thread, the component might be required to capture and restore the execution context () at the time the handler is registered. For more information, see [Calling `InvokeAsync(StateHasChanged)` causes page to fallback to default culture (dotnet/aspnetcore #28521)](https://github.com/dotnet/aspnetcore/issues/28521). -:::moniker-end - :::moniker range=">= aspnetcore-8.0" -### Dispatch exceptions to Blazor's synchronization context - -Use `ComponentBase.DispatchExceptionAsync` in Razor components to process exceptions thrown outside of Blazor's synchronization context. This permits the app's code to treat the exceptions as through they're lifecycle method exceptions. Thereafter, Blazor's error handling mechanisms, such as [error boundaries](xref:blazor/fundamentals/handle-errors#error-boundaries), can process the exceptions. - -> [!NOTE] -> `ComponentBase.DispatchExceptionAsync` is used in Razor component files (`.razor`) that inherit from . When creating components that [implement directly](#component-classes), use `RenderHandle.DispatchExceptionAsync`. - -To dispatch exceptions to Blazor's synchronization context, use a `try-catch` block to pass the exception to `DispatchExceptionAsync` and await the result: - -```csharp -try -{ - await InvokeAsync(() => - { - ... - }); -} -catch (Exception ex) -{ - await DispatchExceptionAsync(ex); -} -``` - -For an example use of `DispatchExceptionAsync` API, implement the timer notification example in the [Invoke component methods externally to update state](#invoke-component-methods-externally-to-update-state) section. In a Blazor app, add the following files from the timer notification example and register the services in `Program.cs` as the text explains: - -* `TimerService.cs` -* `NotifierService.cs` -* `Pages/ReceiveNotifications.razor` - -The example uses a timer outside of Blazor's synchronization context, where an unhandled exception normally doesn't reach Blazor's synchronization context and isn't processed by Blazor's error handling mechanisms, such as an [error boundary](xref:blazor/fundamentals/handle-errors#error-boundaries). - -First, change the code in `TimerService.cs` to create an artificial exception outside of Blazor's synchronization context. In the `while` loop of `TimerService.cs`, throw an exception when the `elapsedCount` reaches a value of two: - -```csharp -if (elapsedCount == 2) -{ - throw new Exception("I threw an exception! Somebody help me!"); -} -``` - -Place an [error boundary](xref:blazor/fundamentals/handle-errors#error-boundaries) in the app's main layout. - -`Shared/MainLayout.razor`: - -```razor -
- - - @Body - - - - - -
-``` - -If you run the app at this point, the exception is thrown when the elapsed count reaches a value of two. However, the UI doesn't change. The error boundary doesn't show the error content. - -Change the `OnNotify` method of the `ReceiveNotification` component (`Pages/ReceiveNotification.razor`): - -* Wrap the call to in a `try-catch` block. -* Pass any to `DispatchExceptionAsync` and await the result. - -```csharp -public async Task OnNotify(string key, int value) -{ - try - { - await InvokeAsync(() => - { - lastNotification = (key, value); - StateHasChanged(); - }); - } - catch (Exception ex) - { - await DispatchExceptionAsync(ex); - } -} -``` - -When the timer service executes and reaches a count of two, the unhandled exception is dispatched to the Razor component, which in turn triggers the error boundary to display the error content: - -> :::no-loc text="Oh, dear! Oh, my! - George Takei"::: +To dispatch caught exceptions from the background `TimerService` to the component to treat the exceptions like normal lifecycle event exceptions, see [Handle caught exceptions outside of a Razor component's lifecycle](xref:blazor/fundamentals/handle-errors#handle-caught-exceptions-outside-of-a-razor-components-lifecycle) in the *Handle errors* article. :::moniker-end -:::moniker range=">= aspnetcore-7.0" - ## Use `@key` to control the preservation of elements and components When rendering a list of elements or components and the elements or components subsequently change, Blazor must decide which of the previous elements or components are retained and how model objects should map to them. Normally, this process is automatic and sufficient for general rendering, but there are often cases where controlling the process using the [`@key`][5] directive attribute is required. diff --git a/aspnetcore/blazor/fundamentals/handle-errors.md b/aspnetcore/blazor/fundamentals/handle-errors.md index ce5326978d0d..e9e613bc4459 100644 --- a/aspnetcore/blazor/fundamentals/handle-errors.md +++ b/aspnetcore/blazor/fundamentals/handle-errors.md @@ -66,6 +66,139 @@ In a Blazor WebAssembly app, customize the experience in the `wwwroot/index.html The `blazor-error-ui` element is normally hidden due to the presence of the `display: none` style of the `blazor-error-ui` CSS class in the site's stylesheet (`wwwroot/css/site.css` for Blazor Server or `wwwroot/css/app.css` for Blazor WebAssembly). When an error occurs, the framework applies `display: block` to the element. +:::moniker range=">= aspnetcore-8.0" + +## Handle caught exceptions outside of a Razor component's lifecycle + +Use `ComponentBase.DispatchExceptionAsync` in a Razor component to process exceptions thrown outside of the component's lifecycle call stack. This permits the component's code to treat exceptions as through they're lifecycle method exceptions. Thereafter, Blazor's error handling mechanisms, such as [error boundaries](xref:blazor/fundamentals/handle-errors#error-boundaries), can process the exceptions. + +> [!NOTE] +> `ComponentBase.DispatchExceptionAsync` is used in Razor component files (`.razor`) that inherit from . When creating components that [implement directly](xref:blazor/components/index#component-classes), use `RenderHandle.DispatchExceptionAsync`. + +To handle caught exceptions outside of a Razor component's lifecycle, pass the exception to `DispatchExceptionAsync` and await the result: + +```csharp +try +{ + ... +} +catch (Exception ex) +{ + await DispatchExceptionAsync(ex); +} +``` + +A common scenario is if a component wants to start an asynchronous operation but doesn't await a . If the operation fails, you may still want the component to treat the failure as a component lifecycle exception for the following example goals: + +* Put the component into a faulted state, for example, to trigger an [error boundary](xref:blazor/fundamentals/handle-errors#error-boundaries). +* Terminate a Blazor Server app's circuit if there's no error boundary. +* Trigger the same logging that occurs for lifecycle exceptions. + +In the following example, the user selects the **Send report** button to trigger a background method, `ReportSender.SendAsync`, that sends a report. In most cases, a component awaits the of an asynchronous call and updates the UI to indicate the operation completed. In the following example, the `SendReport` method doesn't await a and doesn't report the result to the user. Because the component intentionally discards the in `SendReport`, any asynchronous failures occur off of the normal lifecycle call stack, hence aren't seen by Blazor: + +```razor + + +@code { + private void SendReport() + { + _ = ReportSender.SendAsync(); + } +} +``` + +To treat failures like lifecycle method exceptions, explicitly dispatch exceptions back to the component with `DispatchExceptionAsync`, as the following example demonstrates: + +```razor + + +@code { + private void SendReport() + { + _ = SendReportAsync(); + } + + private async Task SendReportAsync() + { + try + { + await ReportSender.SendAsync(); + } + catch (Exception ex) + { + await DispatchExceptionAsync(ex); + } + } +} +``` + +For a working demonstration of `DispatchExceptionAsync`, implement the timer notification example in the [Invoke component methods externally to update state](xref:blazor/components/index#invoke-component-methods-externally-to-update-state) section of the *Components* overview article. In a Blazor app, add the following files from the timer notification example and register the services in `Program.cs` as the section explains: + +* `TimerService.cs` +* `NotifierService.cs` +* `Pages/ReceiveNotifications.razor` + +The example uses a timer outside of a Razor component's lifecycle, where an unhandled exception normally isn't processed by Blazor's error handling mechanisms, such as an [error boundary](xref:blazor/fundamentals/handle-errors#error-boundaries). + +First, change the code in `TimerService.cs` to create an artificial exception outside of the component's lifecycle. In the `while` loop of `TimerService.cs`, throw an exception when the `elapsedCount` reaches a value of two: + +```csharp +if (elapsedCount == 2) +{ + throw new Exception("I threw an exception! Somebody help me!"); +} +``` + +Place an [error boundary](xref:blazor/fundamentals/handle-errors#error-boundaries) in the app's main layout. Replace the `
...
` markup with the following markup. + +`Shared/MainLayout.razor`: + +```razor +
+ + + @Body + + + + + +
+``` + +If you run the app at this point, the exception is thrown when the elapsed count reaches a value of two. However, the UI doesn't change. The error boundary doesn't show the error content. + +Change the `OnNotify` method of the `ReceiveNotification` component (`Pages/ReceiveNotification.razor`): + +* Wrap the call to in a `try-catch` block. +* Pass any to `DispatchExceptionAsync` and await the result. + +```csharp +public async Task OnNotify(string key, int value) +{ + try + { + await InvokeAsync(() => + { + lastNotification = (key, value); + StateHasChanged(); + }); + } + catch (Exception ex) + { + await DispatchExceptionAsync(ex); + } +} +``` + +When the timer service executes and reaches a count of two, the exception is dispatched to the Razor component, which in turn triggers the error boundary to display the error content of the `` in the `MainLayout` component (`Shared/MainLayout.razor`): + +> :::no-loc text="Oh, dear! Oh, my! - George Takei"::: + +:::moniker-end + ## Detailed circuit errors *This section applies to Blazor Server apps.* From eef0049e76d862a736aef46eed6beeb66ca7e894 Mon Sep 17 00:00:00 2001 From: guardrex <1622880+guardrex@users.noreply.github.com> Date: Mon, 8 May 2023 09:32:40 -0400 Subject: [PATCH 08/10] Updates --- aspnetcore/blazor/fundamentals/handle-errors.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/aspnetcore/blazor/fundamentals/handle-errors.md b/aspnetcore/blazor/fundamentals/handle-errors.md index e9e613bc4459..9a681038ef1b 100644 --- a/aspnetcore/blazor/fundamentals/handle-errors.md +++ b/aspnetcore/blazor/fundamentals/handle-errors.md @@ -66,6 +66,8 @@ In a Blazor WebAssembly app, customize the experience in the `wwwroot/index.html The `blazor-error-ui` element is normally hidden due to the presence of the `display: none` style of the `blazor-error-ui` CSS class in the site's stylesheet (`wwwroot/css/site.css` for Blazor Server or `wwwroot/css/app.css` for Blazor WebAssembly). When an error occurs, the framework applies `display: block` to the element. +:::moniker-end + :::moniker range=">= aspnetcore-8.0" ## Handle caught exceptions outside of a Razor component's lifecycle From ae26b5a4a68ffbaf9a18740f729510c501ccd6c1 Mon Sep 17 00:00:00 2001 From: guardrex <1622880+guardrex@users.noreply.github.com> Date: Mon, 8 May 2023 09:43:55 -0400 Subject: [PATCH 09/10] Updates --- aspnetcore/blazor/components/index.md | 4 ++++ aspnetcore/blazor/fundamentals/handle-errors.md | 2 -- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/aspnetcore/blazor/components/index.md b/aspnetcore/blazor/components/index.md index f7d9d3fcac88..db91bef05d6b 100644 --- a/aspnetcore/blazor/components/index.md +++ b/aspnetcore/blazor/components/index.md @@ -783,12 +783,16 @@ In the preceding example: > [!IMPORTANT] > If a Razor component defines an event that's triggered from a background thread, the component might be required to capture and restore the execution context () at the time the handler is registered. For more information, see [Calling `InvokeAsync(StateHasChanged)` causes page to fallback to default culture (dotnet/aspnetcore #28521)](https://github.com/dotnet/aspnetcore/issues/28521). +:::moniker-end + :::moniker range=">= aspnetcore-8.0" To dispatch caught exceptions from the background `TimerService` to the component to treat the exceptions like normal lifecycle event exceptions, see [Handle caught exceptions outside of a Razor component's lifecycle](xref:blazor/fundamentals/handle-errors#handle-caught-exceptions-outside-of-a-razor-components-lifecycle) in the *Handle errors* article. :::moniker-end +:::moniker range=">= aspnetcore-7.0" + ## Use `@key` to control the preservation of elements and components When rendering a list of elements or components and the elements or components subsequently change, Blazor must decide which of the previous elements or components are retained and how model objects should map to them. Normally, this process is automatic and sufficient for general rendering, but there are often cases where controlling the process using the [`@key`][5] directive attribute is required. diff --git a/aspnetcore/blazor/fundamentals/handle-errors.md b/aspnetcore/blazor/fundamentals/handle-errors.md index 9a681038ef1b..e9e613bc4459 100644 --- a/aspnetcore/blazor/fundamentals/handle-errors.md +++ b/aspnetcore/blazor/fundamentals/handle-errors.md @@ -66,8 +66,6 @@ In a Blazor WebAssembly app, customize the experience in the `wwwroot/index.html The `blazor-error-ui` element is normally hidden due to the presence of the `display: none` style of the `blazor-error-ui` CSS class in the site's stylesheet (`wwwroot/css/site.css` for Blazor Server or `wwwroot/css/app.css` for Blazor WebAssembly). When an error occurs, the framework applies `display: block` to the element. -:::moniker-end - :::moniker range=">= aspnetcore-8.0" ## Handle caught exceptions outside of a Razor component's lifecycle From c969e6921acbe0ddf72a21ffb8d116c2352ee66b Mon Sep 17 00:00:00 2001 From: Luke Latham <1622880+guardrex@users.noreply.github.com> Date: Mon, 8 May 2023 10:05:07 -0400 Subject: [PATCH 10/10] Update aspnetcore/blazor/fundamentals/handle-errors.md Co-authored-by: Steve Sanderson --- aspnetcore/blazor/fundamentals/handle-errors.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aspnetcore/blazor/fundamentals/handle-errors.md b/aspnetcore/blazor/fundamentals/handle-errors.md index e9e613bc4459..0655584f143b 100644 --- a/aspnetcore/blazor/fundamentals/handle-errors.md +++ b/aspnetcore/blazor/fundamentals/handle-errors.md @@ -70,7 +70,7 @@ The `blazor-error-ui` element is normally hidden due to the presence of the `dis ## Handle caught exceptions outside of a Razor component's lifecycle -Use `ComponentBase.DispatchExceptionAsync` in a Razor component to process exceptions thrown outside of the component's lifecycle call stack. This permits the component's code to treat exceptions as through they're lifecycle method exceptions. Thereafter, Blazor's error handling mechanisms, such as [error boundaries](xref:blazor/fundamentals/handle-errors#error-boundaries), can process the exceptions. +Use `ComponentBase.DispatchExceptionAsync` in a Razor component to process exceptions thrown outside of the component's lifecycle call stack. This permits the component's code to treat exceptions as though they're lifecycle method exceptions. Thereafter, Blazor's error handling mechanisms, such as [error boundaries](xref:blazor/fundamentals/handle-errors#error-boundaries), can process the exceptions. > [!NOTE] > `ComponentBase.DispatchExceptionAsync` is used in Razor component files (`.razor`) that inherit from . When creating components that [implement directly](xref:blazor/components/index#component-classes), use `RenderHandle.DispatchExceptionAsync`.