Skip to content

Commit

Permalink
🐛 fix: Optimize the logic of component disposing (#552)
Browse files Browse the repository at this point in the history
  • Loading branch information
capdiem authored Jan 30, 2024
1 parent 39a92d9 commit 12b0b92
Show file tree
Hide file tree
Showing 16 changed files with 79 additions and 46 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -125,42 +125,35 @@ protected async Task Retry(Func<Task> callback, Func<bool> @while, int retryTime
}
}

protected virtual async ValueTask DisposeAsync(bool disposing)
protected virtual ValueTask DisposeAsyncCore() => ValueTask.CompletedTask;

public async ValueTask DisposeAsync()
{
if (IsDisposed)
{
await ValueTask.CompletedTask;
return;
}

IsDisposed = true;
}

public async ValueTask DisposeAsync()
{
try
{
await DisposeAsync(true);
GC.SuppressFinalize(this);
await DisposeAsyncCore().ConfigureAwait(false);
}
catch (JSDisconnectedException)
{
// ignored
}
// HACK: remove this after https://github.com/dotnet/aspnetcore/issues/52119 is fixed
catch (JSException e)
{
// HACK: remove this after https://github.com/dotnet/aspnetcore/issues/52119 is fixed
if (e.Message.Contains("has it been disposed") && (OperatingSystem.IsWindows() || OperatingSystem.IsAndroid() || OperatingSystem.IsIOS()))
{
return;
}

throw;
}
}

~NextTickComponentBase()
{
// Finalizer calls Dispose(false)
_ = DisposeAsync(false);
GC.SuppressFinalize(this);
IsDisposed = true;
}
}
4 changes: 2 additions & 2 deletions src/Component/BlazorComponent/Components/App/BApp.razor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,11 @@ private void OnStateChanged(object? sender, EventArgs e)
InvokeAsync(StateHasChanged);
}

protected override async ValueTask DisposeAsync(bool disposing)
protected override async ValueTask DisposeAsyncCore()
{
PopupProvider.StateChanged -= OnStateChanged;

await base.DisposeAsync(disposing);
await base.DisposeAsyncCore();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -118,11 +118,11 @@ private bool UpdateActiveForRoutable()
return matched != Matched;
}

protected override async ValueTask DisposeAsync(bool disposing)
protected override async ValueTask DisposeAsyncCore()
{
NavigationManager.LocationChanged -= OnLocationChanged;

await base.DisposeAsync(disposing);
await base.DisposeAsyncCore();
}
}
}
4 changes: 2 additions & 2 deletions src/Component/BlazorComponent/Components/Form/BForm.razor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -311,11 +311,11 @@ private async Task UpdateValue(bool val)
}
}

protected override async ValueTask DisposeAsync(bool disposing)
protected override async ValueTask DisposeAsyncCore()
{
_editContextValidation?.Dispose();

await base.DisposeAsync(disposing);
await base.DisposeAsyncCore();
}
}
}
4 changes: 2 additions & 2 deletions src/Component/BlazorComponent/Components/I18n/BI18n.razor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -102,9 +102,9 @@ private List<I18nValueSegment> GetSegments(string value)

private record I18nValueSegment(string Text, int PlaceholderIndex = -1);

protected override async ValueTask DisposeAsync(bool disposing)
protected override async ValueTask DisposeAsyncCore()
{
I18n.CultureChanged -= I18nOnCultureChanged;
await base.DisposeAsync(disposing);
await base.DisposeAsyncCore();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -526,14 +526,14 @@ protected virtual void HandleOnValidationStateChanged(object? sender, Validation
InvokeStateHasChanged();
}

protected override ValueTask DisposeAsync(bool disposing)
protected override ValueTask DisposeAsyncCore()
{
if (EditContext != null)
{
EditContext.OnValidationStateChanged -= HandleOnValidationStateChanged;
}

return base.DisposeAsync(disposing);
return base.DisposeAsyncCore();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ public async Task SetValue(string? val)
await _instance.InvokeVoidAsync("setValue", val);
}

protected override async ValueTask DisposeAsync()
protected override async ValueTask DisposeAsyncCore()
{
_isDisposed = true;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -90,10 +90,10 @@ private async Task<bool> UpdateActiveForRoutable()

protected virtual Task OnActiveUpdatedForRoutable() => Task.CompletedTask;

protected override ValueTask DisposeAsync(bool disposing)
protected override ValueTask DisposeAsyncCore()
{
NavigationManager.LocationChanged -= OnLocationChanged;

return base.DisposeAsync(disposing);
return base.DisposeAsyncCore();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -171,12 +171,12 @@ private async Task UpdateValue(bool value)
}
}

protected override async ValueTask DisposeAsync(bool disposing)
protected override async ValueTask DisposeAsyncCore()
{
List?.Unregister(this);
NavigationManager.LocationChanged -= OnLocationChanged;

await base.DisposeAsync(disposing);
await base.DisposeAsyncCore();
}
}
}
4 changes: 2 additions & 2 deletions src/Component/BlazorComponent/Components/Menu/BMenu.razor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -249,7 +249,7 @@ private double CalcLeftAuto()
return Dimensions.Activator.Left - DefaultOffset * 2;
}

protected override async ValueTask DisposeAsync(bool disposing)
protected override async ValueTask DisposeAsyncCore()
{
if (Module is not null)
{
Expand All @@ -263,6 +263,6 @@ protected override async ValueTask DisposeAsync(bool disposing)
}
}

await base.DisposeAsync(disposing);
await base.DisposeAsyncCore();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -230,7 +230,7 @@ public async Task HandleOnOutsideClickAsync()
IsActive = false;
}

protected override async ValueTask DisposeAsync(bool disposing)
protected override async ValueTask DisposeAsyncCore()
{
await OutsideClickJsModule.UnbindAndDisposeAsync();
}
Expand Down
45 changes: 39 additions & 6 deletions src/Component/BlazorComponent/JSInterop/JSModule.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
public abstract class JSModule : IAsyncDisposable
{
private readonly Lazy<Task<IJSObjectReference>> _moduleTask;
protected readonly CancellationTokenSource _cts = new();
private bool _isDisposed;

protected JSModule(IJSRuntime js, string moduleUrl)
=> _moduleTask = new Lazy<Task<IJSObjectReference>>(() => js.InvokeAsync<IJSObjectReference>("import", moduleUrl).AsTask());
Expand All @@ -14,6 +16,11 @@ protected async ValueTask InvokeVoidAsync(string identifier, params object?[]? a
{
var module = await _moduleTask.Value;

if (_cts.IsCancellationRequested)
{
return;
}

try
{
await module.InvokeVoidAsync(identifier, args);
Expand All @@ -24,37 +31,63 @@ protected async ValueTask InvokeVoidAsync(string identifier, params object?[]? a
}
}

protected async ValueTask<T> InvokeAsync<T>(string identifier, params object?[]? args)
protected async ValueTask<T?> InvokeAsync<T>(string identifier, params object?[]? args)
{
var module = await _moduleTask.Value;

if (_cts.Token.IsCancellationRequested)
{
return default;
}

try
{
return await module.InvokeAsync<T>(identifier, args);
}
catch (JSDisconnectedException)
{
return default(T);
return default;
}
}

protected virtual ValueTask DisposeAsync() => ValueTask.CompletedTask;
protected virtual ValueTask DisposeAsyncCore() => ValueTask.CompletedTask;

async ValueTask IAsyncDisposable.DisposeAsync()
{
if (_moduleTask.IsValueCreated)
if (_isDisposed)
{
return;
}

_cts.Cancel();

if (_moduleTask.IsValueCreated && !_moduleTask.Value.IsFaulted)
{
var module = await _moduleTask.Value;

try
{
await DisposeAsync();
await module.DisposeAsync();
await DisposeAsyncCore().ConfigureAwait(false);
await module.DisposeAsync().ConfigureAwait(false);
}
catch (JSDisconnectedException)
{
// ignored
}
catch (JSException e)
{
// HACK: remove this after https://github.com/dotnet/aspnetcore/issues/52119 is fixed
if (e.Message.Contains("has it been disposed") && (OperatingSystem.IsWindows() || OperatingSystem.IsAndroid() || OperatingSystem.IsIOS()))
{
return;
}

throw;
}
}

_isDisposed = true;
//_cts.Dispose();
GC.SuppressFinalize(this);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ public async Task OnClick(MouseEventArgs args)
await _owner.HandleOnClickAsync(args);
}

protected override async ValueTask DisposeAsync()
protected override async ValueTask DisposeAsyncCore()
{
_selfReference?.Dispose();

Expand Down
4 changes: 2 additions & 2 deletions src/Component/BlazorComponent/Mixins/Groupable/BGroupable.cs
Original file line number Diff line number Diff line change
Expand Up @@ -188,14 +188,14 @@ protected async Task SetInternalIsActive(bool val, bool force = false)
}
}

protected override async ValueTask DisposeAsync(bool disposing)
protected override async ValueTask DisposeAsyncCore()
{
if (Matched && this is IGroupable item)
{
ItemGroup!.Unregister(item);
}

await base.DisposeAsync(disposing);
await base.DisposeAsyncCore();
}
}
}
4 changes: 2 additions & 2 deletions src/Component/BlazorComponent/Mixins/Menuable/BMenuable.cs
Original file line number Diff line number Diff line change
Expand Up @@ -457,7 +457,7 @@ protected virtual Task DeactivateAsync()
return Task.CompletedTask;
}

protected override async ValueTask DisposeAsync(bool disposing)
protected override async ValueTask DisposeAsyncCore()
{
Window.OnResize -= HandleOnResizeAsync;

Expand All @@ -473,7 +473,7 @@ protected override async ValueTask DisposeAsync(bool disposing)
// ignored
}

await base.DisposeAsync(disposing);
await base.DisposeAsyncCore();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,14 @@ public async Task UpdateDependentElementsAsync(params string[] selectors)
/// <summary>
/// Remove event listener from document and dispose this module
/// </summary>
public async ValueTask UnbindAndDisposeAsync() => await DisposeAsync();

public async ValueTask UnbindAndDisposeAsync()
{
if (this is IAsyncDisposable asyncDisposable)
{
await asyncDisposable.DisposeAsync();
}
}

/// <summary>
/// Remove event listener from document
Expand All @@ -61,7 +68,7 @@ public async Task OnOutsideClick()
await _owner.HandleOnOutsideClickAsync();
}

protected override async ValueTask DisposeAsync()
protected override async ValueTask DisposeAsyncCore()
{
await UnbindAsync();

Expand Down

0 comments on commit 12b0b92

Please sign in to comment.