dotnet / aspnetcore

ASP.NET Core is a cross-platform .NET framework for building modern cloud-based web applications on Windows, Mac, or Linux.
https://asp.net
MIT License
35.57k stars 10.05k forks source link

New Blazor Web Application, navigate to the server project's component auto display "Not Found". #58480

Closed DillionVVV closed 1 month ago

DillionVVV commented 1 month ago

Is there an existing issue for this?

Describe the bug

I create a Blazor web application via the Blazor Web App Template, then in the Blazor Server project add a Test component (set the rendermode as InteractiveServer), after running the application and navigate to the Test page, firstly it will show the Test page content, after some seconds (2 or 3 seconds), it will auto display "Not Fount" in the page.

Expected Behavior

After redirecting to test page, it should stay on the test page instead of showing "Not Found".

Steps To Reproduce

  1. Create a new Blazor application using the Blazor Web App Template. In the Additional Information window, select the "Auto (Server and WebAssembly)" Interactive render mode and "Global" Interactivity location: Image

  2. In the Server project, add a Testpage component in the Components/Pages folder, like this:

    Image

  3. Running the application, navigate to the Test page, firstly the output as below:

    Image

    then, a few seconds later, it will auto display "Not Found", like this:

    Image

Exceptions (if any)

No exceptions.

.NET Version

.net version: 8.0.403 and 9.0.100-rc.2.24474.11

Anything else?

I check it using the following version of VS 2022, both of them show the same issue:

Microsoft Visual Studio Community 2022 (64-bit) - Current Version 17.11.5

Microsoft Visual Studio Community 2022 (64-bit) - Preview Version 17.12.0 Preview 3.0

Besides, I also compare it with my old Blazor Web Application, it seems that this issue relate the Routes.razor component and the Layout content, in previous projects, these files are in the Server project, but now they are in the Client project.

Image

If I add the Test component in the client project, or move the Routes.razor and Layout content from client project to the server project, it doesn't show the "Not Found" issue.

javiercn commented 1 month ago

@DillionVVV thanks for contacting us.

The test page must be defined in the .Client project. What's happening is that the page first prerenders on the server, and when webassembly starts, it tries to render the same page, but fails to do so because the code is not present in the client assembly.

DillionVVV commented 1 month ago

@DillionVVV thanks for contacting us.

The test page must be defined in the .Client project. What's happening is that the page first prerenders on the server, and when webassembly starts, it tries to render the same page, but fails to do so because the code is not present in the client assembly.

Hi @javiercn

Thanks for your reply.

But if we have to add Interactive Server component, the component must be in the server project, if we put them in the client project, it will cause another error. Like this:

Image

So, I think we'd better to put the Layout folder and Routes component in the Server project.

javiercn commented 1 month ago

Fundamentally when you use Webassembly our auto, your app is broken up in two separate processes.

If your component needs to run on webassembly it needs to live in the .Client project.

If your app is using full interactivity as opposed to per-page interactivity you can't mix and match. Meaning you can't put a server-component when the whole app is running on webassembly already.

DillionVVV commented 1 month ago

Hi @javiercn

I fully understand the render mode of the Blazor Web App project you are talking about, and how it works. When create Asp.net 8 Blazor application using Blazor Web App template, based on selected render mode, the Layout folder and Routes. razor is either in the server project in the Components folder or at the root of the .Client project. If we select the Auto mode, it will create two projects: the main project (server project) and .client project. we need to put the server-side rendering component in the server project and put the client-side rendering component in the .client project.

But now the problem is that: after selecting the "Auto (Server and WebAssembly)" render mode, these files (Layout content and Routes.razor) were previously in the server project but now in the client project. Then when we navigate to the server side components (in the server project), it will show server page first and then auto display "Not Found". This is obviously not what we want, you can according to the steps (in my original post) to reproduce the problem, this might be a bug.

javiercn commented 1 month ago

@DillionVVV thanks for contacting us.

If you setup auto and global interactivity you need to do extra work to opt-out of rendering specific pages in auto mode, given the render mode is specified on the Routes component.

You need to do something similar to this:

<!DOCTYPE html>
<html>
<head>
    ...
    <HeadOutlet @rendermode="@PageRenderMode" />
</head>
<body>
    <Routes @rendermode="@PageRenderMode" />
    ...
</body>
</html>

@code {
    [CascadingParameter]
    private HttpContext HttpContext { get; set; } = default!;

    private IComponentRenderMode? PageRenderMode
        => HttpContext.GetEndpoint().Metadata.GetMetadata<RenderModeAttribute>() is { Mode: RenderMode.InteractiveServer } ? InteractiveServer : RenderMode.Auto;
}

Note that you can't have components that render in webassembly inside components that render on server and viceversa, so given that you are using interactivity for the entire app, you have to choose at the time the page is rendering.

DillionVVV commented 1 month ago

Hi @javiercn,

You are right, when using the default template, in the main (server) project, it will set the InteractiveAuto render mode in the App.razor page:

<!DOCTYPE html>
<html lang="en">

<head>
     ...
    <HeadOutlet @rendermode="InteractiveAuto" />
</head>

<body>
    <Routes @rendermode="InteractiveAuto" />
    <script src="_framework/blazor.web.js"></script>
</body>

</html>

After changing the render mode using the following code, the problem resolved.

<!DOCTYPE html>
<html>
<head>
    ...
    <HeadOutlet @rendermode="@PageRenderMode" />
</head>
<body>
    <Routes @rendermode="@PageRenderMode" />
    ...
</body>
</html>

@code {
    [CascadingParameter]
    private HttpContext HttpContext { get; set; } = default!;

    private IComponentRenderMode? PageRenderMode
        => HttpContext.GetEndpoint().Metadata.GetMetadata<RenderModeAttribute>()?.Mode;
}

But I think we better change the default template so that when we create a new Blazor Web App application (select Auto mode), the issue of 'Not Found' will not occur.

Update:

When I use Microsoft Visual Studio Community 2022 (64-bit) - Preview Version 17.12.0 Preview 3.0 and the above workaround, the problem is resolved.

But after upgrade the VS 2022 to the latest version (Microsoft Visual Studio Community 2022 (64-bit) - Preview Version 17.12.0 Preview 4.0), the above workaround will not be working, and the issue of 'Not Found' will occur again.

So, now there only have one solution: move the Routes.razor and Layout content from client project to the server project. Please fix this template issue and directly add them in the server project.

DM-98 commented 1 month ago

@javiercn nor @DillionVVV solution do not work in .NET 9 RC2:

private IComponentRenderMode? PageRenderMode => HttpContext.GetEndpoint()?.Metadata.GetMetadata<RenderModeAttribute>()?.Mode == RenderMode.InteractiveServer ? RenderMode.InteractiveServer : HttpContext.AcceptsInteractiveRouting() ? InteractiveAuto : null;

I do get:

Cannot create a component of type 'Faluf.Trading.Blazor.Client.Pages.CultureServer' because its render mode 'Microsoft.AspNetCore.Components.Web.InteractiveServerRenderMode' is not supported by WebAssembly rendering.

FYI; InteractiveAuto Global. All components in .Client, one component tested on with @attribute InteractiveServer

@javiercn Once told me this isn't supported and is by design... But they have documentation multiple places stating to be able to do this...

DillionVVV commented 1 month ago

Hi @javiercn

When I use Microsoft Visual Studio Community 2022 (64-bit) - Preview Version 17.12.0 Preview 3.0 and the previous workaround, the problem is resolved.

But after upgrade the VS 2022 to the latest version (Microsoft Visual Studio Community 2022 (64-bit) - Preview Version 17.12.0 Preview 4.0), the above workaround will not be working, and the issue of 'Not Found' will occur again.

So, now there only have one solution: move the Routes.razor and Layout content from client project to the server project. Please fix this template issue and directly add them in the server project.

dotnet-policy-service[bot] commented 1 month ago

This issue has been resolved and has not had any activity for 1 day. It will be closed for housekeeping purposes.

See our Issue Management Policies for more information.