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.23k stars 9.95k forks source link

Blazor WebAssemblyHostBuilder initialization fails if root component's assembly is not loaded on client startup #26601

Closed tehaucave closed 9 months ago

tehaucave commented 3 years ago

Describe the bug

Blazor WebAssembly (5.0-rc1) client project startup fails when prerendering is used and the root component is defined in a razor class library, unless the client project's Main method explicitly references the razor class library assembly.

This appears to be the case because WebAssemblyHostBuilder.CreateDefault(...) only searches loaded assemblies for the root component type specified in the <component> tag in the server-side host page. It is not sufficient for the client project to reference the razor class library project. The client's Main method must explicitly cause the razor class library assembly to load before WebAssemblyHostBuilder.CreateDefault(...) is called.

I understand that most Blazor WebAssembly apps will define their root component in the client-side entry assembly, but it is sometimes convenient to define all of a Blazor app's UI components, including the root component, in a class library project that can be used in both Blazor Server and Blazor WebAssembly apps. While the client initialization error can be worked around, the workaround is not obvious and the error message (see below) is unhelpful.

To Reproduce

See repro project at https://github.com/tehaucave/RootComponentFromClassLibrary

This is a standard ASP.NET Core-hosted Blazor WebAssembly (5.0-rc1) solution with all components removed from the client project, and a razor class library project added containing a single razor component named AppRoot. Also, index.html has been removed from the client project and a _Host.cshtml page has been added to the server project and configured as the server's fallback page. A <component> tag is included in _Host.cshtml with type=AppRoot and render-mode=WebAssemblyPrerendered. In the client's Program.Main method, the explicit root component registration has been removed.

The client app throws a runtime exception on startup unless I add code like the following before the call to WebAssemblyHostBuilder.CreateDefault(args):

typeof(AppRoot).ToString()

Exceptions (if any)

From browser console (chrome):

blazor.webassembly.js:1 System.ArgumentNullException: Value cannot be null. (Parameter 'componentType') at Microsoft.AspNetCore.Components.WebAssembly.Hosting.RootComponentMappingCollection.Add(Type componentType, String selector, ParameterView parameters) at Microsoft.AspNetCore.Components.WebAssembly.Hosting.WebAssemblyHostBuilder.InitializeRegisteredRootComponents(WebAssemblyJSRuntimeInvoker jsRuntimeInvoker) at Microsoft.AspNetCore.Components.WebAssembly.Hosting.WebAssemblyHostBuilder..ctor(WebAssemblyJSRuntimeInvoker jsRuntimeInvoker) at Microsoft.AspNetCore.Components.WebAssembly.Hosting.WebAssemblyHostBuilder.CreateDefault(String[] args) at RootComponentFromClassLibrary.Client.Program.Main(String[] args) in C:\Users\a060514\source\repos\github\RootComponentFromClassLibrary\Client\Program.cs:line 25 at Microsoft.AspNetCore.Components.WebAssembly.Hosting.EntrypointInvoker.InvokeEntrypoint(String assemblyName, String[] args)

Further technical details

.NET SDK (reflecting any global.json): Version: 5.0.100-rc.1.20452.10 Commit: 473d1b592e

Runtime Environment: OS Name: Windows OS Version: 10.0.18362 OS Platform: Windows RID: win10-x64 Base Path: C:\Program Files\dotnet\sdk\5.0.100-rc.1.20452.10\

Host (useful for support): Version: 5.0.0-rc.1.20451.14 Commit: 38017c3935

.NET SDKs installed: 3.1.100 [C:\Program Files\dotnet\sdk] 3.1.300-preview-015048 [C:\Program Files\dotnet\sdk] 3.1.300 [C:\Program Files\dotnet\sdk] 3.1.400-preview-015178 [C:\Program Files\dotnet\sdk] 3.1.401 [C:\Program Files\dotnet\sdk] 5.0.100-preview.8.20417.9 [C:\Program Files\dotnet\sdk] 5.0.100-rc.1.20452.10 [C:\Program Files\dotnet\sdk]

.NET runtimes installed: Microsoft.AspNetCore.All 2.1.21 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.All] Microsoft.AspNetCore.App 2.1.21 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App] Microsoft.AspNetCore.App 3.1.4 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App] Microsoft.AspNetCore.App 3.1.7 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App] Microsoft.AspNetCore.App 5.0.0-preview.8.20414.8 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App] Microsoft.AspNetCore.App 5.0.0-rc.1.20451.17 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App] Microsoft.NETCore.App 2.1.21 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App] Microsoft.NETCore.App 3.1.4 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App] Microsoft.NETCore.App 3.1.7 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App] Microsoft.NETCore.App 5.0.0-preview.8.20407.11 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App] Microsoft.NETCore.App 5.0.0-rc.1.20451.14 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App] Microsoft.WindowsDesktop.App 3.1.4 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App] Microsoft.WindowsDesktop.App 3.1.7 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App] Microsoft.WindowsDesktop.App 5.0.0-preview.8.20411.6 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App] Microsoft.WindowsDesktop.App 5.0.0-rc.1.20452.2 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]

To install additional .NET runtimes or SDKs: https://aka.ms/dotnet-download

ghost commented 3 years ago

Thanks for contacting us. We're moving this issue to the Next sprint planning milestone for future evaluation / consideration. We will evaluate the request when we are planning the work for the next milestone. To learn more about what to expect next and how this issue will be handled you can read more about our triage process here.

ghost commented 3 years ago

We've moved this issue to the Backlog milestone. This means that it is not going to be worked on for the coming release. We will reassess the backlog following the current release and consider this item at that time. To learn more about our issue management process and to have better expectation regarding different types of issues you can read our Triage Process.

ghost commented 2 years ago

We've moved this issue to the Backlog milestone. This means that it is not going to be worked on for the coming release. We will reassess the backlog following the current release and consider this item at that time. To learn more about our issue management process and to have better expectation regarding different types of issues you can read our Triage Process.

Magic73 commented 2 years ago

Just encountered the same issue :(

Daddoon commented 2 years ago

Same issue because of tree shaking, while trying to use a WebAssemblyPrerendered content from a RCL project. The workaround for this problem: Just write a reference to your component type in your WASM Main method before calling RunAsyc.

Like:

using BlazorDynamicEngine.Client;
using Microsoft.AspNetCore.Components.Web;
using Microsoft.AspNetCore.Components.WebAssembly.Hosting;

namespace Company.WebApplication1
{
    public class Program
    {
        public static async Task Main(string[] args)
        {
            var builder = WebAssemblyHostBuilder.CreateDefault(args);

            //JUST DO A STATIC REFERENCE HERE !
            var type = typeof(BlazorDynamicEngine.App.App);

            builder.Services.AddScoped(sp => new HttpClient { BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) });

            await builder.Build().RunAsync();
        }
    }
}
mstancombe commented 2 years ago

Also just hit this, using base app class from an RCL. Workaround was to flex a type in the RCL assembly as previous posters highlighted. Unlike @Daddoon , we found we had to do it explicitly BEFORE the line

var builder = WebAssemblyHostBuilder.CreateDefault() 

i.e.

AssemblyRegister.GetAssemblies(); // <- our own helper which knows about assemblies at compile time
var builder = WebAssemblyHostBuilder.CreateDefault() 
...
Daddoon commented 2 years ago

Also just hit this, using base app class from an RCL. Workaround was to flex a type in the RCL assembly as previous posters highlighted. Unlike @Daddoon , we found we had to do it explicitly BEFORE the line

var builder = WebAssemblyHostBuilder.CreateDefault() 

i.e.

AssemblyRegister.GetAssemblies(); // <- our own helper which knows about assemblies at compile time
var builder = WebAssemblyHostBuilder.CreateDefault() 
...

Indeed, i found later on another project that sometime, the linker seem to optimize agressively, and so my workaround was not always working.

On my side, using a ReferenceConverter object before creating the WebAssemblyHostBuilder did the trick. Possibly, it just do the same as you @mstancombe , but just posting an example of code if useful to someone else:

using BlazorDynamicEngine.Client;
using BlazorDynamicEngine.Client.Extensions;
using Microsoft.AspNetCore.Components.Web;
using Microsoft.AspNetCore.Components.WebAssembly.Hosting;
using System.ComponentModel;

namespace Company.WebApplication1
{
    public class Program
    {
        private ReferenceConverter ReferenceConverter = new ReferenceConverter(typeof(BlazorDynamicEngine.App.App));

        public static async Task Main(string[] args)
        {
            ReferenceConverter test = new ReferenceConverter(typeof(BlazorDynamicEngine.App.App));

            var builder = WebAssemblyHostBuilder.CreateDefault(args);

            /* Custom code here... */

            await builder.Build().RunAsync();
        }
    }
}
ghost commented 1 year ago

Thanks for contacting us. We're moving this issue to the .NET 8 Planning milestone for future evaluation / consideration. Because it's not immediately obvious that this is a bug in our framework, we would like to keep this around to collect more feedback, which can later help us determine the impact of it. 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.

ghost commented 11 months ago

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.

coolwolf commented 8 months ago

Same on .NET Core 8 WebAssembly project. It was crashing on following line in the Program.cs file: var builder = WebAssemblyHostBuilder.CreateDefault(args);

Just put some valid json into wwwroot/appsettings.json For example: { } or { "MySettingValue":1 }

zbarrier commented 8 months ago

Using .NET Aspire causes this issue but everything works fine now without Aspire. It should be consistent.

itsKXCode commented 8 months ago

Still the same issue with SDK 8.0.100