Just went through this after having the same issue with the .NET9 Web App Template and the default Authentication pages like Account/Login
when trying to make the whole app operate in @rendermode="InteractiveServer"
as seen in the docs.
Either way the problem for me (and I suspect for you) is that the page gets correctly rendered statically from the server, but after interactivity starts, the client doesn't know about the existence of the page OR the page doesn't support interactivity for some reason and is rendered in Static mode and the result is a flash of content followed by the white page with Not found
but with the source code all visible via View Source.
I ended up resolving it (by allowing Login
to render statically) in the App.razor
page by adding this to the <head>
<HeadOutlet @rendermode="PageRenderMode" />
This to the <body>:
<Routes @rendermode="PageRenderMode" />
This to the @code
section, which is the key piece for my problem in that it ensures pages that don't accept interactive routing are rendered statically.
private IComponentRenderMode? PageRenderMode =>
HttpContext.AcceptsInteractiveRouting() ? InteractiveServer : null;
This solution can also be seen by, in Visual Studio, using the wizard to create a new Blazor Web App and choosing Server render mode and Interactivity location: Global. This code comes from the aspnetcore template and can be found by searching that doc page for (UseServer)
.
Braindump of things that helped:
Testing InteractiveServer
via this code snippet from .net docs:
@page "/render-mode-2"
@rendermode InteractiveServer
<button @onclick="UpdateMessage">Click me</button> @message
@code {
private string message = "Not updated yet.";
private void UpdateMessage()
{
message = "Somebody updated me!";
}
}
Dumping RendererInfo.Name
in my razor file (via .net docs) to find out what mode my page was rendering in. (It was Static
).
<h2>RendererInfo.Name: @RendererInfo.Name</h2>
Creating the aforementioned Server/Global Web App and BeyondCompare'ing it to my application.
Making a page that dumped all the routes to find out if my page was in the route table:
@page "/debug/routes"
@using Microsoft.AspNetCore.Components.Routing
@using System.Reflection
<h3>Discovered Blazor Routes</h3>
<ul>
@foreach (var route in Routes)
{
<li>@route</li>
}
</ul>
@code {
List<string> Routes = new();
protected override void OnInitialized()
{
var assembly = typeof(Program).Assembly;
// will include any Blazor component, even those not inheriting from ComponentBase
var pageTypes = assembly.GetTypes()
.Where(t => typeof(Microsoft.AspNetCore.Components.IComponent).IsAssignableFrom(t))
.Select(t => new
{
Type = t,
PageAttrs = t.GetCustomAttributes(typeof(Microsoft.AspNetCore.Components.RouteAttribute), true)
})
.Where(x => x.PageAttrs.Length > 0);
foreach (var page in pageTypes)
{
foreach (Microsoft.AspNetCore.Components.RouteAttribute attr in page.PageAttrs)
{
Routes.Add($"{attr.Template} ({page.Type.FullName})");
}
}
}
}