diff --git a/src/Components/Components/test/NavigationManagerTest.cs b/src/Components/Components/test/NavigationManagerTest.cs index 3f6e680d0c8b..73ba7405f792 100644 --- a/src/Components/Components/test/NavigationManagerTest.cs +++ b/src/Components/Components/test/NavigationManagerTest.cs @@ -886,6 +886,38 @@ public void OnNotFoundSubscriptionIsTriggeredWhenNotFoundCalled() // Assert Assert.True(notFoundTriggered, "The OnNotFound event was not triggered as expected."); } + + [Fact] + public void OnNavigateToCallback_WhenThrows_ShouldBeHandledGracefully() + { + // Arrange + var baseUri = "scheme://host/"; + var uri = "scheme://host/test"; + var testNavManager = new TestNavigationManagerWithCallback(); + var exceptionThrown = false; + var expectedException = new InvalidOperationException("Test exception from OnNavigateTo"); + + // Configure the onNavigateTo callback to throw an exception + testNavManager.ConfigureOnNavigateToCallback(throwingUri => + { + exceptionThrown = true; + throw expectedException; + }); + + // Act + // Initialize the navigation manager with the callback + testNavManager.Initialize(baseUri, uri, testNavManager.GetOnNavigateToCallback()); + + // Assert + Assert.True(testNavManager.IsInitialized); + + // When navigation is triggered, the exception should be handled gracefully + var thrownException = testNavManager.TriggerOnNavigateToCallback(uri); + + // Assert + Assert.True(exceptionThrown, "The OnNavigateTo callback should have been called and thrown an exception."); + Assert.Same(expectedException, thrownException); + } private class TestNavigationManager : NavigationManager { @@ -932,4 +964,64 @@ protected override void HandleLocationChangingHandlerException(Exception ex, Loc _exceptionsThrownFromLocationChangingHandlers.Add(ex); } } + + private class TestNavigationManagerWithCallback : TestNavigationManager, IHostEnvironmentNavigationManager + { + private Func _onNavigateToCallback; + + public TestNavigationManagerWithCallback() + { + } + + public void Initialize(string baseUri, string uri, Func onNavigateTo) + { + _onNavigateToCallback = onNavigateTo; + base.Initialize(baseUri, uri); + } + + public void ConfigureOnNavigateToCallback(Func callback) + { + _onNavigateToCallback = callback; + } + + public Func GetOnNavigateToCallback() + { + return _onNavigateToCallback; + } + + public Exception TriggerOnNavigateToCallback(string uri) + { + if (_onNavigateToCallback == null) + { + return null; + } + + try + { + // Simulate the fire-and-forget pattern used in RemoteNavigationManager + _ = _onNavigateToCallback(uri); + return null; + } + catch (Exception ex) + { + return ex; + } + } + + public bool IsInitialized + { + get + { + try + { + _ = BaseUri; // This will throw if not initialized + return true; + } + catch (InvalidOperationException) + { + return false; + } + } + } + } } diff --git a/src/Components/Endpoints/src/Rendering/EndpointHtmlRenderer.cs b/src/Components/Endpoints/src/Rendering/EndpointHtmlRenderer.cs index f5d0699e1efe..3fb8c965ad27 100644 --- a/src/Components/Endpoints/src/Rendering/EndpointHtmlRenderer.cs +++ b/src/Components/Endpoints/src/Rendering/EndpointHtmlRenderer.cs @@ -83,7 +83,10 @@ internal async Task InitializeStandardComponentServicesAsync( IFormCollection? form = null) { var navigationManager = httpContext.RequestServices.GetRequiredService(); - ((IHostEnvironmentNavigationManager)navigationManager)?.Initialize(GetContextBaseUri(httpContext.Request), GetFullUri(httpContext.Request), OnNavigateTo); + ((IHostEnvironmentNavigationManager)navigationManager)?.Initialize( + GetContextBaseUri(httpContext.Request), + GetFullUri(httpContext.Request), + uri => GetErrorHandledTask(OnNavigateTo(uri))); navigationManager?.OnNotFound += (sender, args) => {