Soenneker.Blazor.WebWorkers 4.0.18

Prefix Reserved
dotnet add package Soenneker.Blazor.WebWorkers --version 4.0.18
                    
NuGet\Install-Package Soenneker.Blazor.WebWorkers -Version 4.0.18
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Soenneker.Blazor.WebWorkers" Version="4.0.18" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Soenneker.Blazor.WebWorkers" Version="4.0.18" />
                    
Directory.Packages.props
<PackageReference Include="Soenneker.Blazor.WebWorkers" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add Soenneker.Blazor.WebWorkers --version 4.0.18
                    
#r "nuget: Soenneker.Blazor.WebWorkers, 4.0.18"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package Soenneker.Blazor.WebWorkers@4.0.18
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=Soenneker.Blazor.WebWorkers&version=4.0.18
                    
Install as a Cake Addin
#tool nuget:?package=Soenneker.Blazor.WebWorkers&version=4.0.18
                    
Install as a Cake Tool

alternate text is missing from this package README image alternate text is missing from this package README image alternate text is missing from this package README image alternate text is missing from this package README image alternate text is missing from this package README image

alternate text is missing from this package README image Soenneker.Blazor.WebWorkers

Run background work in Blazor without freezing the UI.

This package gives you one simple API for browser web workers in Blazor.

Use it when you want to:

  • move CPU-heavy work off the UI thread
  • keep the app responsive while work is running
  • run custom JavaScript worker jobs
  • run exported C# methods in JS
  • monitor progress, cancel requests, and inspect worker pool state

Install

dotnet add package Soenneker.Blazor.WebWorkers

The Basic Idea

Soenneker.Blazor.WebWorkers manages worker pools for you.

In most apps, the flow is:

  1. Register IWebWorkersUtil
  2. Call Initialize()
  3. Create a worker pool
  4. Queue work
  5. Optionally monitor progress, cancel work, or inspect snapshots

The same IWebWorkersUtil service works for both:

  • JavaScript workers
  • .NET workers

Quick Start

Register the service in Program.cs:

builder.Services.AddWebWorkersUtilAsScoped();

Inject it where you want to use it:

@inject IWebWorkersUtil WebWorkers

Initialize it once before first use:

await WebWorkers.Initialize();

Common Workflow

1. Create a JavaScript worker pool

Point the pool at your worker script:

await WebWorkers.CreatePool(new WebWorkerPoolOptions
{
    WorkerCount = 4,
    ScriptPath = "js/workers/app.worker.js"
});

That creates the default JavaScript pool.

2. Queue a JavaScript job

Pass a workload name and payload:

using System.Text.Json;
using Soenneker.Blazor.WebWorkers.Dtos;

WebWorkerResult<JsonElement> result = await WebWorkers.Run<JsonElement>(
    "prime-analysis",
    new
    {
        upperBound = 180000
    },
    progress =>
    {
        Console.WriteLine($"{progress.Percent:0}% - {progress.Message}");
        return ValueTask.CompletedTask;
    });

Your worker script is responsible for understanding the workload name and payload.

3. Cancel or inspect work

await WebWorkers.CancelRequest("default", jobId);

WebWorkerCoordinatorSnapshot snapshot = await WebWorkers.GetCoordinatorSnapshot();

JavaScript Worker Path

This is the best fit when your worker logic already lives in JavaScript, or when you want full control over the worker script.

Important points:

  • JavaScript pools use WebWorkerBackend.JavaScript
  • the default pool name is "default"
  • you usually only need WorkerCount and ScriptPath
  • jobs are queued with a workloadName and optional payload
  • you can report progress back while work is running

You can also target a specific named pool:

await WebWorkers.CreatePool(new WebWorkerPoolOptions
{
    Name = "images",
    WorkerCount = 2,
    ScriptPath = "js/workers/image.worker.js"
});

WebWorkerResult<JsonElement> result = await WebWorkers.Run<JsonElement>(
    "images",
    "generate-thumbnail",
    new
    {
        width = 300,
        height = 300
    });

Worker scripts from a Razor class library

If a worker file ships from an RCL, build the static asset path like this:

string workerPath = WebWorkerAssetPaths.WorkerFromPackage(
    "Soenneker.Blazor.Opfs",
    "opfs.worker.js");

Then use that path as the pool's ScriptPath.

.NET Worker Path

This package can also run exported C# methods inside a browser worker by booting a second .NET WebAssembly runtime in that worker.

This path is useful when:

  • your work is already written in C#
  • you want to keep background logic in your Blazor app
  • you do not want to hand-write a JavaScript worker for that job

Requirements

The .NET worker path requires:

  • Blazor WebAssembly
  • AllowUnsafeBlocks=true in the app .csproj
  • exported worker methods defined in the main app assembly
  • worker methods marked with [JSExport]

Example .csproj setting:

<PropertyGroup>
  <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>

Define an exported worker method

using System.Runtime.InteropServices.JavaScript;
using System.Runtime.Versioning;
using Soenneker.Utils.Json;

[SupportedOSPlatform("browser")]
public static partial class WorkerExports
{
    [JSExport]
    public static string? AnalyzePrimeRange(int upperBound)
    {
        return JsonUtil.Serialize(new
        {
            upperBound,
            message = "Ran inside a .NET worker."
        });
    }
}

Create a .NET worker pool

using Soenneker.Blazor.WebWorkers.Enums;
using Soenneker.Blazor.WebWorkers.Options;

await WebWorkers.CreatePool(new WebWorkerPoolOptions
{
    Backend = WebWorkerBackend.DotNet,
    WorkerCount = 1
});

Invoke the exported method

You can call it with a request object:

using Soenneker.Blazor.WebWorkers.Dtos;
using Soenneker.Blazor.WebWorkers.Enums;

WebWorkerResult<string?> result = await WebWorkers.Run<string?>(new WebWorkerRequest
{
    Backend = WebWorkerBackend.DotNet,
    MethodName = "MyApp.WorkerExports.AnalyzePrimeRange",
    Arguments = [220000]
});

Or use the expression-based overload:

WebWorkerResult<MyResult> result =
    await WebWorkers.Run(() => WorkerExports.RunAnalysisAsync(220000));

The expression-based overload is often the easiest option because it avoids building the request manually.

Important Types

IWebWorkersUtil

The main service you work with. It handles:

  • initialization
  • pool creation and destruction
  • job execution
  • cancellation
  • pool and coordinator snapshots

WebWorkerPoolOptions

Used when creating a pool.

The most important properties are:

  • Backend
  • Name
  • ScriptPath
  • WorkerCount
  • WorkerType
  • RuntimeScriptPath
  • BootConfigPath
  • RestartFaultedWorkers

WebWorkerRequest

Used when you need full control over a queued request.

The most important properties are:

  • PoolName
  • Backend
  • RequestId
  • WorkloadName
  • MethodName
  • Payload
  • Arguments
  • TimeoutMs

Monitoring and Cancellation

You can:

  • receive progress callbacks while a job is running
  • cancel a queued or running request
  • inspect one pool or all pools
  • inspect a full coordinator snapshot

Examples:

await WebWorkers.CancelRequest("default", requestId);

WebWorkerPoolSnapshot? pool = await WebWorkers.GetPoolSnapshot("default");
IReadOnlyList<WebWorkerPoolSnapshot> pools = await WebWorkers.GetPoolSnapshots();
WebWorkerCoordinatorSnapshot snapshot = await WebWorkers.GetCoordinatorSnapshot();

Things To Know

  • JavaScript and .NET workers share the same top-level service: IWebWorkersUtil
  • JavaScript jobs use WorkloadName plus Payload
  • .NET jobs use MethodName plus Arguments
  • the .NET worker path is for Blazor WebAssembly
  • .NET worker methods should usually return simple values or serialized JSON
  • if your worker code naturally returns ValueTask, expose a small Task-returning [JSExport] wrapper
  • cancellation of a running .NET worker request may require terminating and replacing the backing worker

Which Path Should I Use?

Use the JavaScript path when:

  • you already have worker logic in JavaScript
  • you need a custom browser worker script
  • your workload is naturally message-based

Use the .NET path when:

  • your workload is already implemented in C#
  • you want to stay in C# as much as possible
  • you are building a Blazor WebAssembly app (Not available in Server)
Product Compatible and additional computed target framework versions.
.NET net10.0 is compatible.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
4.0.18 0 4/15/2026
4.0.17 3 4/15/2026
4.0.16 39 4/15/2026
4.0.15 30 4/14/2026
4.0.14 33 4/14/2026
4.0.13 50 4/13/2026
4.0.12 47 4/13/2026
4.0.11 42 4/13/2026
4.0.10 74 4/8/2026
4.0.9 70 4/8/2026
4.0.8 87 4/8/2026
4.0.7 88 4/8/2026
4.0.6 82 4/8/2026
4.0.5 79 4/7/2026
4.0.4 84 4/6/2026
4.0.3 87 4/5/2026
4.0.2 94 4/3/2026
4.0.1 88 4/1/2026