diff --git a/src/Components/test/E2ETest/Infrastructure/ServerFixtures/BlazorWasmTestAppFixture.cs b/src/Components/test/E2ETest/Infrastructure/ServerFixtures/BlazorWasmTestAppFixture.cs index 9b70be5e2a6c..48273b47af8c 100644 --- a/src/Components/test/E2ETest/Infrastructure/ServerFixtures/BlazorWasmTestAppFixture.cs +++ b/src/Components/test/E2ETest/Infrastructure/ServerFixtures/BlazorWasmTestAppFixture.cs @@ -9,6 +9,7 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; +using TestServer; using DevHostServerProgram = Microsoft.AspNetCore.Components.WebAssembly.DevServer.Server.Program; namespace Microsoft.AspNetCore.Components.E2ETest.Infrastructure.ServerFixtures; @@ -60,6 +61,11 @@ protected override IHost CreateWebHost() args.Add(Environment); } + if (WebAssemblyTestHelper.MultithreadingIsEnabled()) + { + args.Add("--apply-cop-headers"); + } + return DevHostServerProgram.BuildWebHost(args.ToArray()); } diff --git a/src/Components/test/testassets/Components.TestServer/AuthenticationStartup.cs b/src/Components/test/testassets/Components.TestServer/AuthenticationStartup.cs index f92842b82d1b..190584e60f56 100644 --- a/src/Components/test/testassets/Components.TestServer/AuthenticationStartup.cs +++ b/src/Components/test/testassets/Components.TestServer/AuthenticationStartup.cs @@ -52,6 +52,7 @@ public void Configure(IApplicationBuilder app, IWebHostEnvironment env) // Mount the server-side Blazor app on /subdir app.Map("/subdir", app => { + WebAssemblyTestHelper.ServeCoopHeadersIfWebAssemblyThreadingEnabled(app); app.UseBlazorFrameworkFiles(); app.UseStaticFiles(); diff --git a/src/Components/test/testassets/Components.TestServer/ClientStartup.cs b/src/Components/test/testassets/Components.TestServer/ClientStartup.cs index 219dbcce18a1..c99a0f5f4837 100644 --- a/src/Components/test/testassets/Components.TestServer/ClientStartup.cs +++ b/src/Components/test/testassets/Components.TestServer/ClientStartup.cs @@ -34,6 +34,7 @@ public void Configure(IApplicationBuilder app, IWebHostEnvironment env) app.Map("/subdir", app => { // Add it before to ensure it takes priority over files in wwwroot + WebAssemblyTestHelper.ServeCoopHeadersIfWebAssemblyThreadingEnabled(app); app.UseBlazorFrameworkFiles(); app.UseStaticFiles(); diff --git a/src/Components/test/testassets/Components.TestServer/CorsStartup.cs b/src/Components/test/testassets/Components.TestServer/CorsStartup.cs index 5f66e9f7e30d..d70eef3d93a1 100644 --- a/src/Components/test/testassets/Components.TestServer/CorsStartup.cs +++ b/src/Components/test/testassets/Components.TestServer/CorsStartup.cs @@ -49,6 +49,7 @@ public void Configure(IApplicationBuilder app, IWebHostEnvironment env) // Mount the server-side Blazor app on /subdir app.Map("/subdir", app => { + WebAssemblyTestHelper.ServeCoopHeadersIfWebAssemblyThreadingEnabled(app); app.UseBlazorFrameworkFiles(); app.UseStaticFiles(); diff --git a/src/Components/test/testassets/Components.TestServer/HotReloadStartup.cs b/src/Components/test/testassets/Components.TestServer/HotReloadStartup.cs index d9b275f5851a..51269338ae33 100644 --- a/src/Components/test/testassets/Components.TestServer/HotReloadStartup.cs +++ b/src/Components/test/testassets/Components.TestServer/HotReloadStartup.cs @@ -33,6 +33,7 @@ public void Configure(IApplicationBuilder app, IWebHostEnvironment env) app.UseDeveloperExceptionPage(); } + WebAssemblyTestHelper.ServeCoopHeadersIfWebAssemblyThreadingEnabled(app); app.UseBlazorFrameworkFiles(); app.UseStaticFiles(); app.UseRouting(); diff --git a/src/Components/test/testassets/Components.TestServer/InternationalizationStartup.cs b/src/Components/test/testassets/Components.TestServer/InternationalizationStartup.cs index 2ed1cfdb3ff2..9c6a68af89ee 100644 --- a/src/Components/test/testassets/Components.TestServer/InternationalizationStartup.cs +++ b/src/Components/test/testassets/Components.TestServer/InternationalizationStartup.cs @@ -34,6 +34,7 @@ public void Configure(IApplicationBuilder app, IWebHostEnvironment env) // Mount the server-side Blazor app on /subdir app.Map("/subdir", app => { + WebAssemblyTestHelper.ServeCoopHeadersIfWebAssemblyThreadingEnabled(app); app.UseBlazorFrameworkFiles(); app.UseStaticFiles(); diff --git a/src/Components/test/testassets/Components.TestServer/MultipleComponents.cs b/src/Components/test/testassets/Components.TestServer/MultipleComponents.cs index 1069b6e8df65..94dc5d35eff0 100644 --- a/src/Components/test/testassets/Components.TestServer/MultipleComponents.cs +++ b/src/Components/test/testassets/Components.TestServer/MultipleComponents.cs @@ -39,6 +39,7 @@ public void Configure(IApplicationBuilder app, IWebHostEnvironment env) app.Map("/Client/multiple-components", app => { + WebAssemblyTestHelper.ServeCoopHeadersIfWebAssemblyThreadingEnabled(app); app.UseBlazorFrameworkFiles(); app.UseStaticFiles(); app.UseRouting(); diff --git a/src/Components/test/testassets/Components.TestServer/Program.cs b/src/Components/test/testassets/Components.TestServer/Program.cs index a21c65cb8358..16d5a35b81d2 100644 --- a/src/Components/test/testassets/Components.TestServer/Program.cs +++ b/src/Components/test/testassets/Components.TestServer/Program.cs @@ -54,14 +54,21 @@ private static (IHost host, string basePath) CreateDevServerHost(string[] args) var contentRoot = typeof(Program).Assembly.GetCustomAttributes() .Single(a => a.Key == "Microsoft.AspNetCore.InternalTesting.BasicTestApp.ContentRoot") .Value; + var finalArgs = new List(); + finalArgs.AddRange(args); + finalArgs.AddRange( + [ + "--contentroot", contentRoot, + "--pathbase", "/subdir", + "--applicationpath", typeof(BasicTestApp.Program).Assembly.Location, + ]); - var finalArgs = args.Concat(new[] + if (WebAssemblyTestHelper.MultithreadingIsEnabled()) { - "--contentroot", contentRoot, - "--pathbase", "/subdir", - "--applicationpath", typeof(BasicTestApp.Program).Assembly.Location, - }).ToArray(); - var host = DevServerProgram.BuildWebHost(finalArgs); + finalArgs.Add("--apply-cop-headers"); + } + + var host = DevServerProgram.BuildWebHost(finalArgs.ToArray()); return (host, "/subdir"); } diff --git a/src/Components/test/testassets/Components.TestServer/RazorComponentEndpointsStartup.cs b/src/Components/test/testassets/Components.TestServer/RazorComponentEndpointsStartup.cs index 860bbd2b4a53..6dd3c4cb16b6 100644 --- a/src/Components/test/testassets/Components.TestServer/RazorComponentEndpointsStartup.cs +++ b/src/Components/test/testassets/Components.TestServer/RazorComponentEndpointsStartup.cs @@ -57,6 +57,8 @@ public void Configure(IApplicationBuilder app, IWebHostEnvironment env) app.Map("/subdir", app => { + WebAssemblyTestHelper.ServeCoopHeadersIfWebAssemblyThreadingEnabled(app); + if (!env.IsDevelopment()) { app.UseExceptionHandler("/Error", createScopeForErrors: true); diff --git a/src/Components/test/testassets/Components.TestServer/SaveState.cs b/src/Components/test/testassets/Components.TestServer/SaveState.cs index b5bb7819fbd2..db8c55174a9d 100644 --- a/src/Components/test/testassets/Components.TestServer/SaveState.cs +++ b/src/Components/test/testassets/Components.TestServer/SaveState.cs @@ -37,6 +37,7 @@ public void Configure(IApplicationBuilder app, IWebHostEnvironment env) app.UseDeveloperExceptionPage(); } + WebAssemblyTestHelper.ServeCoopHeadersIfWebAssemblyThreadingEnabled(app); app.UseBlazorFrameworkFiles(); app.UseStaticFiles(); app.UseRouting(); diff --git a/src/Components/test/testassets/Components.TestServer/StartupWithMapFallbackToClientSideBlazor.cs b/src/Components/test/testassets/Components.TestServer/StartupWithMapFallbackToClientSideBlazor.cs index d40f802fe8f9..3da94cd6639b 100644 --- a/src/Components/test/testassets/Components.TestServer/StartupWithMapFallbackToClientSideBlazor.cs +++ b/src/Components/test/testassets/Components.TestServer/StartupWithMapFallbackToClientSideBlazor.cs @@ -33,6 +33,7 @@ public void Configure(IApplicationBuilder app, IWebHostEnvironment env) // The client-side files middleware needs to be here because the base href in hardcoded to /subdir/ app.Map("/subdir", subApp => { + WebAssemblyTestHelper.ServeCoopHeadersIfWebAssemblyThreadingEnabled(app); subApp.UseBlazorFrameworkFiles(); subApp.UseStaticFiles(); diff --git a/src/Components/test/testassets/Components.TestServer/WebAssemblyTestHelper.cs b/src/Components/test/testassets/Components.TestServer/WebAssemblyTestHelper.cs new file mode 100644 index 000000000000..7bbb51418cd7 --- /dev/null +++ b/src/Components/test/testassets/Components.TestServer/WebAssemblyTestHelper.cs @@ -0,0 +1,31 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Reflection; + +namespace TestServer; + +public static class WebAssemblyTestHelper +{ + public static bool MultithreadingIsEnabled() + { + var entrypointAssembly = Assembly.GetExecutingAssembly(); + var attribute = entrypointAssembly.GetCustomAttributes() + .FirstOrDefault(x => x.Key.Equals("Microsoft.AspNetCore.InternalTesting.RunWebAssemblyE2ETestsWithMultithreading", StringComparison.Ordinal)); + return attribute is not null && bool.Parse(attribute.Value); + } + + public static void ServeCoopHeadersIfWebAssemblyThreadingEnabled(IApplicationBuilder app) + { + if (MultithreadingIsEnabled()) + { + app.Use(async (ctx, next) => + { + // Browser multi-threaded runtime requires cross-origin policy headers to enable SharedArrayBuffer. + ctx.Response.Headers.Append("Cross-Origin-Embedder-Policy", "require-corp"); + ctx.Response.Headers.Append("Cross-Origin-Opener-Policy", "same-origin"); + await next(ctx); + }); + } + } +} diff --git a/src/Components/test/testassets/Directory.Build.props b/src/Components/test/testassets/Directory.Build.props index e431fcb4f79d..ad5e636d6eb6 100644 --- a/src/Components/test/testassets/Directory.Build.props +++ b/src/Components/test/testassets/Directory.Build.props @@ -3,5 +3,20 @@ true + + + + + + + <_Parameter1>Microsoft.AspNetCore.InternalTesting.RunWebAssemblyE2ETestsWithMultithreading + <_Parameter2>true + +