diff --git a/src/ZB.MOM.WW.ScadaBridge.CentralUI/Components/Shared/SessionExpiry.razor b/src/ZB.MOM.WW.ScadaBridge.CentralUI/Components/Shared/SessionExpiry.razor index 17af5ad6..1b7865ef 100644 --- a/src/ZB.MOM.WW.ScadaBridge.CentralUI/Components/Shared/SessionExpiry.razor +++ b/src/ZB.MOM.WW.ScadaBridge.CentralUI/Components/Shared/SessionExpiry.razor @@ -87,7 +87,11 @@ if (status == Unauthorized) { - await InvokeAsync(() => Navigation.NavigateTo("/login", forceLoad: true)); + // Dispose cancels the CTS but cannot cancel an in-flight ping; skip the redirect + // (and swallow a racing disposal) so the fire-and-forget poll task never faults. + if (_cts is { IsCancellationRequested: true }) return; + try { await InvokeAsync(() => Navigation.NavigateTo("/login", forceLoad: true)); } + catch (ObjectDisposedException) { } } } diff --git a/tests/ZB.MOM.WW.ScadaBridge.CentralUI.Tests/Auth/SessionExpiryComponentTests.cs b/tests/ZB.MOM.WW.ScadaBridge.CentralUI.Tests/Auth/SessionExpiryComponentTests.cs index 73687f8b..c0631a12 100644 --- a/tests/ZB.MOM.WW.ScadaBridge.CentralUI.Tests/Auth/SessionExpiryComponentTests.cs +++ b/tests/ZB.MOM.WW.ScadaBridge.CentralUI.Tests/Auth/SessionExpiryComponentTests.cs @@ -37,6 +37,25 @@ public class SessionExpiryComponentTests : BunitContext Assert.EndsWith("/login", nav.Uri); } + /// Verifies a 401 landing after disposal neither redirects nor throws (review 2026-10-21 07/C-3). + /// A task that represents the asynchronous operation. + [Fact] + public async Task CheckSession_ExpiredAfterDispose_DoesNotRedirectOrThrow() + { + var module = JSInterop.SetupModule(ModulePath); + module.Setup("ping", "/auth/ping").SetResult(401); + + var nav = Services.GetRequiredService(); + var before = nav.Uri; + var cut = Render(); + var instance = cut.Instance; + await cut.InvokeAsync(() => ((IDisposable)instance).Dispose()); + + await instance.CheckSessionAsync(); + + Assert.Equal(before, nav.Uri); + } + /// Verifies that a live session does not redirect. /// A task that represents the asynchronous operation. [Fact]