Running background tasks in Blazor with Web Workers: Exploring the .NET 11 preview - Part 1 The article explores the new Web Worker project template introduced in the .NET 11 preview SDK, which allows Blazor WebAssembly applications to run CPU-intensive tasks on background threads without blocking the UI. It explains that Web Workers provide a way to achieve multi-threading in the browser's single-threaded JavaScript environment by enabling communication between background threads and the main UI thread through message passing. The post demonstrates how to add this template to an existing Blazor app, specifically showing how to replace static JSON data loading with a Web Worker that generates weather forecast data. In this post I take a look at the new Web Worker template available in the .NET 11 SDK, how to add it to an existing app, what the code is doing behind the scenes, and how to use it to run CPU intensive work without blocking the UI. This post was written using the features available in .NET 11 preview 3. Many things may change between now and the final release of .NET 11. Why do you need Web Workers? why-do-you-need-web-workers- One of the neat things about .NET running in the browser using Blazor is that you can easily handle all sorts of complex domains such as image processing, document parsing, or data manipulation. This is simple enough when you are running using Blazor Server, and you can run these CPU intensive tasks on the server. Unfortunately, if you are using Blazor WASM, it's not always so simple. The core problem is that the JavaScript engine e.g. V8 https://v8.dev/ is fundamentally single-threaded. That means if you're doing CPU-intensive work, then nothing else can happen—most importantly, the UI will become unresponsive, and the browser may even suggest closing the page. A related issue is that you can't use multi-threading because there's only a single-threaded event loop . That's where Web Workers https://developer.mozilla.org/en-US/docs/Web/API/Web Workers API/Using web workers come in. Web workers are a way to get multi-threading back, by running JavaScript or WebAssembly on a background thread. They can then communicate back to the main UI thread by posting messages to it. If you're used to creating .NET Windows Forms applications, this communication is somewhat analogous to the single-threaded-apartment model that requires you only modify UI elements on the STA Thread. Web Workers give you "true" multi-threading, but it is a somewhat limited version. It is a much more "cooperative" form of multi-tasking than you might be used to in .NET where using async / await or Task.Run can schedule work implicitly to run on the thread pool . In contrast, you need to explicitly schedule work to run on a Web Worker. It has been possible to use Web Workers with Blazor or pure WASM .NET applications since .NET 8, as described in these https://learn.microsoft.com/en-us/aspnet/core/blazor/blazor-with-dotnet-on-web-workers articles https://learn.microsoft.com/en-us/aspnet/core/client-side/dotnet-on-webworkers , but they're somewhat complex in terms of the number of moving parts to get it working. There's also an open source project, BlazorWorker https://github.com/Tewr/BlazorWorker , that aims to encapsulate this with a simple API. In .NET 11, a Web Worker project template has been added that similarly provides the bulk of the required code for Web Worker, to make it easier to run CPU intensive work on a background thread. For the rest of this post we'll look at how to use that project template, and what it contains. Adding the Web Worker project adding-the-web-worker-project In this section, I show how to add the Web Worker template to a solution, how to reference it from your Blazor app, and how to use it to run code on a Web Worker. Creating the initial Blazor app creating-the-initial-blazor-app We'll start by creating a basic Blazor WASM app. This is just the default template app that includes counter and weather forecast pages. The following is a simple script that creates this app called BlazorWebApp , places it in the /src/BlazorWebApp sub-folder, creates a .sln file, and adds the project to it: dotnet new sln mkdir src dotnet new blazorwasm -o ./src/BlazorWebApp dotnet sln add ./src/BlazorWebApp If you run the app using dotnet run , you'll get the familiar Blazor app: We're going to change how the forecasts are loaded. Currently, they're loading using an HTTP request for static JSON data. In our new approach, we'll invoke a method on a Web Worker which generates the data instead. Generating the Web Worker template generating-the-web-worker-template The first thing to do is to generate the Web Worker project. Note that this template is intended to be used as a standalone project, which you then reference in your main app, rather than by adding the template directly to your Blazor project. This differs from both the existing documentation on how to use Web Workers and the BlazorWorker project . The following creates the BlazorWebWorker project as a sibling project, and adds it to the solution: dotnet new webworker -o ./src/BlazorWebWorker dotnet sln add ./src/BlazorWebWorker This template consists of just a few files, as you can see below: We'll look in detail at the content of these files later. For now, we'll just look at how to use this project in your Blazor app. Updating the Blazor app to reference the Web Worker project updating-the-blazor-app-to-reference-the-web-worker-project The Web Worker template creates a separate project, so you need to reference it from your main app: dotnet add ./src/BlazorWebApp reference ./src/BlazorWebWorker We're also going to use the JSExport attribute, which means we need to explicitly enable unsafe code by adding