PardusLabs.JSVaporizer.NET.8
1.0.9.2
See the version list below for details.
dotnet add package PardusLabs.JSVaporizer.NET.8 --version 1.0.9.2
NuGet\Install-Package PardusLabs.JSVaporizer.NET.8 -Version 1.0.9.2
<PackageReference Include="PardusLabs.JSVaporizer.NET.8" Version="1.0.9.2" />
<PackageVersion Include="PardusLabs.JSVaporizer.NET.8" Version="1.0.9.2" />
<PackageReference Include="PardusLabs.JSVaporizer.NET.8" />
paket add PardusLabs.JSVaporizer.NET.8 --version 1.0.9.2
#r "nuget: PardusLabs.JSVaporizer.NET.8, 1.0.9.2"
#addin nuget:?package=PardusLabs.JSVaporizer.NET.8&version=1.0.9.2
#tool nuget:?package=PardusLabs.JSVaporizer.NET.8&version=1.0.9.2
JSVaporizer
JSVaporizer is a minimal, opinionated .NET-to-JavaScript interop layer for WebAssembly-based apps. It provides two-way bindings:
- .NET → JavaScript through
[JSImport]
wrappers. - JavaScript → .NET via
[JSExport]
methods and delegate pools for event handling and generic function invocation.
The code in this repository allows you to:
- Dynamically create and manage DOM elements from the .NET side.
- Call existing JavaScript functions (and function properties) by name.
- Register C# delegates so that JavaScript can call into them (useful for event handlers, utilities, etc.).
- Maintain dictionaries of these delegates (function pools), avoiding direct references in JS while still enabling dynamic binding.
Table of Contents
- Requirements
- Key Concepts
- Examples
- Project Structure
- Thread Safety
- Performance Considerations
- License
Requirements
- .NET 8 or higher.
- WebAssembly-compatible runtime (e.g., Sdk.WebAssembly).
- A build or project setup that supports C#-to-JS interop using
[JSExport]
and[JSImport]
(e.g., an ASP.NET Core WebAssembly project referencingSystem.Runtime.InteropServices.JavaScript
).
Key Concepts
1. Partial Classes for Interop
All JS-bound methods are grouped into nested partial classes under a common JSVapor
static class. For example, WasmElement
, WasmDocument
, and WasmWindow
are partial classes that each contain [JSImport]
methods to call JavaScript functions.
Similarly, WasmExports
is where we place [JSExport]
methods—these are .NET methods callable from JavaScript.
2. Event Handler and Generic Function Pools
We keep dictionaries to store .NET delegates:
WasmJSVEventHandlerPool
: Holds delegates for DOM event handlers.WasmJSVGenericFuncPool
: Holds delegates for arbitrary functions that JavaScript can invoke by key.
This approach avoids creating direct named methods for every single handler in [JSExport]
. Instead, JavaScript only needs a “function key,” and we look up the actual C# method in the dictionary.
3. Ephemeral JSObject
References
When you request a DOM JSObject
for an element, the code automatically disposes it if it’s connected (isConnected == true
). This ensures we don’t hold on to many JSObject
instances in .NET, which can hurt memory usage. On subsequent calls, the system retrieves a fresh reference by calling document.getElementById
or similar.
4. Custom Exceptions and Error Handling
We use a custom JSVException
class for domain-specific errors (e.g., attribute name is not lowercase, key collisions, missing event handlers). This is to keep interop errors well-defined rather than throwing generic exceptions.
Examples
Creating a DOM Element in .NET
// Create a new <div> element with id="myDiv"
var newDiv = JSVapor.Document.CreateElement("myDiv", "div");
// Set an attribute
newDiv.SetAttribute("class", "myClass");
// Append it to another element
var parentElement = JSVapor.Document.AssertGetElementById("parentContainer");
parentElement.AppendChild(newDiv);
Calling JavaScript Functions from .NET
// Using the WasmJSFunctionPool (which calls JS by function key)
var result = JSVapor.JSFunctionPool.CallFunc("myJsFunctionKey", new object[] { "arg1", 42 });
Here, "myJsFunctionKey" corresponds to a JavaScript-side registration (for example, your JS might have something like window.jsFunctionPool.myJsFunctionKey = function(a, b) { ... }).
Adding Event Handlers
// Suppose you want to handle a "click" event on your newly created div.
newDiv.AddEventListener(
"click",
funcKey: "myClickHandler",
handler: (elem, eventType, evnt) =>
{
// do your .NET side logic
// return an int that indicates whether to stopPropagation or preventDefault
return 0; // e.g., 0 = default prop, 1 = default no prop, etc.
}
);
When JavaScript triggers the click event, it calls into .NET by using the [JSExport]
method CallJSVEventHandler
, which looks up your handler in WasmJSVEventHandlerPool
.
Registering a Generic Function for JS to Call
// In .NET, define a function you want JavaScript to call:
JSVGenericFunction myFunc = (object[] args) =>
{
// Implementation here...
return "Hello from .NET!";
};
// Register it by key
JSVapor.JSVGenericFunctionPool.RegisterJSVGenericFunction("myGenericFuncKey", myFunc);
// On the JavaScript side, you'd do something like:
// const result = Module.jsvGenericFunctionPool.callJSVGenericFunction("myGenericFuncKey", ["any", "args"]);
Project Structure
JSVaporizer/
|
├── JSVapor.cs
| ├── public static partial class JSVapor
| │ ├── internal partial class WasmExports // [JSExport] methods
| │ ├── internal partial class WasmElement // [JSImport] "element"...
| │ ├── internal partial class WasmDocument // [JSImport] "document"...
| │ ├── internal partial class WasmWindow // [JSImport] "window"...
| │ ├── internal partial class WasmJSFunctionPool // [JSImport] "jsFunctionPool"...
| │ ├── internal partial class WasmJSVEventHandlerPool
| │ ├── internal partial class WasmJSVGenericFuncPool
| │ └── (etc.)
|
├── Element.cs // The JSVapor.Element class, a higher-level wrapper for DOM elements
├── Document.cs // The JSVapor.Document class, includes the dictionary of known Elements, creation, getById, etc.
├── Other .cs files for exceptions, shared enumerations, etc.
|
└── README.md
Product | Versions Compatible and additional computed target framework versions. |
---|---|
.NET | 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. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. |
-
net8.0
- Microsoft.AspNetCore.Html.Abstractions (>= 2.3.0)
- Microsoft.AspNetCore.Mvc.ViewFeatures (>= 2.3.0)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.