From 2e6f46f283b30e412ecdd224bb2660eabc4440be Mon Sep 17 00:00:00 2001 From: korecko Date: Wed, 1 Jul 2026 11:57:02 +0200 Subject: [PATCH 1/2] fix: avoid JS interop errors during board teardown --- Ticky.Web/Components/Pages/BoardView.razor | 32 +++++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/Ticky.Web/Components/Pages/BoardView.razor b/Ticky.Web/Components/Pages/BoardView.razor index 6f1b216..182495d 100644 --- a/Ticky.Web/Components/Pages/BoardView.razor +++ b/Ticky.Web/Components/Pages/BoardView.razor @@ -8,6 +8,7 @@ @inject ILogger _logger @inject IHttpContextAccessor _httpContextAccessor @inherits NotifiableBase +@implements IAsyncDisposable @if (_board is not null) { @@ -208,6 +209,7 @@ private HubConnection? _hubConnection; private HashSet _expandedSections = new(); + private bool _isDisposed; protected override void OnParametersSet() { @@ -341,6 +343,9 @@ { await _protectedLocalStorage.SetAsync(Constants.StorageKeys.BoardPreferences, _preferences); } + catch (JSDisconnectedException) + { + } catch (Exception ex) { _logger.LogError(ex, "Failed to save board preferences."); @@ -497,6 +502,9 @@ private async Task LoadCardsAsync() { + if (_isDisposed) + return; + ArgumentNullException.ThrowIfNull(_board); using var db = _dbContextFactory.CreateDbContext(); @@ -534,18 +542,41 @@ _cards = await queryableCards.ToListAsync(); + if (_isDisposed) + return; + await InvokeAsync(StateHasChanged); try { await _protectedLocalStorage.SetAsync(FILTERS_SCOPED_KEY, _filterModel); } + catch (JSDisconnectedException) + { + } catch (Exception ex) { _logger.LogError(ex, "Failed to save filter preferences."); } } + public async ValueTask DisposeAsync() + { + _isDisposed = true; + + if (_hubConnection is null) + return; + + try + { + await _hubConnection.DisposeAsync(); + } + catch (Exception ex) + { + _logger.LogDebug(ex, "Failed to dispose board hub connection."); + } + } + private bool IsAdmin() { if(_board is null) @@ -590,4 +621,3 @@ private bool IsExpanded(string id) => _expandedSections.Contains(id); } - From 00d8edcd0b3f2331b4650d7a9d504405af874aa0 Mon Sep 17 00:00:00 2001 From: korecko Date: Wed, 1 Jul 2026 12:14:44 +0200 Subject: [PATCH 2/2] fix: harden BoardView disposal races --- Ticky.Web/Components/Pages/BoardView.razor | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/Ticky.Web/Components/Pages/BoardView.razor b/Ticky.Web/Components/Pages/BoardView.razor index 182495d..1b2724d 100644 --- a/Ticky.Web/Components/Pages/BoardView.razor +++ b/Ticky.Web/Components/Pages/BoardView.razor @@ -268,6 +268,10 @@ var boardPreferences = await _protectedLocalStorage.GetAsync(Constants.StorageKeys.BoardPreferences); _preferences = (boardPreferences.Success ? boardPreferences.Value : new()) ?? new(); } + catch (JSDisconnectedException) + { + _preferences = new(); + } catch (CryptographicException) { _preferences = new(); @@ -278,6 +282,10 @@ var filterPreferences = await _protectedLocalStorage.GetAsync(FILTERS_SCOPED_KEY); _filterModel = (filterPreferences.Success ? filterPreferences.Value : new()) ?? new(); } + catch (JSDisconnectedException) + { + _filterModel = new(); + } catch(CryptographicException) { _filterModel = new(); @@ -330,6 +338,9 @@ await _hubConnection.SendAsync(nameof(UpdateHub.SubscribeBoard), Id); } catch(Exception ex) { + if (_isDisposed) + return; + _logger.LogError(ex, "Failed to start hub connection or subscribe to board {BoardId}", Id); MainLayout.RunNotification(new("Real-time updates unavailable. Please refresh the page.", NotificationType.Fail)); } @@ -497,6 +508,9 @@ await LoadCardsAsync(); + if (_isDisposed) + return; + await InvokeAsync(StateHasChanged); }