Summary
BWFC data-bound components (FormView, ListView, GridView, DataList, Repeater) that use SelectMethod do not render their bound data when navigated to via Blazor's enhanced navigation. The components render their template structure (header, footer, layout) but the ItemTemplate content is empty because the SelectMethod is never invoked during an enhanced navigation response.
Current workaround
The CLI scaffold (ProjectScaffolder.cs line 246) emits <body data-enhance-nav="false"> to force full-page loads on every navigation. This works but disables ALL enhanced navigation benefits for the entire application.
Root Cause Analysis
How enhanced navigation works
Blazor's blazor.web.js (enabled by default in .NET 10 SSR apps) intercepts <a> link clicks. Instead of a full page navigation, it:
- Fetches the target page via an AJAX
fetch() request
- Receives an HTML response
- DOM-diffs the response against the current page
- Patches only the changed DOM elements
This provides SPA-like smooth transitions without full page reloads.
How BWFC SelectMethod resolution works
BWFC data-bound components resolve data through this chain:
DataBoundComponent<T>.OnParametersSet() (src/BlazorWebFormsComponents/DataBinding/DataBoundComponent.cs lines 173-194) — invokes SelectMethodResolver.InvokeSelectMethod<T>() using the string method name
SelectMethodResolver (src/BlazorWebFormsComponents/DataBinding/SelectMethodResolver.cs) — uses reflection to find and invoke the named method on the HostingPage (WebFormsPageBase)
- The
HostingPage is received via [CascadingParameter] (DataBoundComponent.cs line 77-78): [CascadingParameter(Name = WebFormsPageBase.CascadingParameterName)] protected WebFormsPageBase HostingPage { get; set; }
Where it breaks
During an enhanced navigation response, the Blazor component lifecycle executes on the server to produce the response HTML. However, the cascading parameter chain from WebFormsPageBase → data-bound component may not fully propagate during this lifecycle:
- The
HostingPage cascading parameter may be null when OnParametersSet fires
- If
HostingPage is null, the SelectMethod resolution is silently skipped (the null check at line 205 guards this path)
- The component renders with an empty
Items list — the template structure appears but no data rows
This is observable in the WingtipToys benchmark: navigating to ProductDetails via a link click (enhanced nav) shows an empty page, while a direct URL load (full navigation) renders correctly with product image, name, description, and price.
Evidence from benchmark runs
| Run |
Symptom |
Fix Applied |
| Run 83 |
ProductDetails empty when navigated via link click |
Discovered root cause |
| Run 84 |
CLI scaffold now emits data-enhance-nav="false" |
Global workaround (commit 82ea56f5) |
| Run 85 |
26/26 tests pass with workaround |
Confirmed workaround is effective |
Affected Components
All components inheriting from DataBoundComponent<T> that use string-based SelectMethod:
FormView
ListView
GridView
DataList
Repeater
Components using Items parameter directly (not SelectMethod) are NOT affected — they receive data via parameter binding which works correctly during enhanced navigation.
Key Source Files
| File |
Role |
src/BlazorWebFormsComponents/DataBinding/DataBoundComponent.cs |
Base class with SelectMethod resolution in OnParametersSet / OnParametersSetAsync |
src/BlazorWebFormsComponents/DataBinding/SelectMethodResolver.cs |
Reflection-based method resolution against WebFormsPageBase |
src/BlazorWebFormsComponents/WebFormsPageBase.cs |
Hosting page that cascades itself to child components |
src/BlazorWebFormsComponents.Cli/Scaffolding/ProjectScaffolder.cs (line 246) |
Current workaround: data-enhance-nav="false" on <body> |
Expected Behavior
BWFC data-bound components using SelectMethod should render their data correctly when navigated to via enhanced navigation, without requiring data-enhance-nav="false" on the <body> tag.
Proposed Investigation
-
Diagnose the exact lifecycle failure — Add logging/breakpoints to DataBoundComponent.OnParametersSet and OnParametersSetAsync during enhanced nav vs full nav to determine:
- Is
HostingPage null during enhanced nav?
- Is
OnParametersSet called at all?
- Is the cascading parameter chain broken, or is the issue elsewhere (e.g., the method exists but returns empty data)?
-
Potential fix directions:
- Option A: Ensure cascading parameter propagation — Investigate why
WebFormsPageBase doesn't cascade during enhanced nav responses. This may require changes to how the page base class participates in the component tree.
- Option B: Deferred data binding — Move
SelectMethod resolution to OnAfterRenderAsync(firstRender: true) as a fallback when HostingPage was null during OnParametersSet.
- Option C: StreamRendering — Investigate whether
[StreamRendering] on data-bound components could allow initial empty render followed by data population via streaming SSR.
- Option D: Per-component enhanced nav opt-out — Instead of disabling enhanced nav globally, emit
data-enhance-nav="false" only on links that navigate to pages using SelectMethod-based data binding.
Definition of Done
Unit Tests (bUnit)
Create tests in src/BlazorWebFormsComponents.Test/DataBinding/ that verify:
Acceptance Tests (Playwright)
Add or enhance tests in src/WingtipToys.AcceptanceTests/ that verify:
Success Criteria
Labels
enhancement, component-library, data-binding
Summary
BWFC data-bound components (
FormView,ListView,GridView,DataList,Repeater) that useSelectMethoddo not render their bound data when navigated to via Blazor's enhanced navigation. The components render their template structure (header, footer, layout) but theItemTemplatecontent is empty because theSelectMethodis never invoked during an enhanced navigation response.Current workaround
The CLI scaffold (
ProjectScaffolder.csline 246) emits<body data-enhance-nav="false">to force full-page loads on every navigation. This works but disables ALL enhanced navigation benefits for the entire application.Root Cause Analysis
How enhanced navigation works
Blazor's
blazor.web.js(enabled by default in .NET 10 SSR apps) intercepts<a>link clicks. Instead of a full page navigation, it:fetch()requestThis provides SPA-like smooth transitions without full page reloads.
How BWFC
SelectMethodresolution worksBWFC data-bound components resolve data through this chain:
DataBoundComponent<T>.OnParametersSet()(src/BlazorWebFormsComponents/DataBinding/DataBoundComponent.cslines 173-194) — invokesSelectMethodResolver.InvokeSelectMethod<T>()using the string method nameSelectMethodResolver(src/BlazorWebFormsComponents/DataBinding/SelectMethodResolver.cs) — uses reflection to find and invoke the named method on theHostingPage(WebFormsPageBase)HostingPageis received via[CascadingParameter](DataBoundComponent.csline 77-78):[CascadingParameter(Name = WebFormsPageBase.CascadingParameterName)] protected WebFormsPageBase HostingPage { get; set; }Where it breaks
During an enhanced navigation response, the Blazor component lifecycle executes on the server to produce the response HTML. However, the cascading parameter chain from
WebFormsPageBase→ data-bound component may not fully propagate during this lifecycle:HostingPagecascading parameter may benullwhenOnParametersSetfiresHostingPageis null, theSelectMethodresolution is silently skipped (the null check at line 205 guards this path)Itemslist — the template structure appears but no data rowsThis is observable in the WingtipToys benchmark: navigating to ProductDetails via a link click (enhanced nav) shows an empty page, while a direct URL load (full navigation) renders correctly with product image, name, description, and price.
Evidence from benchmark runs
data-enhance-nav="false"82ea56f5)Affected Components
All components inheriting from
DataBoundComponent<T>that use string-basedSelectMethod:FormViewListViewGridViewDataListRepeaterComponents using
Itemsparameter directly (notSelectMethod) are NOT affected — they receive data via parameter binding which works correctly during enhanced navigation.Key Source Files
src/BlazorWebFormsComponents/DataBinding/DataBoundComponent.csSelectMethodresolution inOnParametersSet/OnParametersSetAsyncsrc/BlazorWebFormsComponents/DataBinding/SelectMethodResolver.csWebFormsPageBasesrc/BlazorWebFormsComponents/WebFormsPageBase.cssrc/BlazorWebFormsComponents.Cli/Scaffolding/ProjectScaffolder.cs(line 246)data-enhance-nav="false"on<body>Expected Behavior
BWFC data-bound components using
SelectMethodshould render their data correctly when navigated to via enhanced navigation, without requiringdata-enhance-nav="false"on the<body>tag.Proposed Investigation
Diagnose the exact lifecycle failure — Add logging/breakpoints to
DataBoundComponent.OnParametersSetandOnParametersSetAsyncduring enhanced nav vs full nav to determine:HostingPagenull during enhanced nav?OnParametersSetcalled at all?Potential fix directions:
WebFormsPageBasedoesn't cascade during enhanced nav responses. This may require changes to how the page base class participates in the component tree.SelectMethodresolution toOnAfterRenderAsync(firstRender: true)as a fallback whenHostingPagewas null duringOnParametersSet.[StreamRendering]on data-bound components could allow initial empty render followed by data population via streaming SSR.data-enhance-nav="false"only on links that navigate to pages usingSelectMethod-based data binding.Definition of Done
Unit Tests (bUnit)
Create tests in
src/BlazorWebFormsComponents.Test/DataBinding/that verify:FormViewwithSelectMethodrenders item data when hosted onWebFormsPageBaseListViewwithSelectMethodrenders all items when hosted onWebFormsPageBaseGridViewwithSelectMethodrenders rows when hosted onWebFormsPageBaseSelectMethodand nullHostingPagecascading parameter handles gracefully (doesn't crash, provides clear error)SelectMethodresolution works whenOnParametersSetis called multiple times (simulating re-render)SelectMethod(returningTask<IEnumerable<T>>) resolves correctlyAcceptance Tests (Playwright)
Add or enhance tests in
src/WingtipToys.AcceptanceTests/that verify:data-enhance-nav="false"on the<body>tagSuccess Criteria
data-enhance-nav="false"fromProjectScaffolder.csbody tagLabels
enhancement,component-library,data-binding