Skip to content

Blazor Pre-rendering and PersistingComponentStateSubscription not working correctly with dotnet 9 with InteractiveServer mode? #59198

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
1 task done
MattCost opened this issue Nov 27, 2024 · 8 comments
Labels
area-blazor Includes: Blazor, Razor Components

Comments

@MattCost
Copy link

Is there an existing issue for this?

  • I have searched the existing issues

Describe the bug

Using dotnet 9, blazor with InteractiveServer mode, The PersistingComponentStateSubscription does not seem to work as expected.

After creating a new blazor app from a template, and following the docs to add the PersistingComponentStateSubscription functionality, the page does not work as expected.

Sometimes the state is saved and the page loads correctly, however, most times the render phase will see an empty state, despite the pre-rendering phase saving the data to the ApplicationState.

Questions

Why does the persisting only work sometimes when InteractiveAuto mode is used?
Leaving the InteractiveAuto annotation off the page allows the state to be saved correctly, but well we lose the interactive nature of blazor.

cc: @guardrex dotnet/AspNetCore.Docs#34229

Expected Behavior

PersistingComponentState works every page load when using InteractiveServer mode + PreRendering, or an alternative setup is documented.

Steps To Reproduce

Sample Repo

Steps to reproduce

  1. Make a new template dotnet new blazor
  2. add @rendermode InteractiveServer to the weather page
  3. Start the app
  4. Go to /weather
  5. Observe the double rendering in action.
  6. Add in code from https://learn.microsoft.com/en-us/aspnet/core/blazor/components/prerender?view=aspnetcore-9.0 to use PersistingComponentStateSubscription to save data
  7. Restart the app
  8. Navigate back and forth using the navigation links on the left hand side. (between home and weather and counter). Most times the double rendering still occurs on the weather page, sometimes it does not.
  9. Navigate to /home via the link on the left.
  10. Manually type in /weather into the url
  11. Double rendering never occurs when manually typing in the url

Exceptions (if any)

No response

.NET Version

9.0.100

Anything else?

.NET SDK:
 Version:           9.0.100
 Commit:            a2bc464e40
 Workload version:  9.0.100-manifests.6bf02610
 MSBuild version:   17.12.7+a2bc464e4

Runtime Environment:
 OS Name:     fedora
 OS Version:  41
 OS Platform: Linux
 RID:         fedora.41-x64
 Base Path:   /usr/lib64/dotnet/sdk/9.0.100/

.NET workloads installed:
There are no installed workloads to display.
Configured to use loose manifests when installing new manifests.

Host:
  Version:      9.0.0
  Architecture: x64
  Commit:       a2bc464e40

.NET SDKs installed:
  9.0.100 [/usr/lib64/dotnet/sdk]

.NET runtimes installed:
  Microsoft.AspNetCore.App 9.0.0 [/usr/lib64/dotnet/shared/Microsoft.AspNetCore.App]
  Microsoft.NETCore.App 9.0.0 [/usr/lib64/dotnet/shared/Microsoft.NETCore.App]

Other architectures found:
  None

Environment variables:
  DOTNET_ROOT       [/usr/lib64/dotnet]

global.json file:
  Not found

Learn more:
  https://aka.ms/dotnet/info

Download .NET:
  https://aka.ms/dotnet/download
@ghost ghost added the area-blazor Includes: Blazor, Razor Components label Nov 27, 2024
@javiercn
Copy link
Member

@MattCost thanks for contacting us.

Based on your repro, this seems a dupe of #51584

PersistentComponentState only works on the initial navigation, not during enhanced navigations.

Your repo sets up per-page interactivity, which is why I suspect that when you visit the weather forecast page directly it works, but when you click on it through enhanced navigation it doesn't.

@javiercn javiercn added the Needs: Author Feedback The author of this issue needs to respond in order for us to continue investigating this issue. label Nov 27, 2024
@guardrex
Copy link
Contributor

Just mentioning in passing that we have it covered thus far by NOTEs in the article that advise devs ...

If the app adopts interactive (enhanced) routing and the page is reached via an internal navigation, prerendering doesn't occur. Therefore, you must perform a full page reload for the PrerenderedCounter1 component to see the following output.

... referring to the examples shown. The first NOTE pertains to PrerenderedCounter1, and a similar one follows later for PrerenderedCounter2.

I'm 👂 to see if we'll need to "enhance" the remark on enhanced routing.

@MattCost
Copy link
Author

I am confused by that note. So yes, you need to enhance the note on enhanced routing.

To be honest, I have no idea if I am using Static or Interactive routing. This page makes it seem like that is controlled by the blazor runtime?

Assuming the app does switch to interactive routing because the page is using interactiveServer mode, then I believe the bug report still stands.
If the app adopts interactive (enhanced) routing and the page is reached via an internal navigation, prerendering doesn't occur

The app should switch to using interactive routing, and the page IS reached via an internal navigation. So pre-rendering should not occur. Got it. BUT I am seeing the app show "Loading..." then seeing the data populate twice, despite having the Save stage code in place.

Sample repo linked in original comment was created using dotnet new blazor and no changes were made to App.razor or Routes.razor

@dotnet-policy-service dotnet-policy-service bot added Needs: Attention 👋 This issue needs the attention of a contributor, typically because the OP has provided an update. and removed Needs: Author Feedback The author of this issue needs to respond in order for us to continue investigating this issue. labels Nov 27, 2024
@MattCosturos
Copy link

If you say this is a dupe of that existing issue, I'll take your word for it.

PersistentComponentState only works on the initial navigation, not during enhanced navigations.

Your repo sets up per-page interactivity, which is why I suspect that when you visit the weather forecast page directly it works, but when you click on it through enhanced navigation it doesn't.

I am an experienced c# dev, but this is my first use of blazer. I am not trying to be rude, but my honest feedback is that I find getting into blazor terribly confusing. Even a "simple" page requires a somewhat deep understanding of all the intraicies of blazor functionality.

Could I create a page with a ServerRender mode, and utilize PersistentComponentState, but have the page contain a blazor component rendered in interactive mode?
The goal of my first application was a page having a list of data, with some user-interactivity beneath it. Perhaps using the template app as a starting point send me off the wrong path

@javiercn
Copy link
Member

@MattCosturos thanks, I think the option on the template sent you the wrong way.

Per page interactivity is more powerful yet more complex. If you want simplicity, I'd recommend starting with server and global interactivity.

@javiercn javiercn removed the Needs: Attention 👋 This issue needs the attention of a contributor, typically because the OP has provided an update. label Nov 27, 2024
@MattCost
Copy link
Author

@javiercn
Ok perfect.
Adding <Routes @rendermode="InteractiveServer" /> to App.razor, and removing the per page @rendermode attributes solved the issue.

Closing this issue, since there is already an active issue

@javiercn
Copy link
Member

@MattCost apologies, I wanted to give you a more detailed response, but it seems that I didn't hit send. I'm leaving it here, since it explains in more details what's going on.

https://github.com/MattCost/blazorTest/blob/main/Components/App.razor#L17 <- Your Routes component doesn't define a render mode, which means the app is using Per page interactivity.

The app should switch to using interactive routing, and the page IS reached via an internal navigation. So pre-rendering should not occur. Got it. BUT I am seeing the app show "Loading..." then seeing the data populate twice, despite having the Save stage code in place.

With per page navigation, navigations are handled by enhanced navigation which triggers a request to the server. That's the reason you see your logic get executed twice.

The first time, is the page rendering on the server as a result of enhanced navigation.
The second time, is the page rendering interactively.

The bug that I pointed out covers precisely the situation you are describing. In an enhanced navigation request, the state in PersitingComponentState is not used during the second render, compared to within a regular navigation, in which case it gets reused.

The main reason here being that we only ever supported passing state from the server to the client at the time the runtime initializes, and not after it has already been running.

@IngweLand
Copy link

I was stuck with this issue for hours today. Could you please clarify few more things, because it still does not make sense for me.

The first time, is the page rendering on the server as a result of enhanced navigation.

So, the page is first still rendered on the server even with enhanced navigation? And the docs says that pre-rendering does not happen in case of enhanced navigation. This is really confusing. If that is not a pre-render, then what is that and why does it happen at the first place?

The main reason here being that we only ever supported passing state from the server to the client at the time the runtime initializes, and not after it has already been running.

Well, I can clearly see base64 encoded state in the web-page when PersistentComponentState returns nothing.
My largest confusion in all this is:

  1. OnInitializeAsync is still called twice in any case (meaning, that if it fetches data, then the job is done 2 times)
  2. Page returned from the server have persistent state inside it in any case, adding unnecessary overhead to the bandwidth in case it cannot be used (still really confused why not)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area-blazor Includes: Blazor, Razor Components
Projects
None yet
Development

No branches or pull requests

5 participants