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

Option to serve WebAssembly app with multithreading #54071

Closed SteveSandersonMS closed 6 months ago

SteveSandersonMS commented 7 months ago

Background and Motivation

Work continues in the runtime repo on WebAssembly multithreading. It's now pretty easy to enable and use - people just need to:

A. Add <WasmEnableThreads>true</WasmEnableThreads> in the wasm project csproj

B. Ensure the site is served with the relevant Cross-Origin-... headers as per browser requirements

Proposed API

namespace Microsoft.AspNetCore.Components.WebAssembly.Server;

public sealed class WebAssemblyComponentsEndpointOptions
{
+    /// <summary>
+    /// Gets or sets a flag to determine whether to enable WebAssembly multithreading. If true,
+    /// the server will add headers similar to <code>Cross-Origin-Embedder-Policy: require-corp</code> and
+    /// <code>Cross-Origin-Opener-Policy: same-origin</code> on the response for the host page, because
+    /// this is required to enable the SharedArrayBuffer feature in the browser.
+    ///
+    /// Note that enabling this feature can restrict your ability to use other JavaScript APIs. For more
+    /// information, see <see href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/SharedArrayBuffer#security_requirements" />.
+    /// </summary>
+    public bool ServeMultithreadingHeaders { get; set; }
}

Usage Examples

app.MapRazorComponents<App>()
    .AddInteractiveWebAssemblyRenderMode(options => { options.ServeMultithreadingHeaders = true; })
    .AddAdditionalAssemblies(typeof(MyWebAssemblyApp.Pages.Index).Assembly);

Alternative Designs

Overall, since this feature is nascent and remains experimental, I'm erring on the side of making it more explicit and literal so people who turn it on know what they are getting into. In the future if we get to the point that wasm multithreading is so good that most people should enable it, we retain the option to streamline the usage.

Alternative: Infer it automatically

We could try to infer this based on <WasmEnableThreads> in the wasm csproj, but:

  1. There could be multiple wasm apps. What if they want different configurations?
  2. Since this is an early and quite experimental feature, it's really good to force developers to opt in to serving the COOP headers explicitly. Doing so can restrict the availability of other JS APIs (e.g., can interfere with popups that might be used for auth flows) as described at https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/SharedArrayBuffer#security_requirements. It might turn out to be fine, but in case this causes issues for people, it's really good that the developer has a chance to discover what they are enabling and the possible side-effects of that.

Alternative: Extension method

An alternative API would be making it an extension method on RazorComponentsEndpointConventionBuilder, e.g.:

app.MapRazorComponents<App>().AddInteractiveWebAssemblyRenderMode().ServeWasmMultithreadingHeaders();

... but that would be very strange and ambiguous since you could also write:

app.MapRazorComponents<App>().AddInteractiveServerRenderMode().ServeWasmMultithreadingHeaders();

I prefer it being an option on AddInteractiveWebAssemblyRenderMode since it is more specific and accurate, as it only applies within that case.

Alternative: Naming

It would be more obvious to call it EnableMultithreading instead of ServeMultithreadingHeaders, but that would not so well serve the purpose of helping developer understand what exactly they are enabling and how it might have other side effects.

Risks

Nothing obvious.

SteveSandersonMS commented 7 months ago

Implemented in https://github.com/dotnet/aspnetcore/pull/54062

dotnet-policy-service[bot] commented 7 months ago

Thank you for submitting this for API review. This will be reviewed by @dotnet/aspnet-api-review at the next meeting of the ASP.NET Core API Review group. Please ensure you take a look at the API review process documentation and ensure that:

halter73 commented 6 months ago

API Review Notes:

We would really like it if we didn't need to add ServeMultithreadingHeaders at all and instead it was inferred based off of <WasmEnableThreads>, but it sounds like the implementation of that is non-trivial, and adding a bool is fairly simple.

namespace Microsoft.AspNetCore.Components.WebAssembly.Server;

public sealed class WebAssemblyComponentsEndpointOptions
{
+    /// <summary>
+    /// Gets or sets a flag to determine whether to enable WebAssembly multithreading. If true,
+    /// the server will add headers similar to <code>Cross-Origin-Embedder-Policy: require-corp</code> and
+    /// <code>Cross-Origin-Opener-Policy: same-origin</code> on the response for the host page, because
+    /// this is required to enable the SharedArrayBuffer feature in the browser.
+    ///
+    /// Note that enabling this feature can restrict your ability to use other JavaScript APIs. For more
+    /// information, see <see href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/SharedArrayBuffer#security_requirements" />.
+    /// </summary>
+    public bool ServeMultithreadingHeaders { get; set; }
}
danroth27 commented 6 months ago

These headers aren't really specific to multithreading - they are used to enable cross-origin isolation in the browser. It's similar to other general web security features like CORS and CSP. Should we consider making enabling cross-origin isolation in an ASP.NET Core app a more general-purpose feature instead of tying it specifically to multithreading?

SteveSandersonMS commented 6 months ago

Should we consider making enabling cross-origin isolation in an ASP.NET Core app a more general-purpose feature instead of tying it specifically to multithreading?

We discussed this in API review and decided it's not clear that ASP.NET Core should have that responsibility. If a developer specifically knows they want to send some particular combination of headers, ASP.NET Core already lets them do that. Enabing SharedArrayBuffer unrelated to Blazor WebAssembly is niche enough that developers who want to do it should already be able to send the headers they need.

The only reason we're special-casing it for WebAssembly multithreading is to make the on-ramp easier for that specific Blazor WebAssembly feature.

SteveSandersonMS commented 6 months ago

Since this API was now approved, this feature is done (implemented in https://github.com/dotnet/aspnetcore/pull/54062).