Description
When <WasmEnableThreads>true</WasmEnableThreads> is set, the .NET runtime moves entirely to a background Web Worker (the "Deputy Thread" model). This makes DotNet.invokeMethod — synchronous JS-to-.NET calls — impossible, because the browser's UI thread cannot block while waiting for a response from a worker.
I'm requesting a supported configuration option that enables .NET threading (thread pool, Task.Run, System.Threading) while keeping the main .NET entry point on the browser's UI thread.
Background
I maintain the SpawnDev.BlazorJS ecosystem — 41 NuGet packages, 323,000+ total downloads — which provides typed C# wrappers for JavaScript APIs in Blazor WebAssembly. This library depends on synchronous JS-to-.NET interop (DotNet.invokeMethod) because the JavaScript specification requires synchronous handling in many scenarios:
event.preventDefault() must be called synchronously within the handler
event.stopImmediatePropagation() — same constraint
beforeunload requires a synchronous return value
- Synchronous property getters on JS objects
- Callback-driven APIs that expect synchronous returns
These are not edge cases. These are fundamental browser APIs that cannot be handled asynchronously.
Proposed Behavior
A configuration like:
<PropertyGroup>
<WasmEnableThreads>true</WasmEnableThreads>
<WasmMainThreadOnUI>true</WasmMainThreadOnUI>
</PropertyGroup>
When enabled:
Program.Main executes on the browser's UI thread (as it does today without threading)
- Synchronous JS interop (
DotNet.invokeMethod, [JSExport] with sync signatures) works normally
Task.Run, ThreadPool, and new Thread() dispatch to background Web Workers
- Blocking primitives (
lock, Monitor.Enter, Thread.Sleep) work on background threads but throw on the UI thread (this is already the browser's constraint)
This is architecturally the same model that SpawnDev.BlazorJS.WebWorkers (90,000+ downloads) has used successfully for years: main .NET on the UI thread, heavy work dispatched to workers explicitly.
Why This Matters
Without this option, any .NET library that provides synchronous JavaScript interop is broken when threading is enabled. This affects:
- SpawnDev.BlazorJS and its 41-package ecosystem (WebRTC, WebGPU, WebTorrent, Canvas, Crypto, etc.)
- Any third-party library wrapping synchronous JS APIs
- Any application handling DOM events that require synchronous responses
The Deputy Thread model is valuable for applications that prioritize background computation over DOM fidelity. But it should not be the only option. Developers who need synchronous JS interop should be able to opt into threading without losing it.
Related Issues
Environment
- .NET 10
- Blazor WebAssembly
- All modern browsers (Chrome, Edge, Firefox, Safari)
Description
When
<WasmEnableThreads>true</WasmEnableThreads>is set, the .NET runtime moves entirely to a background Web Worker (the "Deputy Thread" model). This makesDotNet.invokeMethod— synchronous JS-to-.NET calls — impossible, because the browser's UI thread cannot block while waiting for a response from a worker.I'm requesting a supported configuration option that enables .NET threading (thread pool,
Task.Run,System.Threading) while keeping the main .NET entry point on the browser's UI thread.Background
I maintain the SpawnDev.BlazorJS ecosystem — 41 NuGet packages, 323,000+ total downloads — which provides typed C# wrappers for JavaScript APIs in Blazor WebAssembly. This library depends on synchronous JS-to-.NET interop (
DotNet.invokeMethod) because the JavaScript specification requires synchronous handling in many scenarios:event.preventDefault()must be called synchronously within the handlerevent.stopImmediatePropagation()— same constraintbeforeunloadrequires a synchronous return valueThese are not edge cases. These are fundamental browser APIs that cannot be handled asynchronously.
Proposed Behavior
A configuration like:
When enabled:
Program.Mainexecutes on the browser's UI thread (as it does today without threading)DotNet.invokeMethod,[JSExport]with sync signatures) works normallyTask.Run,ThreadPool, andnew Thread()dispatch to background Web Workerslock,Monitor.Enter,Thread.Sleep) work on background threads but throw on the UI thread (this is already the browser's constraint)This is architecturally the same model that SpawnDev.BlazorJS.WebWorkers (90,000+ downloads) has used successfully for years: main .NET on the UI thread, heavy work dispatched to workers explicitly.
Why This Matters
Without this option, any .NET library that provides synchronous JavaScript interop is broken when threading is enabled. This affects:
The Deputy Thread model is valuable for applications that prioritize background computation over DOM fidelity. But it should not be the only option. Developers who need synchronous JS interop should be able to opt into threading without losing it.
Related Issues
Environment