Skip to content

Data-bound components with SelectMethod render empty during Blazor enhanced navigation #548

@csharpfritz

Description

@csharpfritz

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:

  1. Fetches the target page via an AJAX fetch() request
  2. Receives an HTML response
  3. DOM-diffs the response against the current page
  4. 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:

  1. DataBoundComponent<T>.OnParametersSet() (src/BlazorWebFormsComponents/DataBinding/DataBoundComponent.cs lines 173-194) — invokes SelectMethodResolver.InvokeSelectMethod<T>() using the string method name
  2. SelectMethodResolver (src/BlazorWebFormsComponents/DataBinding/SelectMethodResolver.cs) — uses reflection to find and invoke the named method on the HostingPage (WebFormsPageBase)
  3. 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

  1. 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)?
  2. 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:

  • FormView with SelectMethod renders item data when hosted on WebFormsPageBase
  • ListView with SelectMethod renders all items when hosted on WebFormsPageBase
  • GridView with SelectMethod renders rows when hosted on WebFormsPageBase
  • Data-bound component with SelectMethod and null HostingPage cascading parameter handles gracefully (doesn't crash, provides clear error)
  • SelectMethod resolution works when OnParametersSet is called multiple times (simulating re-render)
  • Async SelectMethod (returning Task<IEnumerable<T>>) resolves correctly

Acceptance Tests (Playwright)

Add or enhance tests in src/WingtipToys.AcceptanceTests/ that verify:

  • ProductDetails page shows product image, name, description, and price when navigated via link click from ProductList (this is the enhanced navigation path)
  • ProductList page shows product grid when navigated via navbar link click
  • ShoppingCart page shows cart items after adding a product (form POST → redirect → enhanced nav)
  • All above tests pass WITHOUT data-enhance-nav="false" on the <body> tag

Success Criteria

  • Remove data-enhance-nav="false" from ProjectScaffolder.cs body tag
  • All existing 26 WingtipToys acceptance tests continue to pass
  • New enhanced-nav-specific acceptance tests pass
  • All existing bUnit tests continue to pass
  • New data-binding lifecycle tests pass

Labels

enhancement, component-library, data-binding

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions