diff --git a/src/Components/WebAssembly/Server/src/WebAssemblyRazorComponentsBuilderExtensions.cs b/src/Components/WebAssembly/Server/src/WebAssemblyRazorComponentsBuilderExtensions.cs index 0dfb50ef840a..a55065ca9b45 100644 --- a/src/Components/WebAssembly/Server/src/WebAssemblyRazorComponentsBuilderExtensions.cs +++ b/src/Components/WebAssembly/Server/src/WebAssemblyRazorComponentsBuilderExtensions.cs @@ -1,6 +1,8 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Diagnostics.CodeAnalysis; +using System.Reflection; using Microsoft.AspNetCore.Components; using Microsoft.AspNetCore.Components.Authorization; using Microsoft.AspNetCore.Components.Endpoints.Infrastructure; @@ -14,6 +16,9 @@ namespace Microsoft.Extensions.DependencyInjection; /// public static class WebAssemblyRazorComponentsBuilderExtensions { + private const string LazyAssemblyLoaderAssemblyName = "Microsoft.AspNetCore.Components.WebAssembly"; + private const string LazyAssemblyLoaderTypeName = "Microsoft.AspNetCore.Components.WebAssembly.Services.LazyAssemblyLoader"; + /// /// Adds services to support rendering interactive WebAssembly components. /// @@ -25,6 +30,15 @@ public static IRazorComponentsBuilder AddInteractiveWebAssemblyComponents(this I builder.Services.TryAddEnumerable(ServiceDescriptor.Singleton()); + // Try register LazyAssemblyLoader to prevent crashes during prerendering. + // TODO: Remove this once LazyAssemblyLoader is no longer used. + var lazyAssemblyLoaderType = GetLazyAssemblyLoaderType(); + + if (lazyAssemblyLoaderType != null) + { + builder.Services.TryAddScoped(lazyAssemblyLoaderType); + } + return builder; } @@ -46,4 +60,18 @@ public static IRazorComponentsBuilder AddAuthenticationStateSerialization(this I return builder; } + + [DynamicDependency(DynamicallyAccessedMemberTypes.PublicConstructors, LazyAssemblyLoaderTypeName, LazyAssemblyLoaderAssemblyName)] + private static Type? GetLazyAssemblyLoaderType() + { + try + { + var assembly = Assembly.Load(LazyAssemblyLoaderAssemblyName); + return assembly.GetType(LazyAssemblyLoaderTypeName, throwOnError: false); + } + catch + { + return null; + } + } } diff --git a/src/ProjectTemplates/test/Templates.Blazor.Tests/BlazorWebTemplateTest.cs b/src/ProjectTemplates/test/Templates.Blazor.Tests/BlazorWebTemplateTest.cs index dc2cf5b63982..7a63733db354 100644 --- a/src/ProjectTemplates/test/Templates.Blazor.Tests/BlazorWebTemplateTest.cs +++ b/src/ProjectTemplates/test/Templates.Blazor.Tests/BlazorWebTemplateTest.cs @@ -1,6 +1,7 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.IO; using System.Net; using System.Net.Http; using System.Net.Http.Headers; @@ -26,6 +27,18 @@ public async Task BlazorWebTemplate_Works(BrowserKind browserKind, string intera args: ["-int", interactivityOption], getTargetProject: GetTargetProject); + if (HasClientProject()) + { + // In order to prevent an exception casued by missing LazyAssemblyLoader during pre-rendering, + // we are registering it into DI in AddInteractiveWebAssemblyComponents. + // To avoid adding new references between assemblies we try to resolve the type during run-time using reflection. + // This assert is here to check that the assembly containing LazyAssemblyLoader is actually present in a standard app + // created from the Blazor Web template. + // See https://github.com/dotnet/aspnetcore/issues/51966. + // TODO: Remove this when LazyAssemblyLoader is no longer being used, or the dependency graph changes so reflection is no longer needed. + AssertServerProjectCanUseLazyAssemblyLoader(GetTargetProject(project)); + } + // There won't be a counter page when the 'None' interactivity option is used var pagesToExclude = interactivityOption is "None" ? BlazorTemplatePages.Counter @@ -92,4 +105,12 @@ private static async Task AssertWebAssemblyCompressionFormatAsync(AspNetProcess }); Assert.Equal(expectedEncoding, response.Content.Headers.ContentEncoding.Single()); } + + private static void AssertServerProjectCanUseLazyAssemblyLoader(Project project) + { + var assemblyName = "Microsoft.AspNetCore.Components.WebAssembly.dll"; + var fullPath = Path.Combine(project.TemplateBuildDir, assemblyName); + var doesExist = File.Exists(fullPath); + Assert.True(doesExist, "Required assembly does not exist"); + } }