WebAssembly 1.3.0
dotnet add package WebAssembly --version 1.3.0
NuGet\Install-Package WebAssembly -Version 1.3.0
<PackageReference Include="WebAssembly" Version="1.3.0" />
<PackageVersion Include="WebAssembly" Version="1.3.0" />
<PackageReference Include="WebAssembly" />
paket add WebAssembly --version 1.3.0
#r "nuget: WebAssembly, 1.3.0"
#addin nuget:?package=WebAssembly&version=1.3.0
#tool nuget:?package=WebAssembly&version=1.3.0
WebAssembly for .NET
[!WARNING] Only WebAssembly 1.0 is supported! Most WASM files target a higher version and will encounter errors if you try to load them with WebAssembly for .NET.
A library able to create, read, modify, write, execute WebAssembly (WASM) files from .NET-based applications. It can also convert WASM files to .NET DLLs. Execution does not use an interpreter or a 3rd party library: WASM instructions are mapped to their .NET equivalents and converted to native machine language by the .NET JIT compiler.
Available on NuGet at https://www.nuget.org/packages/WebAssembly .
Getting Started
- Use the
WebAssembly.Module
class to create, read, modify, and write WebAssembly (WASM) binary files.Module.ReadFromBinary
reads a stream into an instance, which can then be inspected and modified through its properties.- Most WASM files use post-1.0 features and will experience errors when you try to load them.
WriteToBinary
on a module instance writes binary WASM to the provided stream.
- Use the
WebAssembly.Runtime.Compile
class to execute WebAssembly (WASM) binary files using the .NET JIT compiler or convert it to a .NET DLL.- Most WASM files have many imports and exports--you'll need to cover these yourself.
- This should work for most WASM 1.0 files, but spec compliance is not perfect.
- This will not work for any newer-than-1.0 files
- Saving to a DLL requires .NET 9 or higher and has several additional steps.
You're welcome to report a bug if you can share a WASM file that has a problem, but no one is actively working on this project so a fix may not come.
Sample: Create and execute a WebAssembly file in memory
using System;
using WebAssembly; // Acquire from https://www.nuget.org/packages/WebAssembly
using WebAssembly.Instructions;
using WebAssembly.Runtime;
// Module can be used to create, read, modify, and write WebAssembly files.
var module = new Module(); // In this case, we're creating a new one.
// Types are function signatures: the list of parameters and returns.
module.Types.Add(new WebAssemblyType // The first added type gets index 0.
{
Parameters =
[
WebAssemblyValueType.Int32, // This sample takes a single Int32 as input.
// Complex types can be passed by sending them in pieces.
],
Returns =
[
// Multiple returns are supported by the binary format.
// Standard currently allows a count of 0 or 1, though.
WebAssemblyValueType.Int32,
],
});
// Types can be re-used for multiple functions to reduce WASM size.
// The function list associates a function index to a type index.
module.Functions.Add(new Function // The first added function gets index 0.
{
Type = 0, // The index for the "type" value added above.
});
// Code must be passed in the exact same order as the Functions above.
module.Codes.Add(new FunctionBody
{
Code =
[
new LocalGet(0), // The parameters are the first locals, in order.
// We defined the first parameter as Int32, so now an Int32 is at the top of the stack.
new Int32CountOneBits(), // Returns the count of binary bits set to 1.
// It takes the Int32 from the top of the stack, and pushes the return value.
// So, in the end, there is still a single Int32 on the stack.
new End(), // All functions must end with "End".
// The final "End" also delivers the returned value.
],
});
// Exports enable features to be accessed by external code.
// Typically this means JavaScript, but this library adds .NET execution capability, too.
module.Exports.Add(new Export
{
Kind = ExternalKind.Function,
Index = 0, // This should match the function index from above.
Name = "Demo", // Anything legal in Unicode is legal in an export name.
});
// We now have enough for a usable WASM file, which we could save with module.WriteToBinary().
// Below, we show how the Compile feature can be used for .NET-based execution.
// For stream-based compilation, WebAssembly.Compile should be used.
var instanceCreator = module.Compile<Sample>(); // Sample is defined later.
// Instances should be wrapped in a "using" block for automatic disposal.
// This sample doesn't import anything, so we pass an empty import dictionary.
using (var instance = instanceCreator(new ImportDictionary()))
{
// FYI, instanceCreator can be used multiple times to create independent instances.
Console.WriteLine(instance.Exports.Demo(0)); // Binary 0, result 0
Console.WriteLine(instance.Exports.Demo(1)); // Binary 1, result 1,
Console.WriteLine(instance.Exports.Demo(42)); // Binary 101010, result 3
} // Automatically release the WebAssembly instance here.
public abstract class Sample
{
// Sometimes you can use C# dynamic instead of building an abstract class like this.
public abstract int Demo(int value);
}
Sample: Convert a WASM file to a .NET DLL
[!NOTE] This feature is experimental.
The saving process uses the PersistedAssemblyBuilder feature introduced in .NET 9. Aided by MetadataLoadContext, this example produces a DLL for .NET Standard 2.0.
var resolver = new PathAssemblyResolver([
// A core DLL containing System.String and other basic features:
"C:\\Program Files\\dotnet\\sdk\\9.0.300-preview.0.25177.5\\ref\\netstandard.dll",
// One way or another you'll need a reference to the matching WebAssembly.dll built against the core DLL.
"C:\\dotnet-webassembly\\WebAssembly\\bin\\Release\\netstandard2.0\\WebAssembly.dll"
]);
using var context = new MetadataLoadContext(resolver);
const string name = "HelloWorld"; // Name components should match.
var assembly = Compile.CreatePersistedAssembly(
File.OpenRead("HelloWorld.wasm"), // This is part of the "RunExisting" sample.
new(
context.CoreAssembly,
resolver.Resolve(context, new("WebAssembly")),
new(name),
$"{name}.dll"
)
{
// The type name includes the namespace.
// If not set, defaults to WebAssembly.CompiledFromWasm.
TypeName = "Converted.HelloWorld"
}
);
assembly.Save($"{name}.dll");
To use the new DLL, you directly reference it in your .csproj.
<ItemGroup>
<Reference Include="HelloWorld">
<HintPath>bin\HelloWorld.dll</HintPath>
</Reference>
</ItemGroup>
Once the DLL reference is in place, you can access it just like any other .NET library.
var helloWorld = new Converted.HelloWorld((module, field) =>
{
// Imports are defined by the original WASM and must be supplied by you.
if (module == "env" && field == "sayc")
return new FunctionImport(new Action<int>(raw => Console.Write((char)raw)));
throw new Exception($"Unknown import: {module} {field}");
});
// You can directly access anything exported by the WASM.
var result = helloWorld.main();
Other Information
Product | Versions Compatible and additional computed target framework versions. |
---|---|
.NET | net5.0 was computed. net5.0-windows was computed. net6.0 was computed. 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 was computed. 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. net9.0 is compatible. 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. |
.NET Core | netcoreapp2.0 was computed. netcoreapp2.1 was computed. netcoreapp2.2 was computed. netcoreapp3.0 was computed. netcoreapp3.1 was computed. |
.NET Standard | netstandard2.0 is compatible. netstandard2.1 was computed. |
.NET Framework | net461 was computed. net462 was computed. net463 was computed. net47 was computed. net471 was computed. net472 was computed. net48 was computed. net481 was computed. |
MonoAndroid | monoandroid was computed. |
MonoMac | monomac was computed. |
MonoTouch | monotouch was computed. |
Tizen | tizen40 was computed. tizen60 was computed. |
Xamarin.iOS | xamarinios was computed. |
Xamarin.Mac | xamarinmac was computed. |
Xamarin.TVOS | xamarintvos was computed. |
Xamarin.WatchOS | xamarinwatchos was computed. |
-
.NETStandard 2.0
- System.Reflection.Emit (>= 4.3.0)
-
net8.0
- No dependencies.
-
net9.0
- No dependencies.
NuGet packages (4)
Showing the top 4 NuGet packages that depend on WebAssembly:
Package | Downloads |
---|---|
ConcordiumNetSdk
A .NET integration library written in C# which adds support for constructing and sending various transactions, as well as querying various aspects of the Concordium blockchain and its nodes. This SDK uses version 2 of the Concordium Node gRPC API to interact with Concordium nodes and in turn the Concordium blockchain. |
|
Backlang.Backends.Wasm
A backend for backlang for the bs2k emulation system |
|
WebAssembly.FSharp
Provides an idiomatic F# WebAssembly module generation toolkit around the base WebAssembly package. |
|
Microsoft.CST.OSSGadget.Shared.CLI
OSS Gadget - Shared CLI Functionality |
GitHub repositories (1)
Showing the top 1 popular GitHub repositories that depend on WebAssembly:
Repository | Stars |
---|---|
microsoft/OSSGadget
Collection of tools for analyzing open source packages.
|
Version | Downloads | Last updated |
---|---|---|
1.3.0 | 206 | 4/20/2025 |
1.2.1 | 21,015 | 8/14/2022 |
1.2.0 | 8,552 | 5/24/2021 |
1.1.0 | 457 | 5/16/2021 |
1.0.0 | 426 | 4/24/2021 |
0.11.0 | 878 | 2/15/2021 |
0.10.2-preview | 258 | 1/31/2021 |
0.10.1-preview | 364 | 12/26/2020 |
0.10.0-preview | 342 | 10/3/2020 |
0.9.0-preview | 1,062 | 6/13/2020 |
0.8.0-preview | 1,374 | 12/8/2019 |
0.7.1-preview | 661 | 8/4/2019 |
0.7.0-preview | 427 | 7/27/2019 |
0.6.0-preview | 462 | 7/4/2019 |
0.5.0-preview | 469 | 7/1/2019 |
0.4.0-preview | 467 | 6/24/2019 |
0.3.8-preview | 510 | 5/26/2019 |
0.3.7-preview | 585 | 2/10/2019 |
0.3.6-preview | 582 | 2/3/2019 |
0.3.5-preview | 707 | 10/20/2018 |
0.3.4-preview | 795 | 8/7/2018 |
0.3.3-preview | 776 | 8/4/2018 |
0.3.2-preview | 948 | 6/3/2018 |
0.3.1-preview | 896 | 12/3/2017 |
0.3.0-preview | 893 | 8/18/2017 |
0.2.4-preview | 904 | 6/19/2017 |
0.2.3-preview | 919 | 6/12/2017 |
0.2.2-preview | 869 | 6/4/2017 |
0.2.0-preview | 926 | 5/30/2017 |
0.1.0-preview | 1,270 | 5/21/2017 |
Full support for creation and modification of WASM 1.0 files; .NET CLR JIT-based execution works well but may not support every WASM.