dotnet / AspNetCore.Docs

Documentation for ASP.NET Core
https://docs.microsoft.com/aspnet/core
Creative Commons Attribution 4.0 International
12.54k stars 25.3k forks source link

Prerendered hosted Blazor WASM errors not addressed by guidance #28443

Open Krangth opened 1 year ago

Krangth commented 1 year ago

The instructions regarding setting up a solution with working WebAssemblyPrerendered are too difficult to follow. I have spent several hours trying to follow along and I just cannot get it to work.

Step 4 says: Add _Host.cshtml and _Layout.cshtml files to the Server project's Pages folder. You can obtain the files from a project created from the Blazor Server template using Visual Studio or using the .NET CLI with the dotnet new blazorserver -o BlazorServer command in a command shell (the -o BlazorServer option creates a folder for the project). After placing the files into the Server project's Pages folder, make the following changes to the files.

That template does not contain a _Layout.cshtml file.

I encountered numerous error messages and I couldn't find any information on how to resolve them. I'm going to switch to a Blazor Server solution instead.

I think that there should be two dotnet new templates for a blazor wasm hosted with prerendering enabled. One with auth and one without auth. Then I could at least do a diff on my solution versus the working solution.


Document Details

โš  Do not edit this section. It is required for learn.microsoft.com โžŸ GitHub issue linking.

guardrex commented 1 year ago

There isn't too much I can do about it ... just the complexity aspect that is. This is (or was given that it hasn't been checked since perhaps the 6.0 release) ... this is the set of required steps to set it up.

WRT ...

That template does not contain a _Layout.cshtml file.

That's for 6.0. In 7.0, they went back to _Host.cshtml. I'll check to confirm that that step is versioned properly. If you're looking at the 6.0 version of the topic, that's fine. If you're looking at the 5.0 or 7.0 version of the topic, that shouldn't be there.

I think that there should be two dotnet new templates for a blazor wasm hosted with prerendering enabled. One with auth and one without auth. Then I could at least do a diff on my solution versus the working solution.

That would have to be a product unit request provided to them on their repo at ...

https://github.com/dotnet/aspnetcore/issues

As for this issue, let's leave it here for me to take some time and check the guidance against 7.0 to see if I can get it to work these days ... if not to get it working for >=7.0. I'm buried in security updates for a few more weeks, so I think the soonest that I would reach this is in March.

guardrex commented 1 year ago

No ... actually ... you are looking at the 6.0 version of the topic. If you use the doc version selector and look at the 7.0 version of the topic, that content on _Layout.cshtml in the Pages folder of the client app goes away correctly. I did get the versioning correct on that.

Ok ... so that's fine. I do need to check the whole process tho against 7.0 to see if I can get it to ๐Ÿ’ฅ ... or work. I'll get back to this as soon as I can.

Krangth commented 1 year ago

I mistakenly had not considered that the dotnet new command was creating the project for .net 7 and not .net 6.

However, I also followed the instructions for creating a new hosted option dotnet new blazorwasm -ho and the instructions appear to work correctly. But if the user clicks any links too soon the page produces an error. And if the user reloads any page, except the home page, a 404 error appears. Is that expected? That means a user wouldn't be able to share a link.

guardrex commented 1 year ago

I'm not sure. I'll definitely take that into account when I walk the steps to see what's what. If we need product unit support for items like that, I'll probably refer you to the product repo to open an issue for them. First, let me see if I can reproduce those behaviors here.

I was thinking that I'd like to push this to beyond the security work, but I'll do it on Tuesday morning. We're on a three-day holiday for President's Day ... back on Tuesday. I'll get back to you.

guardrex commented 1 year ago

I'm going to walk these steps right now. Unfortunately, I've been up since 3am due to a family member's coughing related to COVID. ๐Ÿค• There is nothing else to do around here at this hour but work! ๐Ÿคฃ

I mistakenly had not considered that the dotnet new command was creating the project for .net 7 and not .net 6.

It's probably worth mentioning at the start of the whole section that the reader should be careful to look at the version of the document for the version of ASP.NET Core that they're adopting, so I'll at least call that out.

I'll be back in a bit. I'll see if I can repro what you reported.

guardrex commented 1 year ago

Ok ... let's take these one at a time ...

> But if the user clicks any links too soon the page produces an error.

I can't detect any problems. However, I'm using a very FAST ๐Ÿƒ PC here.

Also, you didn't say what links you're clicking that are failing, nor did you indicate what error or behavior you're seeing.

> And if the user reloads any page, except the home page, a 404 error appears. Is that expected? That means a user wouldn't be able to share a link.

๐Ÿ˜ฎ I wasn't aware of this! As you said ... when reloading on the FetchData page or opening another browser and attempting to navigate directly to that page, I get ...

InvalidOperationException: Cannot provide a value for property 'Http' on type 'BlazorHosted.Client.Pages.FetchData'. There is no registered service of type 'System.Net.Http.HttpClient'.

Full stack trace for reference (I'll need this in a sec because I'm going to report this) ...

System.InvalidOperationException: Cannot provide a value for property 'Http' on type 'BlazorHosted.Client.Pages.FetchData'. There is no registered service of type 'System.Net.Http.HttpClient'.
   at Microsoft.AspNetCore.Components.ComponentFactory.<>c__DisplayClass7_0.<CreateInitializer>g__Initialize|1(IServiceProvider serviceProvider, IComponent component)
   at Microsoft.AspNetCore.Components.ComponentFactory.PerformPropertyInjection(IServiceProvider serviceProvider, IComponent instance)
   at Microsoft.AspNetCore.Components.ComponentFactory.InstantiateComponent(IServiceProvider serviceProvider, Type componentType)
   at Microsoft.AspNetCore.Components.RenderTree.Renderer.InstantiateChildComponentOnFrame(RenderTreeFrame& frame, Int32 parentComponentId)
   at Microsoft.AspNetCore.Components.RenderTree.RenderTreeDiffBuilder.InitializeNewComponentFrame(DiffContext& diffContext, Int32 frameIndex)
   at Microsoft.AspNetCore.Components.RenderTree.RenderTreeDiffBuilder.InitializeNewSubtree(DiffContext& diffContext, Int32 frameIndex)
   at Microsoft.AspNetCore.Components.RenderTree.RenderTreeDiffBuilder.InsertNewFrame(DiffContext& diffContext, Int32 newFrameIndex)
   at Microsoft.AspNetCore.Components.RenderTree.RenderTreeDiffBuilder.AppendDiffEntriesForRange(DiffContext& diffContext, Int32 oldStartIndex, Int32 oldEndIndexExcl, Int32 newStartIndex, Int32 newEndIndexExcl)
   at Microsoft.AspNetCore.Components.RenderTree.RenderTreeDiffBuilder.ComputeDiff(Renderer renderer, RenderBatchBuilder batchBuilder, Int32 componentId, ArrayRange`1 oldTree, ArrayRange`1 newTree)
   at Microsoft.AspNetCore.Components.Rendering.ComponentState.RenderIntoBatch(RenderBatchBuilder batchBuilder, RenderFragment renderFragment, Exception& renderFragmentException)
   at Microsoft.AspNetCore.Components.RenderTree.Renderer.ProcessRenderQueue()
--- End of stack trace from previous location ---
   at Microsoft.AspNetCore.Components.RenderTree.Renderer.ProcessRenderQueue()
   at Microsoft.AspNetCore.Components.RenderTree.Renderer.AddToRenderQueue(Int32 componentId, RenderFragment renderFragment)
   at Microsoft.AspNetCore.Components.ComponentBase.StateHasChanged()
   at Microsoft.AspNetCore.Components.ComponentBase.CallOnParametersSetAsync()
   at Microsoft.AspNetCore.Components.ComponentBase.RunInitAndSetParametersAsync()
   at Microsoft.AspNetCore.Components.RenderTree.Renderer.RenderRootComponentAsync(Int32 componentId, ParameterView initialParameters)
   at Microsoft.AspNetCore.Components.Rendering.HtmlRenderer.RenderComponentAsync(Type componentType, ParameterView initialParameters)
   at Microsoft.AspNetCore.Components.Rendering.RendererSynchronizationContext.<>c__11`1.<<InvokeAsync>b__11_0>d.MoveNext()
--- End of stack trace from previous location ---
   at Microsoft.AspNetCore.Mvc.ViewFeatures.StaticComponentRenderer.PrerenderComponentAsync(ParameterView parameters, HttpContext httpContext, Type componentType)
   at Microsoft.AspNetCore.Mvc.ViewFeatures.ComponentRenderer.PrerenderedWebAssemblyComponentAsync(HttpContext context, Type type, ParameterView parametersCollection)
   at Microsoft.AspNetCore.Mvc.ViewFeatures.ComponentRenderer.RenderComponentAsync(ViewContext viewContext, Type componentType, RenderMode renderMode, Object parameters)
   at Microsoft.AspNetCore.Mvc.TagHelpers.ComponentTagHelper.ProcessAsync(TagHelperContext context, TagHelperOutput output)
   at Microsoft.AspNetCore.Razor.Runtime.TagHelpers.TagHelperRunner.<RunAsync>g__Awaited|0_0(Task task, TagHelperExecutionContext executionContext, Int32 i, Int32 count)
   at BlazorHosted.Server.Pages.Pages__Host.<ExecuteAsync>b__14_1() in C:\Users\guard\OneDrive\Desktop\BlazorHosted\Server\Pages\_Host.cshtml:line 20
   at Microsoft.AspNetCore.Razor.Runtime.TagHelpers.TagHelperExecutionContext.SetOutputContentAsync()
   at BlazorHosted.Server.Pages.Pages__Host.ExecuteAsync()
   at Microsoft.AspNetCore.Mvc.Razor.RazorView.RenderPageCoreAsync(IRazorPage page, ViewContext context)
   at Microsoft.AspNetCore.Mvc.Razor.RazorView.RenderPageAsync(IRazorPage page, ViewContext context, Boolean invokeViewStarts)
   at Microsoft.AspNetCore.Mvc.Razor.RazorView.RenderAsync(ViewContext context)
   at Microsoft.AspNetCore.Mvc.ViewFeatures.ViewExecutor.ExecuteAsync(ViewContext viewContext, String contentType, Nullable`1 statusCode)
   at Microsoft.AspNetCore.Mvc.ViewFeatures.ViewExecutor.ExecuteAsync(ViewContext viewContext, String contentType, Nullable`1 statusCode)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeNextResultFilterAsync>g__Awaited|30_0[TFilter,TFilterAsync](ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Rethrow(ResultExecutedContextSealed context)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.ResultNext[TFilter,TFilterAsync](State& next, Scope& scope, Object& state, Boolean& isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.InvokeResultFilters()
--- End of stack trace from previous location ---
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeNextResourceFilter>g__Awaited|25_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Rethrow(ResourceExecutedContextSealed context)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.InvokeFilterPipelineAsync()
--- End of stack trace from previous location ---
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Awaited|17_0(ResourceInvoker invoker, Task task, IDisposable scope)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Awaited|17_0(ResourceInvoker invoker, Task task, IDisposable scope)
   at Microsoft.AspNetCore.Routing.EndpointMiddleware.<Invoke>g__AwaitRequestTask|6_0(Endpoint endpoint, Task requestTask, ILogger logger)
   at Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context)
   at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context)
   at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddlewareImpl.Invoke(HttpContext context)

Also, when reloading rapidly on the Counter page, I get a client-side (i.e., in the console) error. The following only happens when I reload rapidly, not slowly. Relatively slow reloads seem to be fine.

System.AggregateException: One or more errors occurred. (error loading dynamically imported module ---> Microsoft.JSInterop.JSException: error loading dynamically imported module

at Microsoft.JSInterop.JSRuntime.d__16`1[[Microsoft.JSInterop.IJSObjectReference, Microsoft.JSInterop, Version=7.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60]].MoveNext() at Microsoft.AspNetCore.Components.WebAssembly.HotReload.WebAssemblyHotReload.InitializeAsync() at Microsoft.AspNetCore.Components.WebAssembly.Hosting.WebAssemblyHost.RunAsyncCore(CancellationToken cancellationToken, WebAssemblyCultureProvider cultureProvider) at Program.

$(String[] args) --- End of inner exception stack trace ---

Opening for the product unit

I'll open a product unit issue on these and ping you on it.

guardrex commented 1 year ago

Ok, that issue on their repo will get us started here, but I'm going to put in a quick "addresses" PR to call out that the reader should be careful with which version of the topic that they're consuming relative to the version of ASP.NET Core that they're working in. As you say, looking at the 6.0 version of the topic and working in 5.0 or 7.0+ will be very confusing given the churn on the _Layout.cshtml file, which was only used for the 6.0 release.

guardrex commented 1 year ago

@Krangth ... Since Artak just labelled that for .NET 8 investigation, it could take a little while to address these problems. Let's leave this docs issue open. I'll just mark it 'blocked' for now. I'll keep an ๐Ÿ‘๏ธ on the PU issue to see how it plays out.

guardrex commented 1 year ago

UPDATE (7/6): I've learned that the hosted WASM hosting option is going away for 8.0 and later. I'm asking on the PU issue if they still plan to investigate these problems for <8.0. If they just close it out as a won't-fix scenario, then we probably won't ever get an answer on these problems. Stand-by .... They'll probably respond shortly to my ask, and I'll remark here on their decision.

guardrex commented 11 months ago

UPDATE (10/2): The PU issue is still open and is scheduled for this release. They might bump it ... not sure. I'll continue to monitor that issue and see how it plays out. In the meantime, we have new integration guidance for the upcoming .NET 8 release that's hot off the presses ...

https://learn.microsoft.com/en-us/aspnet/core/blazor/components/integration?view=aspnetcore-8.0

It favors server rendering with a BWA, but WebAssembly component rendering should work fine if the app is configured for it via the Render modes article. We won't be updating the guidance specifically for hosted WebAssembly apps created from the hosted WebAssembly project template of <8.0. For >=8.0, devs are encouraged to adopt a BWA to host WebAssembly-rendered components in spite of hosted WASM continuing to be supported by the product unit in 8.0.

guardrex commented 7 months ago

Update (1/17/24): It was moved to .NET 9 for PU investigation. I'm going to place this issue on On Hold until they take a look.

guardrex commented 3 months ago

Update (6/11/24): The PU still has their issue marked for investigation for .NET 9. I'll continue to HOLD this issue until they move forward to a resolution.

guardrex commented 1 month ago

Update (8/5/24): This is still scheduled as a bug investigation on the PU repo for 9.0. Continuing to HOLD for now.