diff --git a/aspnetcore/blazor/components/lifecycle.md b/aspnetcore/blazor/components/lifecycle.md index 8bc35d425b2c..1b4f10b0977b 100644 --- a/aspnetcore/blazor/components/lifecycle.md +++ b/aspnetcore/blazor/components/lifecycle.md @@ -197,6 +197,8 @@ protected override async Task OnInitializedAsync() It isn't necessary to call unless a custom base class is used with custom logic. For more information, see the [Base class lifecycle methods](#base-class-lifecycle-methods) section. +A component must ensure that it's in a valid state for rendering when returns from awaiting a potentially incomplete . If the method returns an incomplete , the part of the method that completes synchronously must leave the component in a valid state for rendering. For more information, see the introductory remarks of and [Component disposal with `IDisposable` and `IAsyncDisposable` (this article)](#component-disposal-with-idisposable-and-iasyncdisposable). + Blazor apps that prerender their content on the server call *twice*: * Once when the component is initially rendered statically as part of the page. @@ -216,7 +218,7 @@ To prevent developer code in unless a custom base class is used with custom logic. For more information, see the [Base class lifecycle methods](#base-class-lifecycle-methods) section. -If event handlers are provided in developer code, unhook them on disposal. For more information, see the [Component disposal with `IDisposable` `IAsyncDisposable`](#component-disposal-with-idisposable-and-iasyncdisposable) section. +If event handlers are provided in developer code, unhook them on disposal. For more information, see the [Component disposal with `IDisposable` and `IAsyncDisposable`](#component-disposal-with-idisposable-and-iasyncdisposable) section. + +If a disposable component doesn't use a , and should check if the component is disposed. If returns an incomplete , the component must ensure that the part of the method that completes synchronously leaves the component in a valid state for rendering. For more information, see the introductory remarks of and [Component disposal with `IDisposable` and `IAsyncDisposable` (this article)](#component-disposal-with-idisposable-and-iasyncdisposable). For more information on route parameters and constraints, see . @@ -422,7 +426,7 @@ Even if you return a from and aren't called. 1. When the Blazor script (`blazor.{server|webassembly|web}.js`) starts in the browser, the component is restarted in an interactive rendering mode. After a component is restarted, and **are** called because the app isn't in the prerendering phase any longer. -If event handlers are provided in developer code, unhook them on disposal. For more information, see the [Component disposal with `IDisposable` `IAsyncDisposable`](#component-disposal-with-idisposable-and-iasyncdisposable) section. +If event handlers are provided in developer code, unhook them on disposal. For more information, see the [Component disposal with `IDisposable` and `IAsyncDisposable`](#component-disposal-with-idisposable-and-iasyncdisposable) section. ## Base class lifecycle methods @@ -763,12 +767,14 @@ Although the content in this section focuses on Blazor Server and stateful Signa ## Component disposal with `IDisposable` and `IAsyncDisposable` -If a component implements or , the framework calls for resource disposal when the component is removed from the UI. Don't rely on the exact timing of when these methods are executed. For example, can be triggered before or after an asynchronous awaited in [`OnInitalizedAsync`](#component-initialization-oninitializedasync) is called or completes. Also, object disposal code shouldn't assume that objects created during initialization or other lifecycle methods exist. +If a component implements or , the framework calls for resource disposal when the component is removed from the UI. Don't rely on the exact timing of when these methods are executed. For example, can be triggered before or after an asynchronous awaited in [`OnInitalizedAsync`](#component-initialization-oninitializedasync) or [`OnParametersSetAsync`](#after-parameters-are-set-onparameterssetasync) is called or completes. Also, object disposal code shouldn't assume that objects created during initialization or other lifecycle methods exist. Components shouldn't need to implement and simultaneously. If both are implemented, the framework only executes the asynchronous overload. Developer code must ensure that implementations don't take a long time to complete. +For more information, see the introductory remarks of . + ### Disposal of JavaScript interop object references Examples throughout the [JavaScript (JS) interop articles](xref:blazor/js-interop/index) demonstrate typical object disposal patterns: @@ -950,6 +956,7 @@ The following component: For more information, see: +* * [Cleaning up unmanaged resources (.NET documentation)](/dotnet/standard/garbage-collection/unmanaged) * [Null-conditional operators ?. and ?[]](/dotnet/csharp/language-reference/operators/member-access-operators#null-conditional-operators--and-) diff --git a/aspnetcore/blazor/components/synchronization-context.md b/aspnetcore/blazor/components/synchronization-context.md index d962ae38765d..b4ecb1542f4d 100644 --- a/aspnetcore/blazor/components/synchronization-context.md +++ b/aspnetcore/blazor/components/synchronization-context.md @@ -16,6 +16,18 @@ Blazor uses a synchronization context (. [Lifecycle methods](xref:blazor/components/lifecycle) or [component disposal methods](xref:blazor/components/lifecycle#component-disposal-with-idisposable-and-iasyncdisposable) may be called before the asynchronous control flow resumes after awaiting a to complete. Therefore, a component must ensure that it's in a valid state before awaiting a potentially incomplete . In particular, a component must ensure that it's in a valid state for rendering when or return. If either of these methods return an incomplete , they must ensure that the part of the method that completes synchronously leaves the component in a valid state for rendering. + +Another implication of re-entrant components is that a method can't defer a until after the method returns by passing it to . Calling may only defer the until the next [`await` operator](/dotnet/csharp/language-reference/operators/await) is reached. + +Components might implement or to call asynchronous methods using a from a that's canceled when the component is disposed. However, this really depends on the scenario. It's up to the component author to determine whether that's the correct behavior. For example, if implementing a `SaveButton` component that persists some local data to a database when a save button is selected, the component author may indeed intend to discard the changes if the user selects the button and quickly navigates to another page, which could dispose the component before the asynchronous save completes. + +A disposable component can check for disposal after awaiting any that doesn't receive the component's . Incomplete s may also prevent garbage collection of a disposed component. + + ignores exceptions caused by cancellation (more precisely, it ignores *all* exceptions if the awaited s are canceled), so component methods don't need to handle and . + + can't follow the preceding guidelines because it doesn't conceptualize what constitutes a valid state for a derived component and it doesn't itself implement or . If returns an incomplete that doesn't use a and the component is disposed before the completes, still calls and awaits . If a disposable component doesn't use a , and should check if the component is disposed. + ## Avoid thread-blocking calls Generally, don't call the following methods in components. The following methods block the execution thread and thus block the app from resuming work until the underlying is complete: