Skip to content

Commit 8e435d1

Browse files
Add option to serve WebAssembly app with multithreading (#54062)
1 parent f03012c commit 8e435d1

24 files changed

+562
-11
lines changed

AspNetCore.sln

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1322,6 +1322,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "StandaloneApp", "src\Compon
13221322
EndProject
13231323
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThreadingApp", "src\Components\WebAssembly\testassets\ThreadingApp\ThreadingApp.csproj", "{A40350FE-4334-4007-B1C3-6BEB1B070308}"
13241324
EndProject
1325+
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThreadingApp.Server", "src\Components\WebAssembly\testassets\ThreadingApp.Server\ThreadingApp.Server.csproj", "{F1792637-28B9-4F2A-B318-FA923C365049}"
1326+
EndProject
13251327
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "HealthChecks", "HealthChecks", "{C1E7F837-6988-43E2-9E1C-7302DB484F99}"
13261328
EndProject
13271329
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{2A91479A-4ABE-4BB7-9A5E-CA3B9CCFC69E}"
@@ -1778,7 +1780,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Output
17781780
EndProject
17791781
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.OutputCaching.StackExchangeRedis", "src\Middleware\Microsoft.AspNetCore.OutputCaching.StackExchangeRedis\src\Microsoft.AspNetCore.OutputCaching.StackExchangeRedis.csproj", "{F232B503-D412-45EE-8B31-EFD46B9FA302}"
17801782
EndProject
1781-
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.AspNetCore.InternalTesting", "src\Testing\src\Microsoft.AspNetCore.InternalTesting.csproj", "{B0A8E5D4-BC5A-448E-B222-431B6B2EB58E}"
1783+
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.InternalTesting", "src\Testing\src\Microsoft.AspNetCore.InternalTesting.csproj", "{B0A8E5D4-BC5A-448E-B222-431B6B2EB58E}"
17821784
EndProject
17831785
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.AspNetCore.InternalTesting.Tests", "src\Testing\test\Microsoft.AspNetCore.InternalTesting.Tests.csproj", "{15D08EA7-8C63-45FB-8B4D-C5F8E43B433E}"
17841786
EndProject
@@ -8250,6 +8252,22 @@ Global
82508252
{A40350FE-4334-4007-B1C3-6BEB1B070308}.Release|x64.Build.0 = Release|Any CPU
82518253
{A40350FE-4334-4007-B1C3-6BEB1B070308}.Release|x86.ActiveCfg = Release|Any CPU
82528254
{A40350FE-4334-4007-B1C3-6BEB1B070308}.Release|x86.Build.0 = Release|Any CPU
8255+
{F1792637-28B9-4F2A-B318-FA923C365049}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
8256+
{F1792637-28B9-4F2A-B318-FA923C365049}.Debug|Any CPU.Build.0 = Debug|Any CPU
8257+
{F1792637-28B9-4F2A-B318-FA923C365049}.Debug|arm64.ActiveCfg = Debug|Any CPU
8258+
{F1792637-28B9-4F2A-B318-FA923C365049}.Debug|arm64.Build.0 = Debug|Any CPU
8259+
{F1792637-28B9-4F2A-B318-FA923C365049}.Debug|x64.ActiveCfg = Debug|Any CPU
8260+
{F1792637-28B9-4F2A-B318-FA923C365049}.Debug|x64.Build.0 = Debug|Any CPU
8261+
{F1792637-28B9-4F2A-B318-FA923C365049}.Debug|x86.ActiveCfg = Debug|Any CPU
8262+
{F1792637-28B9-4F2A-B318-FA923C365049}.Debug|x86.Build.0 = Debug|Any CPU
8263+
{F1792637-28B9-4F2A-B318-FA923C365049}.Release|Any CPU.ActiveCfg = Release|Any CPU
8264+
{F1792637-28B9-4F2A-B318-FA923C365049}.Release|Any CPU.Build.0 = Release|Any CPU
8265+
{F1792637-28B9-4F2A-B318-FA923C365049}.Release|arm64.ActiveCfg = Release|Any CPU
8266+
{F1792637-28B9-4F2A-B318-FA923C365049}.Release|arm64.Build.0 = Release|Any CPU
8267+
{F1792637-28B9-4F2A-B318-FA923C365049}.Release|x64.ActiveCfg = Release|Any CPU
8268+
{F1792637-28B9-4F2A-B318-FA923C365049}.Release|x64.Build.0 = Release|Any CPU
8269+
{F1792637-28B9-4F2A-B318-FA923C365049}.Release|x86.ActiveCfg = Release|Any CPU
8270+
{F1792637-28B9-4F2A-B318-FA923C365049}.Release|x86.Build.0 = Release|Any CPU
82538271
{B06040BC-DA28-4923-8CAC-20EB517D471B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
82548272
{B06040BC-DA28-4923-8CAC-20EB517D471B}.Debug|Any CPU.Build.0 = Debug|Any CPU
82558273
{B06040BC-DA28-4923-8CAC-20EB517D471B}.Debug|arm64.ActiveCfg = Debug|Any CPU
@@ -11405,7 +11423,8 @@ Global
1140511423
{9788C76F-658B-4441-88F8-22C6B86FAD27} = {7D2B0799-A634-42AC-AE77-5D167BA51389}
1140611424
{1970D5CD-D9A4-4673-A297-179BB04199F4} = {7D2B0799-A634-42AC-AE77-5D167BA51389}
1140711425
{A40350FE-4334-4007-B1C3-6BEB1B070309} = {7D2B0799-A634-42AC-AE77-5D167BA51389}
11408-
{A40350FE-4334-4007-B1C3-6BEB1B070308} = {6126DCE4-9692-4EE2-B240-C65743572995}
11426+
{A40350FE-4334-4007-B1C3-6BEB1B070308} = {7D2B0799-A634-42AC-AE77-5D167BA51389}
11427+
{F1792637-28B9-4F2A-B318-FA923C365049} = {7D2B0799-A634-42AC-AE77-5D167BA51389}
1140911428
{C1E7F837-6988-43E2-9E1C-7302DB484F99} = {017429CC-C5FB-48B4-9C46-034E29EE2F06}
1141011429
{2A91479A-4ABE-4BB7-9A5E-CA3B9CCFC69E} = {C1E7F837-6988-43E2-9E1C-7302DB484F99}
1141111430
{7CB09412-C9B0-47E8-A8C3-311AA4CFDE04} = {C1E7F837-6988-43E2-9E1C-7302DB484F99}

src/Components/Components.slnf

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
"src\\Components\\WebAssembly\\testassets\\HostedInAspNet.Server\\HostedInAspNet.Server.csproj",
3737
"src\\Components\\WebAssembly\\testassets\\StandaloneApp\\StandaloneApp.csproj",
3838
"src\\Components\\WebAssembly\\testassets\\ThreadingApp\\ThreadingApp.csproj",
39+
"src\\Components\\WebAssembly\\testassets\\ThreadingApp.Server\\ThreadingApp.Server.csproj",
3940
"src\\Components\\WebAssembly\\testassets\\Wasm.Prerendered.Client\\Wasm.Prerendered.Client.csproj",
4041
"src\\Components\\WebAssembly\\testassets\\Wasm.Prerendered.Server\\Wasm.Prerendered.Server.csproj",
4142
"src\\Components\\WebAssembly\\testassets\\WasmLinkerTest\\WasmLinkerTest.csproj",

src/Components/Samples/BlazorUnitedApp/BlazorUnitedApp.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,8 @@
1111
<Reference Include="Microsoft.AspNetCore.Components.Endpoints" />
1212
<Reference Include="Microsoft.AspNetCore.Components.Server" />
1313
<Reference Include="Microsoft.AspNetCore.HttpsPolicy" />
14-
<Reference Include="Microsoft.Extensions.Hosting" />
1514
<Reference Include="Microsoft.AspNetCore.StaticFiles" />
15+
<Reference Include="Microsoft.AspNetCore.Mvc" />
1616
</ItemGroup>
1717

1818
</Project>

src/Components/WebAssembly/Server/src/Builder/WebAssemblyComponentsEndpointOptions.cs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,4 +15,15 @@ public sealed class WebAssemblyComponentsEndpointOptions
1515
/// This path must correspond to a referenced Blazor WebAssembly application project.
1616
/// </summary>
1717
public PathString PathPrefix { get; set; }
18+
19+
/// <summary>
20+
/// Gets or sets a flag to determine whether to enable WebAssembly multithreading. If true,
21+
/// the server will add headers similar to <code>Cross-Origin-Embedder-Policy: require-corp</code> and
22+
/// <code>Cross-Origin-Opener-Policy: same-origin</code> on the response for the host page, because
23+
/// this is required to enable the SharedArrayBuffer feature in the browser.
24+
///
25+
/// Note that enabling this feature can restrict your ability to use other JavaScript APIs. For more
26+
/// information, see <see href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/SharedArrayBuffer#security_requirements" />.
27+
/// </summary>
28+
public bool ServeMultithreadingHeaders { get; set; }
1829
}

src/Components/WebAssembly/Server/src/Builder/WebAssemblyRazorComponentsEndpointConventionBuilderExtensions.cs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
// Licensed to the .NET Foundation under one or more agreements.
22
// The .NET Foundation licenses this file to you under the MIT license.
33

4+
using Microsoft.AspNetCore.Components.Endpoints;
45
using Microsoft.AspNetCore.Components.Endpoints.Infrastructure;
56
using Microsoft.AspNetCore.Components.Web;
67
using Microsoft.AspNetCore.Components.WebAssembly.Server;
8+
using System.Linq;
79

810
namespace Microsoft.AspNetCore.Builder;
911

@@ -24,6 +26,24 @@ public static RazorComponentsEndpointConventionBuilder AddInteractiveWebAssembly
2426

2527
callback?.Invoke(options);
2628

29+
if (options.ServeMultithreadingHeaders)
30+
{
31+
builder.Add(endpointBuilder =>
32+
{
33+
var needsCoopHeaders = endpointBuilder.Metadata.OfType<ComponentTypeMetadata>().Any() // e.g., /somecomponent
34+
|| endpointBuilder.Metadata.OfType<WebAssemblyRenderModeWithOptions>().Any(); // e.g., /_framework/*
35+
if (needsCoopHeaders && endpointBuilder.RequestDelegate is { } originalDelegate)
36+
{
37+
endpointBuilder.RequestDelegate = httpContext =>
38+
{
39+
httpContext.Response.Headers["Cross-Origin-Embedder-Policy"] = "require-corp";
40+
httpContext.Response.Headers["Cross-Origin-Opener-Policy"] = "same-origin";
41+
return originalDelegate(httpContext);
42+
};
43+
}
44+
});
45+
}
46+
2747
ComponentEndpointConventionBuilderHelper.AddRenderMode(builder, new WebAssemblyRenderModeWithOptions(options));
2848
return builder;
2949
}
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,3 @@
11
#nullable enable
2+
Microsoft.AspNetCore.Components.WebAssembly.Server.WebAssemblyComponentsEndpointOptions.ServeMultithreadingHeaders.get -> bool
3+
Microsoft.AspNetCore.Components.WebAssembly.Server.WebAssemblyComponentsEndpointOptions.ServeMultithreadingHeaders.set -> void

src/Components/WebAssembly/testassets/HostedInAspNet.Server/HostedInAspNet.Server.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
<Reference Include="Microsoft.AspNetCore" />
1414
<Reference Include="Microsoft.AspNetCore.Components.WebAssembly.Server" />
1515
<Reference Include="Microsoft.AspNetCore.Diagnostics" />
16-
<Reference Include="Microsoft.Extensions.Hosting" />
16+
<Reference Include="Microsoft.AspNetCore.Mvc" />
1717
<!-- Avoid MSB3277 warnings due to dependencies brought in through Microsoft.AspNetCore.Blazor targeting netstandard2.0. -->
1818
<Reference Include="System.Text.Json" />
1919
</ItemGroup>
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
4+
<head>
5+
<meta charset="utf-8" />
6+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
7+
<base href="/" />
8+
<link href="bootstrap.min.css" rel="stylesheet" />
9+
<link href="app.css" rel="stylesheet" />
10+
<HeadOutlet @rendermode="RenderMode.InteractiveWebAssembly" />
11+
</head>
12+
13+
<body>
14+
<app>Loading...</app>
15+
16+
<div id="blazor-error-ui">
17+
An unhandled exception has occurred. See browser dev tools for details.
18+
<a href="" class="reload">Reload</a>
19+
<a class="dismiss">🗙</a>
20+
</div>
21+
22+
<script src="_framework/blazor.web.js"></script>
23+
</body>
24+
25+
</html>
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
@using System.Net.Http
2+
@using System.Net.Http.Json
3+
@using Microsoft.AspNetCore.Components.Forms
4+
@using Microsoft.AspNetCore.Components.Routing
5+
@using Microsoft.AspNetCore.Components.Web
6+
@using static Microsoft.AspNetCore.Components.Web.RenderMode
7+
@using Microsoft.AspNetCore.Components.Web.Virtualization
8+
@using Microsoft.JSInterop
9+
@using ThreadingApp.Server
10+
@using ThreadingApp.Server.Components
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
4+
namespace ThreadingApp.Server;
5+
6+
public class Program
7+
{
8+
private static void Main(string[] args)
9+
=> BuildWebHost(args).Run();
10+
11+
public static IHost BuildWebHost(string[] args)
12+
{
13+
var builder = WebApplication.CreateBuilder(args);
14+
15+
// We require this line because we run in Production environment
16+
// and static web assets are only on by default during development.
17+
builder.Environment.ApplicationName = typeof(Program).Assembly.GetName().Name!;
18+
builder.WebHost.UseStaticWebAssets();
19+
20+
// Add services to the container.
21+
builder.Services.AddRazorComponents()
22+
.AddInteractiveWebAssemblyComponents();
23+
24+
var app = builder.Build();
25+
26+
// Configure the HTTP request pipeline.
27+
if (!app.Environment.IsDevelopment())
28+
{
29+
app.UseExceptionHandler("/Error", createScopeForErrors: true);
30+
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
31+
app.UseHsts();
32+
}
33+
34+
app.UseHttpsRedirection();
35+
36+
app.UseStaticFiles();
37+
app.UseAntiforgery();
38+
39+
app.MapRazorComponents<Server.Components.App>()
40+
.AddInteractiveWebAssemblyRenderMode(options => { options.ServeMultithreadingHeaders = true; })
41+
.AddAdditionalAssemblies(typeof(ThreadingApp.Pages.Index).Assembly);
42+
43+
return app;
44+
}
45+
}

0 commit comments

Comments
 (0)