You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
It isn't necessary to call <xref:Microsoft.AspNetCore.Components.ComponentBase.OnInitializedAsync%2A?displayProperty=nameWithType> unless a custom base class is used with custom logic. For more information, see the [Base class lifecycle methods](#base-class-lifecycle-methods) section.
199
199
200
+
A component must ensure that it's in a valid state for rendering when <xref:Microsoft.AspNetCore.Components.ComponentBase.OnInitializedAsync%2A> returns from awaiting a potentially incomplete <xref:System.Threading.Tasks.Task>. If the method returns an incomplete <xref:System.Threading.Tasks.Task>, 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 <xref:blazor/components/sync-context> and [Component disposal with `IDisposable` and `IAsyncDisposable` (this article)](#component-disposal-with-idisposable-and-iasyncdisposable).
201
+
200
202
Blazor apps that prerender their content on the server call <xref:Microsoft.AspNetCore.Components.ComponentBase.OnInitializedAsync%2A>*twice*:
201
203
202
204
* Once when the component is initially rendered statically as part of the page.
@@ -216,7 +218,7 @@ To prevent developer code in <xref:Microsoft.AspNetCore.Components.ComponentBase
216
218
217
219
While a Blazor app is prerendering, certain actions, such as calling into JavaScript (JS interop), aren't possible. Components may need to render differently when prerendered. For more information, see the [Prerendering with JavaScript interop](#prerendering-with-javascript-interop) section.
218
220
219
-
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.
221
+
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.
It isn't necessary to call <xref:Microsoft.AspNetCore.Components.ComponentBase.OnParametersSetAsync%2A?displayProperty=nameWithType> unless a custom base class is used with custom logic. For more information, see the [Base class lifecycle methods](#base-class-lifecycle-methods) section.
318
320
319
-
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.
321
+
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.
322
+
323
+
If a disposable component doesn't use a <xref:System.Threading.CancellationToken>, <xref:Microsoft.AspNetCore.Components.ComponentBase.OnParametersSet%2A> and <xref:Microsoft.AspNetCore.Components.ComponentBase.OnParametersSetAsync%2A> should check if the component is disposed. If <xref:Microsoft.AspNetCore.Components.ComponentBase.OnParametersSetAsync%2A> returns an incomplete <xref:System.Threading.Tasks.Task>, 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 <xref:blazor/components/sync-context> and [Component disposal with `IDisposable` and `IAsyncDisposable` (this article)](#component-disposal-with-idisposable-and-iasyncdisposable).
320
324
321
325
For more information on route parameters and constraints, see <xref:blazor/fundamentals/routing>.
322
326
@@ -422,7 +426,7 @@ Even if you return a <xref:System.Threading.Tasks.Task> from <xref:Microsoft.Asp
422
426
1. The component executes on the server to produce some static HTML markup in the HTTP response. During this phase, <xref:Microsoft.AspNetCore.Components.ComponentBase.OnAfterRender%2A> and <xref:Microsoft.AspNetCore.Components.ComponentBase.OnAfterRenderAsync%2A> aren't called.
423
427
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, <xref:Microsoft.AspNetCore.Components.ComponentBase.OnAfterRender%2A> and <xref:Microsoft.AspNetCore.Components.ComponentBase.OnAfterRenderAsync%2A>**are** called because the app isn't in the prerendering phase any longer.
424
428
425
-
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.
429
+
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.
426
430
427
431
## Base class lifecycle methods
428
432
@@ -763,12 +767,14 @@ Although the content in this section focuses on Blazor Server and stateful Signa
763
767
764
768
## Component disposal with `IDisposable` and `IAsyncDisposable`
765
769
766
-
If a component implements <xref:System.IDisposable> or <xref:System.IAsyncDisposable>, 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, <xref:System.IAsyncDisposable> can be triggered before or after an asynchronous <xref:System.Threading.Tasks.Task> 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.
770
+
If a component implements <xref:System.IDisposable> or <xref:System.IAsyncDisposable>, 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, <xref:System.IAsyncDisposable> can be triggered before or after an asynchronous <xref:System.Threading.Tasks.Task> 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.
767
771
768
772
Components shouldn't need to implement <xref:System.IDisposable> and <xref:System.IAsyncDisposable> simultaneously. If both are implemented, the framework only executes the asynchronous overload.
769
773
770
774
Developer code must ensure that <xref:System.IAsyncDisposable> implementations don't take a long time to complete.
771
775
776
+
For more information, see the introductory remarks of <xref:blazor/components/sync-context>.
777
+
772
778
### Disposal of JavaScript interop object references
773
779
774
780
Examples throughout the [JavaScript (JS) interop articles](xref:blazor/js-interop/index) demonstrate typical object disposal patterns:
@@ -950,6 +956,7 @@ The following component:
950
956
951
957
For more information, see:
952
958
959
+
*<xref:blazor/components/sync-context>
953
960
*[Cleaning up unmanaged resources (.NET documentation)](/dotnet/standard/garbage-collection/unmanaged)
954
961
*[Null-conditional operators ?. and ?[]](/dotnet/csharp/language-reference/operators/member-access-operators#null-conditional-operators--and-)
Copy file name to clipboardExpand all lines: aspnetcore/blazor/components/synchronization-context.md
+12Lines changed: 12 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -16,6 +16,18 @@ Blazor uses a synchronization context (<xref:System.Threading.SynchronizationCon
16
16
17
17
Blazor's server-side synchronization context attempts to emulate a single-threaded environment so that it closely matches the WebAssembly model in the browser, which is single threaded. This emulation is scoped only to an individual circuit, meaning two different circuits can run in parallel. At any given point in time within a circuit, work is performed on exactly one thread, which yields the impression of a single logical thread. No two operations execute concurrently within the same circuit.
18
18
19
+
A single logical thread of execution doesn't imply a single asynchronous control flow. A component is re-entrant at any point where it awaits an incomplete <xref:System.Threading.Tasks.Task>. [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 <xref:System.Threading.Tasks.Task> to complete. Therefore, a component must ensure that it's in a valid state before awaiting a potentially incomplete <xref:System.Threading.Tasks.Task>. In particular, a component must ensure that it's in a valid state for rendering when <xref:Microsoft.AspNetCore.Components.ComponentBase.OnInitializedAsync%2A> or <xref:Microsoft.AspNetCore.Components.ComponentBase.OnParametersSetAsync%2A> return. If either of these methods return an incomplete <xref:System.Threading.Tasks.Task>, they must ensure that the part of the method that completes synchronously leaves the component in a valid state for rendering.
20
+
21
+
Another implication of re-entrant components is that a method can't defer a <xref:System.Threading.Tasks.Task> until after the method returns by passing it to <xref:Microsoft.AspNetCore.Components.ComponentBase.InvokeAsync%2A?displayProperty=nameWithType>. Calling <xref:Microsoft.AspNetCore.Components.ComponentBase.InvokeAsync%2A?displayProperty=nameWithType> may only defer the <xref:System.Threading.Tasks.Task> until the next [`await` operator](/dotnet/csharp/language-reference/operators/await) is reached.
22
+
23
+
Components might implement <xref:System.IDisposable> or <xref:System.IAsyncDisposable> to call asynchronous methods using a <xref:System.Threading.CancellationToken> from a <xref:System.Threading.CancellationTokenSource> 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.
24
+
25
+
A disposable component can check for disposal after awaiting any <xref:System.Threading.Tasks.Task> that doesn't receive the component's <xref:System.Threading.CancellationToken>. Incomplete <xref:System.Threading.Tasks.Task>s may also prevent garbage collection of a disposed component.
26
+
27
+
<xref:Microsoft.AspNetCore.Components.ComponentBase> ignores exceptions caused by <xref:System.Threading.Tasks.Task> cancellation (more precisely, it ignores *all* exceptions if the awaited <xref:System.Threading.Tasks.Task>s are canceled), so component methods don't need to handle <xref:System.Threading.Tasks.TaskCanceledException> and <xref:System.OperationCanceledException>.
28
+
29
+
<xref:Microsoft.AspNetCore.Components.ComponentBase> 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 <xref:System.IDisposable> or <xref:System.IAsyncDisposable>. If <xref:Microsoft.AspNetCore.Components.ComponentBase.OnInitializedAsync%2A> returns an incomplete <xref:System.Threading.Tasks.Task> that doesn't use a <xref:System.Threading.CancellationToken> and the component is disposed before the <xref:System.Threading.Tasks.Task> completes, <xref:Microsoft.AspNetCore.Components.ComponentBase> still calls <xref:Microsoft.AspNetCore.Components.ComponentBase.OnParametersSet%2A> and awaits <xref:Microsoft.AspNetCore.Components.ComponentBase.OnParametersSetAsync%2A>. If a disposable component doesn't use a <xref:System.Threading.CancellationToken>, <xref:Microsoft.AspNetCore.Components.ComponentBase.OnParametersSet%2A> and <xref:Microsoft.AspNetCore.Components.ComponentBase.OnParametersSetAsync%2A> should check if the component is disposed.
30
+
19
31
## Avoid thread-blocking calls
20
32
21
33
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 <xref:System.Threading.Tasks.Task> is complete:
0 commit comments