SpawnDev.BlazorJS.WebWorkers 1.8.0

There is a newer version of this package available.
See the version list below for details.
dotnet add package SpawnDev.BlazorJS.WebWorkers --version 1.8.0                
NuGet\Install-Package SpawnDev.BlazorJS.WebWorkers -Version 1.8.0                
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="SpawnDev.BlazorJS.WebWorkers" Version="1.8.0" />                
For projects that support PackageReference, copy this XML node into the project file to reference the package.
paket add SpawnDev.BlazorJS.WebWorkers --version 1.8.0                
#r "nuget: SpawnDev.BlazorJS.WebWorkers, 1.8.0"                
#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.
// Install SpawnDev.BlazorJS.WebWorkers as a Cake Addin
#addin nuget:?package=SpawnDev.BlazorJS.WebWorkers&version=1.8.0

// Install SpawnDev.BlazorJS.WebWorkers as a Cake Tool
#tool nuget:?package=SpawnDev.BlazorJS.WebWorkers&version=1.8.0                

NuGet

Package Description Link
SpawnDev.BlazorJS Enhanced Blazor WebAssembly Javascript interop NuGet version
SpawnDev.BlazorJS.WebWorkers Blazor WebAssembly WebWorkers and SharedWebWorkers NuGet version

SpawnDev.BlazorJS

NuGet

An easy Javascript interop library designed specifically for client side Blazor.

Supports Blazor WebAssembly .Net 6, 7, and 8.

  • Use Javascript libraries in Blazor without writing any Javascript code.
  • Alternative access to IJSRuntime JS is globally available without injection and is usable on the first line of Program.cs
  • Get and set global properties via JS.Set and JS.Get
  • Create new Javascript objects with JS.New
  • Get and set object properties via IJSInProcessObjectReference extended methods
  • Create Callbacks that can be sent to Javascript event listeners or assigned to javascript variables

JS

// Get Set
var innerHeight = JS.Get<int>("window.innerHeight");
JS.Set("document.title", "Hello World!");

// Call
var item = JS.Call<string?>("localStorage.getItem", "itemName");
JS.CallVoid("addEventListener", "resize", Callback.Create(() => Console.WriteLine("WindowResized"), _callBacks));

IJSInProcessObjectReference extended

// Get Set
var window = JS.Get<IJSInProcessObjectReference>("window");
window.Set("myVar", 5);
var myVar = window.Get<int>("myVar");

// Call
window.CallVoid("addEventListener", "resize", Callback.Create(() => Console.WriteLine("WindowResized")));

Create a new Javascript object

var worker = JS.New("Worker", myWorkerScript);

Callback

Pass methods to Javascript using the Callback.Create and Callback.CreateOne methods. These method use type arguments to set the type expected for incoming arguments (if any) and the expected return type (if any.) async methods are passed as Promises.

Pass lambda callbacks to Javascript

JS.Set("testCallback", Callback.Create<string>((strArg) => {
    Console.WriteLine($"Javascript sent: {strArg}");
    // this prints "Hello callback!"
}));
// in Javascript
testCallback('Hello callback!');

Pass method callbacks to Javascript

string SomeNetFn(string input){
    return $"Recvd: {input}";
}

JS.Set("someNetFn", Callback.CreateOne<string, string>(SomeNetFn));
// in Javascript
someNetFn('Hello callback!');

// prints
Recvd: Hello callback!

Pass async method callbacks to Javascript Under the hood, BlazorJS is returning a Promise to javascript when the method is called

async Task<string> SomeNetFnAsync(string input){
    return $"Recvd: {input}";
}

JS.Set("someNetFnAsync", Callback.CreateOne<string, string>(SomeNetFnAsync));
// in Javascript
await someNetFnAsync('Hello callback!');

// prints
Recvd: Hello callback!

JSObject

JSObjects are wrappers around IJSInProcessReference objects that can be passed to and from Javascript and allow strongly typed access to the underlying object.

Use the extended functions of IJSInProcessObjectReference to work with Javascript objects or use the growing library of over 100 of the most common Javascript objects, including ones for Window, HTMLDocument, WebStorage (localStorage and sessionStorage), WebGL, WebRTC, and more in SpawnDev.BlazorJS.JSObjects. JSObjects are wrappers around IJSInProcessObjectReference that allow strongly typed use.

Custom JSObjects

Implement your own JSObject classes for Javascript objects not already available in the BlazorJS.JSObjects library.

Instead of this (simple but not as reusable)

var audio = JS.New("Audio", "https://some_audio_online");
audio.CallVoid("play");

You can do this...
Create a custom JSObject wrapper

[JsonConverter(typeof(JSObjectConverter<Audio>))]
public class Audio : JSObject
{
    public Audio(IJSInProcessObjectReference _ref) : base(_ref) { }
    public Audio(string url) : base(JS.New("Audio", url)) { }
    public void Play() => JSRef.CallVoid("play");
}

Then use your new object

var audio = new Audio("https://some_audio_online");
audio.Play();

Promise

Below is a an example that uses Promises to utilize the Web Locks API

using var navigator = JS.Get<Navigator>("navigator");
using var locks = navigator.Locks;

Console.WriteLine($"lock: 1");

using var waitLock = locks.Request("my_lock", Callback.CreateOne((Lock lockObj) => new Promise(async () => {
    Console.WriteLine($"lock acquired 3");
    await Task.Delay(5000);
    Console.WriteLine($"lock released 4");
})));

using var waitLock2 = locks.Request("my_lock", Callback.CreateOne((Lock lockObj) => new Promise(async () => {
    Console.WriteLine($"lock acquired 5");
    await Task.Delay(5000);
    Console.WriteLine($"lock released 6");
})));

Console.WriteLine($"lock: 2");

SpawnDev.BlazorJS.WebWorkers

NuGet

  • Easily call Blazor Services in separate threads with WebWorkers and SharedWebWorkers

  • Does not require SharedArrayBuffer and therefore does not require the special HTTP headers associated with using it.

  • Supports and uses transferable objects whenever possible

  • Works in Blazor WASM .Net 6, 7, and 8.

  • Tested on (with .Net 8):
    Chrome Windows - Working
    MS Edge Windows - Working
    Firefox Windows - Working
    Chrome Android - Working
    MS Edge Android - Working
    Firefox Android - Working

Firefox WebWorkers note:
Firefox does not support dynamic modules in workers, which originally made BlazorJS.WebWorkers fail in that browser. The web worker script now tries to detect this and changes the blazor wasm scripts before they are loaded to workaround this limitation. It is possible some other browsers may have this issue but may not be detected properly.

Issues can be reported here on GitHub.

Example WebWorkerService setup and usage

// Program.cs
...
using SpawnDev.BlazorJS;
using SpawnDev.BlazorJS.WebWorkers;

var builder = WebAssemblyHostBuilder.CreateDefault(args);
if (JS.IsWindow)
{
    // we can skip adding dom objects in non UI threads
    builder.RootComponents.Add<App>("#app");
    builder.RootComponents.Add<HeadOutlet>("head::after");
}
// add services
builder.Services.AddSingleton((sp) => new HttpClient { BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) });
// SpawnDev.BlazorJS.WebWorkers
builder.Services.AddSingleton<WebWorkerService>();
// app specific services...
// worker services should be registered with an interface to work with WebWorker.GetService<TServiceInterface>()
builder.Services.AddSingleton<IMathsService, MathsService>();
// build 
WebAssemblyHost host = builder.Build();
// init WebWorkerService 
var workerService = host.Services.GetRequiredService<WebWorkerService>();
await workerService.InitAsync();
await host.RunAsync();

WebWorker


// Create a WebWorker
var webWorker = await workerService.GetWebWorker();

// Call GetService<ServiceInterface> on a web worker to get a proxy for the service on the web worker.
// GetService can only be called with Interface types
var workerMathService = webWorker.GetService<IMathsService>();

// Call async methods on your worker service
var result = await workerMathService.CalculatePi(piDecimalPlaces);

// Action types can be passed for progress reporting
var result = await workerMathService.CalculatePiWithActionProgress(piDecimalPlaces, new Action<int>((i) =>
{
    // the worker thread can call this method to report progress if desired
    piProgress = i;
    StateHasChanged();
}));

SharedWebWorker

Calling GetSharedWebWorker in another window with the same sharedWorkerName will return the same SharedWebWorker

// Create or get SHaredWebWorker with the provided sharedWorkerName
var sharedWebWorker = await workerService.GetSharedWebWorker("workername");

// Just like WebWorker but shared
var workerMathService = sharedWebWorker.GetService<IMathsService>();

// Call async methods on your shared worker service
var result = await workerMathService.CalculatePi(piDecimalPlaces);

Send events

// Optionally listen for event messages
worker.OnMessage += (sender, msg) =>
{
    if (msg.TargetName == "progress")
    {
        PiProgress msgData = msg.GetData<PiProgress>();
        piProgress = msgData.Progress;
        StateHasChanged();
    }
};

// From SharedWebWorker or WebWorker threads send an event to connected parents
workerService.SendEventToParents("progress", new PiProgress { Progress = piProgress });

// Or on send an event to a connected worker
webWorker.SendEvent("progress", new PiProgress { Progress = piProgress });

Worker Transferable JSObjects

Faster is better. SpawnDev WebWorkers use transferable objects by default for better performance, but it can be disabled with WorkerTransferAttribute. Setting WorkerTransfer to false will cause the property, return value, or parameter to be copied to the receiving thread instead of transferred.

Example

        public class ProcessFrameResult : IDisposable
        {
            [WorkerTransfer(false)]
            public ArrayBuffer? ArrayBuffer { get; set; }
            public byte[]? HomographyBytes { get; set; }
            public void Dispose(){
                ArrayBuffer?.Dispose();
            }
        }

        [return: WorkerTransfer(false)]
        public async Task<ProcessFrameResult?> ProcessFrame([WorkerTransfer(false)] ArrayBuffer? frameBuffer, int width, int height, int _canny0, int _canny1, double _needlePatternSize)
        {
            var ret = new ProcessFrameResult();
            // ...
            return ret;
        }

In the above example; the WorkerTransferAttribute on the return type set to false will prevent all properties of the return type from being transferred.

Transferable JSObject types

ArrayBuffer
MessagePort
ReadableStream
WritableStream
TransformStream
AudioData
ImageBitmap
VideoFrame
OffscreenCanvas
RTCDataChannel

IDisposable

NOTE: The above code shows quick examples. Some objects implement IDisposable, such as JSObject, Callback, and IJSInProcessObjectReference types.

JSObject types will dispose of their IJSInProcessObjectReference object when their finalizer is called if not previously disposed.

Callback types must be disposed unless created with the Callback.CreateOne method, in which case they will dispose themselves after the first callback. Disposing a Callback prevents it from being called.

IJSInProcessObjectReference does not dispose of interop resources with a finalizer and MUST be disposed when no longer needed. Failing to dispose these will cause memory leaks.

IDisposable objects returned from a WebWorker or SharedWorker service are automatically disposed after the data has been sent to the calling thread.

Support

Issues can be reported here on GitHub.

Inspired by Tewr's BlazorWorker implementation. Thank you! I wrote my implementation from scratch as I needed workers in .Net 7.
https://github.com/Tewr/BlazorWorker

BlazorJS and WebWorkers Demo
https://blazorjs.spawndev.com/

Buy me a coffee

paypal

Product Compatible and additional computed target framework versions.
.NET net6.0 is compatible.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 is compatible.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 is compatible.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages (1)

Showing the top 1 NuGet packages that depend on SpawnDev.BlazorJS.WebWorkers:

Package Downloads
SpawnDev.BlazorJS.PeerJS

PeerJS simplifies peer-to-peer data, video, and audio calls in Blazor WebAssembly

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last updated
2.5.21 33 11/21/2024
2.5.20 64 11/20/2024
2.5.19 72 11/18/2024
2.5.18 67 11/17/2024
2.5.17 75 11/16/2024
2.5.16 68 11/15/2024
2.5.15 66 11/15/2024
2.5.14 70 11/14/2024
2.5.13 77 11/13/2024
2.5.12 54 11/10/2024
2.5.11 161 10/31/2024
2.5.10 219 10/9/2024
2.5.9 93 9/27/2024
2.5.8 545 8/13/2024
2.5.6 73 8/8/2024
2.5.5 113 8/7/2024
2.5.4 88 8/6/2024
2.5.3 77 8/5/2024
2.5.2 81 8/5/2024
2.5.1 118 7/26/2024
2.5.0 79 7/26/2024
2.4.7 93 7/24/2024
2.4.6 95 7/22/2024
2.4.5 152 7/19/2024
2.4.4 93 7/18/2024
2.4.3 112 7/16/2024
2.4.2 76 7/15/2024
2.4.0 72 7/15/2024
2.3.8 79 7/14/2024
2.3.7 123 7/9/2024
2.3.6 98 7/8/2024
2.3.5 95 7/6/2024
2.3.4 92 7/4/2024
2.3.3 132 6/23/2024
2.3.2 127 6/16/2024
2.3.1 219 6/13/2024
2.3.0 100 6/12/2024
2.2.106 112 6/5/2024
2.2.105 133 5/31/2024
2.2.104 116 5/30/2024
2.2.103 99 5/29/2024
2.2.102 111 5/28/2024
2.2.101 111 5/22/2024
2.2.100 148 5/17/2024
2.2.99 101 5/17/2024
2.2.98 115 5/16/2024
2.2.97 132 5/15/2024
2.2.96 87 5/14/2024
2.2.95 95 5/13/2024
2.2.94 100 5/11/2024
2.2.93 120 5/7/2024
2.2.92 111 5/7/2024
2.2.91 131 5/3/2024
2.2.90 86 5/3/2024
2.2.89 66 5/2/2024
2.2.88 72 5/2/2024
2.2.87 128 4/26/2024
2.2.86 112 4/26/2024
2.2.85 134 4/18/2024
2.2.84 121 4/18/2024
2.2.83 125 4/16/2024
2.2.82 148 4/8/2024
2.2.81 118 4/8/2024
2.2.80 136 4/7/2024
2.2.79 121 4/6/2024
2.2.78 123 4/5/2024
2.2.77 121 4/5/2024
2.2.76 116 4/4/2024
2.2.75 104 4/4/2024
2.2.73 94 4/3/2024
2.2.72 111 4/3/2024
2.2.71 109 4/3/2024
2.2.70 109 4/2/2024
2.2.69 272 4/1/2024
2.2.68 117 3/29/2024
2.2.67 151 3/27/2024
2.2.66 125 3/24/2024
2.2.65 121 3/21/2024
2.2.64 174 3/11/2024
2.2.63 123 3/9/2024
2.2.62 132 3/7/2024
2.2.61 127 3/6/2024
2.2.60 123 3/6/2024
2.2.58 177 3/2/2024
2.2.57 198 2/24/2024
2.2.56 143 2/18/2024
2.2.55 118 2/17/2024
2.2.53 127 2/15/2024
2.2.52 120 2/15/2024
2.2.51 120 2/15/2024
2.2.49 871 2/2/2024
2.2.48 1,368 12/29/2023
2.2.47 181 12/20/2023
2.2.46 126 12/15/2023
2.2.45 141 12/10/2023
2.2.44 130 12/10/2023
2.2.42 140 12/9/2023
2.2.41 132 12/9/2023
2.2.40 125 12/8/2023
2.2.38 1,119 11/21/2023
2.2.37 449 11/16/2023
2.2.36 102 11/16/2023
2.2.35 155 11/14/2023
2.2.34 121 11/13/2023
2.2.33 82 11/10/2023
2.2.32 95 11/10/2023
2.2.31 89 11/9/2023
2.2.28 103 11/7/2023
2.2.27 153 10/31/2023
2.2.26 174 10/22/2023
2.2.25 96 10/20/2023
2.2.24 99 10/20/2023
2.2.23 107 10/20/2023
2.2.22 105 10/20/2023
2.2.21 100 10/20/2023
2.2.20 88 10/19/2023
2.2.19 90 10/19/2023
2.2.18 94 10/19/2023
2.2.17 187 10/13/2023
2.2.16 497 10/12/2023
2.2.15 86 10/12/2023
2.2.14 117 10/5/2023
2.2.13 97 10/5/2023
2.2.12 95 10/5/2023
2.2.11 255 10/3/2023
2.2.10 169 9/18/2023
2.2.9 95 9/18/2023
2.2.8 264 9/14/2023
2.2.7 106 9/13/2023
2.2.6 6,610 9/6/2023
2.2.5 147 8/30/2023
2.2.4 154 8/26/2023
2.2.3 121 8/20/2023
2.2.2 107 8/18/2023
2.2.1 118 8/11/2023
2.2.0 208 7/17/2023
2.1.15 131 5/26/2023
2.1.14 111 5/20/2023
2.1.13 126 4/26/2023
2.1.12 196 4/21/2023
2.1.11 116 4/19/2023
2.1.10 136 4/19/2023
2.1.8 145 4/10/2023
2.1.7 168 3/27/2023
2.1.6 141 3/24/2023
2.1.5 141 3/23/2023
2.1.4 146 3/23/2023
2.1.3 147 3/23/2023
2.1.2 142 3/21/2023
2.1.0 144 3/21/2023
2.0.3 151 3/21/2023
2.0.2 141 3/20/2023
2.0.1 142 3/20/2023
2.0.0 152 3/20/2023
1.9.2 153 3/14/2023
1.8.1 144 3/11/2023
1.8.0 142 3/10/2023
1.7.1 145 3/10/2023
1.7.0 135 3/8/2023
1.6.4 151 3/1/2023
1.6.3 308 1/31/2023
1.6.2 320 1/24/2023
1.6.1 329 1/11/2023
1.6.0 329 1/11/2023
1.5.0 373 12/23/2022
1.4.0 323 12/20/2022
1.3.0 344 12/16/2022
1.2.7 350 12/16/2022
1.2.5 321 12/14/2022
1.2.4.1 330 12/13/2022
1.2.4 319 12/13/2022
1.2.3 321 12/13/2022