Repository navigation
Avoid starting the response when navigating with exception - #69174
ilonatommy wants to merge 4 commits into
Conversation
… successfully due to the by-design naviagaion exception.
There was a problem hiding this comment.
🟢 Approval recommended
The change is narrowly scoped to navigation-exception handling, updates call sites consistently, and adds both unit and E2E coverage for the reported regression scenario.
Pull request overview
This PR fixes a static SSR TempData persistence regression when legacy exception-driven NavigationManager.NavigateTo is used from a non-streaming form handler (notably EditForm). It ensures handled NavigationException faults don’t incorrectly route the response through the streaming update path, which could start/flush the response before cookie-backed TempData is persisted.
Changes:
- Update
EndpointHtmlRenderer.WaitForNonStreamingPendingTasksto return whether it handled aNavigationException, while still propagating mixed (non-navigation) failures. - Prevent
RazorComponentEndpointInvokerfrom entering streaming updates when the only reason quiescence is faulted is a handled navigation exception. - Add coverage: an E2E repro via
EditForm+[SupplyParameterFromTempData], and unit tests for the new pending-task navigation handling.
File summaries
| File | Description |
|---|---|
| src/Components/test/testassets/Components.TestServer/RazorComponents/Pages/TempData/TempDataComponent.razor | Adds an EditForm POST path to exercise legacy navigation-by-exception with TempData. |
| src/Components/test/E2ETest/Tests/TempDataCookieTest.cs | Adds E2E coverage ensuring cookie TempData persists across an EditForm-driven redirect in the legacy navigation flow. |
| src/Components/Endpoints/test/EndpointHtmlRendererTest.cs | Adds unit tests validating WaitForNonStreamingPendingTasks reports handled navigation and doesn’t mask mixed exceptions. |
| src/Components/Endpoints/src/Rendering/EndpointHtmlRenderer.Prerendering.cs | Changes WaitForNonStreamingPendingTasks to return a bool and inspects aggregated exceptions to avoid treating mixed failures as successful navigation. |
| src/Components/Endpoints/src/Rendering/EndpointHtmlRenderer.cs | Updates the cached completion task type for non-streaming pending tasks to Task<bool>. |
| src/Components/Endpoints/src/RazorComponentEndpointInvoker.cs | Skips streaming updates when navigation was already handled and the remaining quiescence fault contains only NavigationExceptions. |
Review details
- Files reviewed: 6/6 changed files
- Comments generated: 0
- Review effort level: Lite
💡 Add a code-review agent skill for context-aware, tailored reviews. Learn more in the docs.
|
Looks like this PR hasn't been active for some time and the codebase could have been changed in the meantime. |
Avoid starting the response when task didn't finish successfully due to the by-design navigation exception.
Description
Cookie-backed
[SupplyParameterFromTempData]values were lost when a non-streaming static SSREditFormhandler redirected using exception-driven navigation.The redirect succeeded, but the response was accidentally routed through the streaming response path before TempData persistence. This started the response and prevented the TempData provider from adding its cookie.
Background
During static SSR,
NavigationManager.NavigateTosupports two control-flow modes:NavigateTothrowsNavigationException, which the renderer catches and converts into a redirect.NavigateTodirectly invokes the endpoint navigation callback.Exception-driven navigation remains the runtime compatibility default when
BlazorDisableThrowNavigationExceptionis absent orfalse. This means newly created applications normally use non-throwing navigation, while existing applications upgraded to .NET 11 can continue using exception-driven navigation.When
NavigateTothrows insideHandleSubmitAsync, the exception becomes the failure of the task returned byHandleSubmitAsync. The renderer tracks that task as non-streaming pending work.Root cause
WaitForNonStreamingPendingTaskscorrectly caught the task'sNavigationExceptionand established the redirect before the response started. However, the separate full-quiescence task retained byRazorComponentEndpointInvokerremained non-successful:The invoker used
!quiesceTask.IsCompletedSuccessfullyto decide whether to callSendStreamingUpdatesAsync. As a result, the already-handled navigation fault was mistaken for streaming work.SendStreamingUpdatesAsyncflushed the response before awaiting the faulted task and then emitted a streaming redirection template. By the timeTempDataService.Persistran,Response.HasStartedwastrue, so the cookie provider could no longer add the TempData cookie.This was what was meant by
in #68796 (comment).
Fix
WaitForNonStreamingPendingTasksreports whether it handled aNavigationExceptionto avoid starting streaming in navigation-by-exception flows.Before reporting navigation as handled, it inspects the original
Task.WhenAllexception collection. If the batch contains any non-navigation exception, that exception is propagated instead of being treated as successful navigation.The invoker excludes the quiescence task from the streaming path only when:
NavigationException.Fixes #68796