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.37k stars 9.99k forks source link

[Blazor] Auto Render not working properly in .NET 8 and page locks until WebAssembly start #52154

Closed AmBplus closed 9 months ago

AmBplus commented 11 months ago

Is there an existing issue for this?

Describe the bug

I updated Visual Studio to the latest version 17.8.0 and created a Blazor app using Auto render mode With Dotnet 8. When I run the application and navigate to the Counter tab, the whole page locks up until the WebAssembly Start. I can't do anything or switch to another tab until the download Finished And WebAssembly Start, even though it happens quickly locally. This could cause problems in production where the download may take longer. It also goes against the purpose of Auto render mode.

Expected Behavior

With auto render mode, the page should initially use server-side rendering. Once WebAssembly finishes downloading And Start, it can switch over seamlessly without locking up the page.

Steps To Reproduce

No response

Exceptions (if any)

No response

.NET Version

NET 8 , Windows 10-64

Anything else?

As you can see, the page is locked and prevents navigating to another tab.

lockPage
mikes-gh commented 8 months ago

Ok So I'm confused when this fix will be released. This issue is milestone 8.0.2 but the corresponding PR is 9.0-preview1. Surely Render mode auto won't be broken until net9.0?

danroth27 commented 8 months ago

Ok So I'm confused when this fix will be released. This issue is milestone 8.0.2 but the corresponding PR is 9.0-preview1. Surely Render mode auto won't be broken until net9.0?

@mikes-gh This issue will be fixed in both 8.02 and 9.0 Preview 1. Expected release timeframe is mid-Feb.

bcookew commented 8 months ago

Hiya,

Did this go live in 8.0.2 as expected? I am running:

Behavior seems similar / the same at least in development. But perhaps I have misunderstood the fix... Does the fix correct the behavior without developer intervention or do we still need to modify the Blazor startup in some way?

Thanks for you efforts!

ashishsinha24 commented 8 months ago

Same here.

mikes-gh commented 8 months ago

Looks like it only got merged 10 hours ago and is labelled 8.0.3 https://github.com/dotnet/aspnetcore/pull/54011 Can someone confirm it missed 8.0.2?

wtgodbe commented 8 months ago

Looks like it only got merged 10 hours ago and is labelled 8.0.3 https://github.com/dotnet/aspnetcore/pull/54011 Can someone confirm it missed 8.0.2?

That label is misleading, that PR is a mechanical one that brings in any internal fixes from the previous month. All of the commits in that PR, except for the last 2, were internal commits that were included with 8.0.2. If you browse the commit history from the v8.0.2 tag (below), you can see that the render mode fix was included in 8.0.2.

https://github.com/dotnet/aspnetcore/commits/v8.0.2/

@MackinnonBuck any thoughts on why customers might not be seeing the new behavior with the change?

MackinnonBuck commented 8 months ago

The fix was included in 8.0.2. I confirmed this by installing the SDK on a fresh machine and testing a Blazor Web App with "Auto" interactivity by creating a new project from the project template. All that should be required for existing projects is updating Microsoft.AspNetCore.Components.* packages to use version 8.0.2.

My verification steps were the following:

  1. Create the project using dotnet new blazor -int Auto
  2. Start the project using dotnet run
  3. Navigate to the app's URL
  4. Open the browser dev tools window (Edge)
  5. In the network tab, select Fast 3G (or Slow 3G) throttling
  6. Navigate to the counter page
  7. Observe that WebAssembly resource downloads are throttled, allowing server interactivity to start before WebAssembly resources finish downloading

A few notes/caveats:

For those that see issues not described by the above, could you describe what problem you're seeing? Thanks!

MackinnonBuck commented 8 months ago

For those that see issues not described by the above, could you describe what problem you're seeing? Thanks!

To expand on this, if someone can point out to a difference in behavior between 8.0.2 and the fix that I linked in a previous comment, that would potentially point to a bug. Thanks!

mikes-gh commented 8 months ago

@MackinnonBuck For me I made sure all my references were 8.0.2 I had previously tested your hotfix successfully. As a preliminary test using 8.0.2 the problem of delayed server interactivity returns the same as before.

image

Although I thought previously without the fix the websocket came after all the libraries for the app had downloaded. It seems now only the main dotnet wasm runtime comes before the websocket so maybe the delay is something else locally like debugger startup. I probably need to setup both senarios alonside each other to be sure

bcookew commented 8 months ago

A small update. My experience of that delay and switchover to wasm rather than staying in interactive server has been resolved. I think I caused my own problem by trying to implement an undocumented (unsupported) project configuration. I was experimenting with adding a second client project with the same setup as the original and then when I couldn't determine how to resolve an issue around Static Assets paths to the two projects I deleted one... You can probably see where this is going.

I thoughtlessly deleted the original client project instead of the one I added and didn't observe that there was an extra package reference.

<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.DevServer" Version="8.0.2" PrivateAssets="all" />

As soon as I realized that this was the only difference I could find between a fresh template and my project I removed it, cleaned, rebuilt, ran without debugging, and there it was. The behavior was working correctly as you had described.

Apologies for reopening this can of worms over an error on my part.

david-at-solve commented 8 months ago

Auto-mode now works as expected, thank you!

danroth27 commented 8 months ago

Same here.

@ashishsinha24 Can you share more details about the issue you're still seeing?

ashishsinha24 commented 8 months ago

Same here.

@ashishsinha24 Can you share more details about the issue you're still seeing?

I am still seeing that the app locks until the wasm is downloaded. I am seeing it in debug and release versions. I am using Radzen controls. Maybe the problem is specific to this. I haven't had the time to fully test it.

MackinnonBuck commented 8 months ago

@ashishsinha24,

I am still seeing that the app locks until the wasm is downloaded.

If the app is locking up, it's probably the WebAssembly runtime starting, not being downloaded. The WebAssembly runtime starts synchronously, which is why the webpage becomes temporarily non-interactive. Does the same thing happen when using an InteractiveWebAssembly render mode? If so, that would indicate that this is not a problem with the InteractiveAuto mode, but rather a performance characteristic of WebAssembly runtime startup.

mikes-gh commented 8 months ago

@MackinnonBuck

  1. Is it expected that wasm dotnet runtime downloads and starts up before the websocket for InteractiveServer becomes available?
  2. Which exact libraries does your fix alter.

TIA

MackinnonBuck commented 8 months ago

Is it expected that wasm dotnet runtime downloads and starts up before the websocket for InteractiveServer becomes available?

It's not expected, but I don't think this is what's happening in the screenshot you shared. If you're pointing out that dotnet.native.wasm gets downloaded before the websocket connects, that's somewhat of a timing coincidence, and the download of dotnet.native.wasm doesn't block the circuit starting up. If you test using "Slow 3G" performance, you might find that the websocket can connect before dotnet.native.wasm fully downloads. But the WebAssembly runtime doesn't actually start until all .wasm downloads have completed.

Which exact libraries does your fix alter.

The fix only alters blazor.web.js, which is an embedded resource in Microsoft.AspNetCore.Components.Endpoints.dll, which is part of the ASP.NET Core shared framework.

Andrzej-W commented 8 months ago

I tested a new application created as Global InteractiveAuto and everything works as expected. I can switch between pages and Counter page is interactive while wasm files are loaded.

@ashishsinha24 I have no experience with Radzen components, but I have some with DevExpress. Simple application with one DxGrid downloads A LOT of files and it is huge. Here is an interesting blog post: https://community.devexpress.com/blogs/aspnet/archive/2023/03/16/blazor-webassembly-aot-compilation-and-link-trimming.aspx

Maybe you see the problem described by @MackinnonBuck (WebAssembly startup.) On a fast computer I have to wait 1 s. before WebAssembly app with DevExpress components will be interactive. On iPhone 6s and laptop with Intel Core i7-6500U processor I have to wait about 4 s. It is possible that app with Radzen component also needs a few seconds to start on your hardware.

mikes-gh commented 8 months ago

@MackinnonBuck

But the WebAssembly runtime doesn't actually start until all .wasm downloads have completed.

If the app is locking up, it's probably the WebAssembly runtime starting, not being downloaded. The WebAssembly runtime starts synchronously, which is why the webpage becomes temporarily non-interactive. Does the same thing happen when using an InteractiveWebAssembly render mode? If so, that would indicate that this is not a problem with the InteractiveAuto mode, but rather a performance characteristic of WebAssembly runtime startup.

I'm a bit lost on the order of things. I hadn't considered that the WebAssembly runtime starting could block the Blazor Server interactivity.

So if the app downloads quite quickly then the WebAssembly runtime starting can still block the Blazor Server interactivity giving the same feel that the app is not responding even though the websocket is open?

MackinnonBuck commented 8 months ago

So if the app downloads quite quickly then the WebAssembly runtime starting can still block the Blazor Server interactivity giving the same feel that the app is not responding even though the websocket is open?

I should have been clearer - the WebAssembly runtime (as in the code from the .Client project) won't actually start until all .wasm downloads have completed and a component requires WebAssembly interactivity. So, if you had an InteractiveServer component and InteractiveWebAssembly component on the same page, the starting of the WebAssembly runtime could momentarily block interactivity for the InteractiveServer component. But this shouldn't happen when only using the InteractiveAuto render mode. If you do see a delay like that, it's probably because the InteractiveAuto component is using WebAssembly interactivity.

saintarian commented 8 months ago

Thanks for the fix, @MackinnonBuck. I updated my SDK to 8.0.2 and tried on a new project and the issue looks fixed. However, I see that all the wasm files are downloaded serially (see image below). Is there a way to make this parallel (or, say 10 degrees of parallelism), while still having the websocket connection be established before the wasm is downloaded?

Screenshot 2024-02-16 at 5 25 46 PM
Andrzej-W commented 8 months ago

@saintarian you cannot download 10 files concurrently because your application will be unusable. Maybe it is not a problem on high speed fiber Internet connection but try to download a few files concurrently using cellular network and check latency with ping command.

bxjg1987 commented 8 months ago

Regarding the content here, the official document does not seem to provide a detailed explanation. Would you like to supplement this document

bcookew commented 8 months ago

It may be unrelated and specific to something I have done in my app but... Is anyone having difficulty with InteractiveAuto since the last update when using: @rendermode @(new InteractiveAutoRenderMode(prerender: false)) The page I am trying to render is injecting services from the WASM service collection which is why I am not pre-rendering. Page loads no issues with @rendermode @(new InteractiveWebAssemblyRenderMode(prerender: false)) But when using auto I get nothing loading and if I navigate to another page I get a circuit exception. image

The component loads normally if I refresh the page once or twice. Maybe a BrowserLink / Debugging issue? I did notice that after navigating to the page the DevTools Debugger does briefly hold on an unhandled exception but even with "Pause on uncaught exceptions" ticked it jumps over it so quickly I can't catch it.

Edit: I was not trying to use prerender = false prior to the 8.0.2 update so I don't know if this is new behavior since the changes talked about above.

danielgreen commented 8 months ago

@bcookew If the page initially loads in server mode then it will be trying to resolve the injected dependencies from the server side service provider. The dependencies will need to be present there, if they're not that could explain the problems.

bcookew commented 8 months ago

@bcookew If the page initially loads in server mode then it will be trying to resolve the injected dependencies from the server side service provider. The dependencies will need to be present there, if they're not that could explain the problems.

Good offer. That was, in truth, where I started my day. I had a look at the MS Docs related to render modes here. And followed their advice to set prerender to false. This did indeed clear the DI issue but left me with this odd behavior where the page never loads unless I refresh a couple of times.

Open to further thoughts / discussion on this for sure!

danielgreen commented 8 months ago

@bcookew It still sounds like a DI issue. Setting prerender to false will still mean it tries to load in server (SignalR) mode initially. Then when you refresh, if the wasm resources have been downloaded by that point then after refreshing it will switch to wasm mode. So you still need to ensure the dependencies can be resolved server side, or change the render mode from Auto to WebAssembly.

bcookew commented 8 months ago

@danielgreen Thanks, I will dig deeper around that.

Evengard commented 7 months ago

I stumbled upon a similar problem. A browser which doesn't have WASM or WASM is disabled alltogether. I tested with Firefox setting javascript.options.wasm to false. I'd expect it to still work using server-side rendering. Instead, it seems like it crashes and no interactivity works.