SectionContent doesn't work correctly with render modes
Is there an existing issue for this?
- [X] I have searched the existing issues
Describe the bug
SectionContent doesn't inherit render mode (SectionOutlet does instead).
Expected Behavior
SectionContent should inherit render mode
Steps To Reproduce
In interactive server app add in top-row div in MainLayout.razor
<SectionOutlet SectionName="topbar" />
In Counter.razor add
<SectionContent SectionName="topbar">
<button class="btn btn-primary" @onclick="IncrementCount">Click me</button>
</SectionContent>
The result is that the button in the topbar does not increase the counter.
The workaround is to add interactive server mode to SectionOutlet:
<SectionOutlet SectionName="topbar" @rendermode="@RenderMode.InteractiveServer" />
Then the button is interctive.
However, if the app uses all render modes the bahavior is ugly.
If I have ServerCounter.razor, AutoCounter.razor, WasmCounter.razor (same Counter.razor but with the corresponding render mode) then there is a problem even with the workaround.
In case
<SectionOutlet SectionName="topbar" @rendermode="@RenderMode.InteractiveServer" />
https://github.com/dotnet/aspnetcore/assets/114938397/ca0c3976-06c7-47e1-8847-62085c821e50
Changing to interactive Auto is also bad
https://github.com/dotnet/aspnetcore/assets/114938397/6ef13ce4-7493-46c3-8308-38c0b41fc44a
Exceptions (if any)
No response
.NET Version
No response
Anything else?
No response
@mkArtakMSFT this I feel is related: #51132
Agreed, this issue is related to itself :)
Opps @SteveSandersonMS ... I meant #50998
Thanks for filing this, @surayya-MS! I've been looking into it and think I understand now.
Regarding the initial case you mentioned, i.e.,
In Counter.razor add < SectionContent SectionName="topbar"> <button class="btn btn-primary" @onclick="IncrementCount">Click me < /SectionContent>
There are multiple reasons why this doesn't work:
- Nothing tells the renderer to introduce a rendermode boundary for
SectionOutletContentRenderer- We only introduce a rendermode boundary when a rendermode is set either on the component type itself or at the callsite, and in this case, neither is true
- You might think we could change the code in
SectionOutletthat createsSectionOutletContentRendererand make it explicitly assign the rendermode from_currentContentProvider, but that doesn't actually make sense- ... because then
SectionOutletContentRendererwould become an interactive root, which means we have to serialize all its params, but we can't serialize theRenderFragmentyou're actually trying to render as the section content
- ... because then
- You might think people could work around it themselves by putting some extra layer of component inside the
SectionContent, e.g., aMyButtoncomponent, but that doesn't work either:- Again, it won't be treated as an interactive root if it doesn't have any rendermode set on itself or at the callsite
- You might think you could work around that by setting an explicit rendermode at the callsite, e.g.,
<MyButton @rendermode=... OnClick=SomeCallback />- ... but that doesn't work either because
SomeCallbackwill be a delegate and hence can't be serialized, so even thoughMyButtonnow does run as a server component, it can't invoke a callback like you want it to
- ... but that doesn't work either because
Altogether the intuition for why this can't work is that it would involve creating an interactive root for the section outlet, but how would we serialize a definition of what content should go into it? There isn't an actual component name for the content (it's just a RenderFragment) and in general you can be referring to nonserializable things.
To make something like this work, we'd need some further abstraction around the idea of a component marker, so that instead of just describing a type+params, it would have to describe some kind of abstract slot that may later be filled by interactively-generated content. Maybe we'd have a special marker specifically for "section outlet" based on its name.
Thanks for contacting us.
We're moving this issue to the .NET 9 Planning milestone for future evaluation / consideration. We would like to keep this around to collect more feedback, which can help us with prioritizing this work. We will re-evaluate this issue, during our next planning meeting(s).
If we later determine, that the issue has no community involvement, or it's very rare and low-impact issue, we will close it - so that the team can focus on more important and high impact issues.
To learn more about what to expect next and how this issue will be handled you can read more about our triage process here.
Thanks for contacting us.
We're moving this issue to the .NET 9 Planning milestone for future evaluation / consideration. We would like to keep this around to collect more feedback, which can help us with prioritizing this work. We will re-evaluate this issue, during our next planning meeting(s).
If we later determine, that the issue has no community involvement, or it's very rare and low-impact issue, we will close it - so that the team can focus on more important and high impact issues.
To learn more about what to expect next and how this issue will be handled you can read more about our triage process here.
There are two parts involved here:
- Throw an error when the render modes between SectionContent and SectionOutlet don't match
- Find a proper solution to avoid this problem altogether
We'll use this issue to track no. 1 above.
The PageTitle issues 52368/50267/50268/52689, got closed just because it is related to this one. Not sure how they are related, but in all the tickets for the PageTitle issue, I never found a work around. So is PageTitle just broke until .net 9 comes out?
@nateinindy Would it be possible to file an issue with repro steps for your scenario? We don't know for sure what specific problem you might be encountering.
Hey Steve. Yeah, the following code does not set the page title.
@page "/test"
@rendermode @(new InteractiveServerRenderMode(false))
<PageTitle>@pageTitle</PageTitle>
@code {
private string pageTitle = "";
protected override async Task OnInitializedAsync()
{
await Task.Delay(1);
pageTitle = "no show";
}
}
Thanks for clarifying, @nateinindy. I'm reopening https://github.com/dotnet/aspnetcore/issues/50268 since that seems like the best issue for tracking the specific limitation with PageTitle.
Any progress on this issue? Just want to mention that this functionality is critical to SEO, as no head elements are rendered when bots (for example Google crawler) are indexing the page. This is a really serious blocker for websites.
Enabling prerender is not an answer for production pages, as the flicker is bad for usability.