dotnet / dotnet/aspnetcore

[Blazor] SSR Error page gets overwritten by NotFound WASM component on InteractiveWebAssembly handoff

Open
#63,842 6 comments 1 reaction 0 assignees View on GitHub
area-blazor
Dominant language
C#
Stars
38.4k
Forks
10.9k
Avg merge
2d 6h
Merged PRs (30d)
290

Description

### Is there an existing issue for this?

- [x] I have searched the existing issues

### Describe the bug

Using the default template with `InteractiveWebAssembly` in .NET 10 (or earlier), the Error page is defined on the Server project, and the Routes are defined in the Client project. When navigating to `/error`, the Error page is rendered statically on the server, then when the client app starts, overwrites the Error page with the NotFound page content on the client.

### Expected Behavior

The default project should demonstrate how to mix server-rendered and client-rendered content properly in the same app. Currently, the default project itself demonstrates mixing the render modes incorrectly.

While putting `@attribute [ExcludeFromInteractiveRouting]` can be considered a workaround, it is undesirable: the layout of the application itself might still be using WebAssembly for even simple interactivity, like collapsing menus. `ExcludeFromInteractiveRouting` bypasses starting the WebAssembly runtime altogether.

Possible solutions:
- Mark server-rendered content to persist on the client after client interactive routing kicks in. Possibly a marker attribute on the element, a directive, or an `@attribute` similar to `ExcludeFromInteractiveRoutingAttribute`.
- Allow `ExcludeFromInteractiveRoutingAttribute` to actually initialize the WebAssembly app, but leave the components marked with this attribute as-is in the DOM. Consider renaming the attribute if so. This might be easy to do using similar mechanics as seen in `PersistentState`
- Allow customizing the `Router`. For example, allow a behavior that lets the router "keep" the content as-is when a navigation event occurs, by overriding/passing `OnNavigatingAsync` or similar, or by inheriting from the built-in `Router`.
- Allow supplying a custom `Router` altogether. This would also allow multiple additional scenarios if community-built routers were to show up: handling localization in the URL, multiple hierarchic routers, etc.
- Allow rendering content on the server and let the client WebAssembly app "consume" the rendered static HTML as interactive. This might be a stretch, but for some simple cases, it can work.
- Modify/implement a new `RenderMode` that allows server-client handoff.

### Steps To Reproduce

`dotnet new blazor --name BlazorSSRCSR --all-interactive --interactivity WebAssembly`
`cd BlazorSSRCSR`
`dotnet run`

Navigate to the created app's `/error` endpoint. The endpoint will show the server side error, then after a short time, the client side router overwrites the content with the client side `NotFound` page content.

### Exceptions (if any)

_No response_

### .NET Version

10.0.100-rc.1.25451.107

### Anything else?

This is NOT the same as similar (possibly slightly related) issues:
- https://github.com/dotnet/aspnetcore/issues/38128
- https://github.com/dotnet/aspnetcore/issues/42561

Note that there's also the implication that if this is done, "mixing" render modes across a hierarchy might become possible. That would also require the user be able to set `RenderMode` to `Static` explicitly, which is currently not possible because it's not even defined in `RenderMode`: it's condered `Static` rendering when the `RenderMode` evaluates to `null`.

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.