Fix Blazor crash when interactive component is in layout with enhanced nav#66007
Fix Blazor crash when interactive component is in layout with enhanced nav#66007
Conversation
22a336b to
b530b67
Compare
…d nav When an InteractiveAuto/InteractiveWebAssembly component is placed in the layout, navigating between pages via enhanced navigation causes: TypeError: Cannot read properties of null (reading insertBefore) Root cause: The Blazor-WebAssembly metadata comment was removed from the DOM during discoverWebAssemblyOptions() but remained in the logical children array as an orphaned node. On subsequent enhanced navigations, insertLogicalChild would pick this orphaned comment as a reference node for insertBefore, crashing because parentNode was null. Fix: 1. Reorder registerAllComponentDescriptors to call discoverWebAssemblyOptions before upgradeComponentCommentsToLogicalRootComments, ensuring metadata comments are removed before the logical tree is built. 2. Strip metadata comments from new content in preprocessAndSynchronizeDomContent before building the logical tree during enhanced navigation. 3. Add defensive null check in insertLogicalChild for disconnected reference nodes. Fixes #64722 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
b530b67 to
4f13842
Compare
This comment was marked as resolved.
This comment was marked as resolved.
…ced-nav-layout-crash # Conflicts: # src/Components/Web.JS/src/Rendering/DomMerging/DomSync.ts Co-authored-by: maraf <10020471+maraf@users.noreply.github.com>
This comment was marked as resolved.
This comment was marked as resolved.
There was a problem hiding this comment.
Pull request overview
This PR fixes a crash in Blazor’s enhanced navigation DOM merging when an interactive component is rendered from a layout, by preventing WebAssembly metadata comments from becoming orphaned logical nodes and by making logical insertion more defensive. It also adds new test assets and an E2E regression test that navigates between pages using a layout containing an InteractiveAuto component.
Changes:
- Adjust DOM merge preprocessing/registration ordering to remove WebAssembly options metadata comments before building logical element trees.
- Add a defensive fallback in
insertLogicalChildto avoid crashing when a reference node is disconnected. - Add new test pages/layout + an E2E regression test for navigating between enhanced-nav pages with an interactive component in the layout.
Reviewed changes
Copilot reviewed 7 out of 7 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| src/Components/Web.JS/src/Rendering/DomMerging/DomSync.ts | Reorders descriptor registration steps and strips WASM options metadata from incoming enhanced-nav content before logical tree creation. |
| src/Components/Web.JS/src/Rendering/LogicalElements.ts | Avoids insertBefore crash by handling disconnected reference nodes during logical insertions. |
| src/Components/test/E2ETest/ServerRenderingTests/EnhancedNavigationTest.cs | Adds a new E2E regression test for enhanced navigation with an interactive component in the layout. |
| src/Components/test/testassets/TestContentPackage/InteractiveCounterInLayout.razor | Adds an InteractiveAuto counter component intended to be rendered from a layout. |
| src/Components/test/testassets/Components.TestServer/RazorComponents/Shared/EnhancedNavWithInteractiveInLayout.razor | Adds a layout that includes the interactive counter and enhanced-nav links. |
| src/Components/test/testassets/Components.TestServer/RazorComponents/Pages/EnhancedNav/InteractiveInLayoutHome.razor | Adds a home page using the new layout for the regression scenario. |
| src/Components/test/testassets/Components.TestServer/RazorComponents/Pages/EnhancedNav/InteractiveInLayoutOther.razor | Adds a second page using the new layout to exercise back-and-forth enhanced navigation. |
|
Addressing Copilot review feedback: Comment on staleness assertion (line 938): Good catch. Applied — I now capture a layout element ( Comment on error detection (line 949): Agreed. Replaced the unreliable |
- Add staleness-based assertion using layout element to verify enhanced navigation was actually used (not full page reload) - Replace unreliable blazor-error-ui check with browser console log assertion matching existing patterns in the file - Click interactive counter button to prove the interactive layout component is still functional after navigation Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
ilonatommy
left a comment
There was a problem hiding this comment.
Looks correct, one nit for discussion.
Replace the simple null-check fallback with a cleanup-first approach: scan and remove all orphaned nodes (disconnected from DOM) from the siblings array before the insert logic runs, adjusting the insertion index as orphans are pruned. This ensures: 1. Correct DOM ordering is preserved - the reference sibling is always connected after cleanup, so insertBefore places nodes correctly. 2. Orphaned siblings are removed from the logical children array so subsequent operations don't encounter them. Add unit tests for orphan cleanup in insertLogicalChild covering: - Orphan at reference position - Multiple orphans before insertion index (index adjustment) - Orphans interspersed with connected nodes - Append fallback after cleanup - Normal insert (no regression) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Use fresh Browser.Exists() queries inside WaitAssert lambdas instead of a captured element reference. The InteractiveAuto component re-renders client-side after clicking the button, replacing the DOM node and making the captured reference stale. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
|
/azp run aspnetcore-components-e2e |
|
Azure Pipelines successfully started running 1 pipeline(s). |
… test The test CanNavigateBetweenPagesWhenLayoutContainsInteractiveComponent was racing against InteractiveAuto bootstrap: after enhanced navigation it clicked the counter button before the component had finished transitioning to interactive mode, so the click did nothing and the counter stayed at 0. Add an 'Interactive' marker to InteractiveCounterInLayout (toggled from OnAfterRender(firstRender)) and wait for it to read 'True' in the test before clicking, mirroring the pattern used by TestContentPackage.Counter. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Fix Blazor crash when interactive component is in layout with enhanced navigation
Fixes #64722
Problem
When an
InteractiveAutoorInteractiveWebAssemblycomponent is placed in the layout (e.g.<Counter />inMainLayout.razor), navigating between pages via enhanced navigation causes:Root Cause
The
<!--Blazor-WebAssembly:{...}-->metadata comment was removed from the physical DOM duringdiscoverWebAssemblyOptions(), but remained in the parent element's logical children array as an orphaned node (parentNode === null). On subsequent enhanced navigations,insertLogicalChild()picked this orphaned comment as a reference node forinsertBefore, crashing becauseparentNodewas null.Changes
Reorder
registerAllComponentDescriptors— CalldiscoverWebAssemblyOptionsbeforeupgradeComponentCommentsToLogicalRootComments, ensuring metadata comments are removed from the DOM before the logical tree is built.Strip metadata in
preprocessAndSynchronizeDomContent— Remove metadata comments from new enhanced-nav content before building the logical tree, preventing orphaned nodes during navigation.Defensive null check in
insertLogicalChild— Replace the non-null assertionparentNode!.insertBefore(...)with a null check, falling back toappendDomNodeif the reference node is disconnected.