The first .NET CDK for the Internet Computer. Two stories under one roof: a
shipped, working NativeAOT-LLVM path that compiles your C# directly into
canister wasm today, and an in-progress runtime path that re-hosts
Microsoft's pre-built dotnet.native.wasm (the Blazor WebAssembly engine)
inside an ICP canister to give you the full BCL plus reflection. Pick AOT for
small, fast, simple canisters; pick the runtime path when you need ASP.NET
Core, full reflection, or Reflection.Emit.
Alpha. APIs and on-disk layout will change. Pin a commit; expect breaking changes between releases.
| Package / sample | Path | Status |
|---|---|---|
Wasp.IcCdk |
aot/Wasp.IcCdk/ |
shipped (alpha) |
Wasp.IcCdk.SourceGenerator |
aot/Wasp.IcCdk.SourceGenerator/ |
shipped (alpha) |
Wasp.Http |
aot/Wasp.Http/ |
shipped (alpha) |
Wasp.Outcalls |
aot/Wasp.Outcalls/ |
shipped (alpha) |
Wasp.WebSockets |
aot/Wasp.WebSockets/ |
shipped (alpha) |
samples/HelloWorld |
aot/samples/HelloWorld/ |
shipped |
samples/Counter |
aot/samples/Counter/ |
shipped |
samples/HelloWeb |
aot/samples/HelloWeb/ |
shipped |
samples/HelloFetch |
aot/samples/HelloFetch/ |
shipped |
samples/HelloChat |
aot/samples/HelloChat/ |
shipped |
samples/BlazorChat |
aot/samples/BlazorChat/ |
shipped |
runtime/wasp_canister |
runtime/wasp_canister/ |
Phase A — WIP |
runtime/WaspHost |
runtime/wasp_dotnet_app/ |
Phase B — planned |
Wasp.Runtime.AspNetCore |
runtime/ (TBD) |
Phase C — planned |
shared/tools/wasi-stub |
shared/tools/wasi-stub/ |
shipped |
shared/tools/icp-publish |
shared/tools/icp-publish/ |
shipped |
Prerequisites: Docker, dfx,
wasm-tools, and the
wasp-dotnet-build Docker image (see aot/docker/Dockerfile.build).
git clone https://github.com/miadey/wasp-dotnet.git
cd wasp-dotnet/aot
# build the Docker image once
docker build -t wasp-dotnet-build:latest -f docker/Dockerfile.build .
# build the wasi-stub helper
(cd ../shared/tools/wasi-stub && cargo build --release)
# bring up a local replica and deploy HelloWorld
dfx start --background --clean
dfx canister create hello
./samples/HelloWorld/build-and-deploy.sh
# call the canister
dfx canister call hello helloYou should see ("Hello from C# compiled to wasm by .NET 10").
┌──────────────────────────┐ ┌───────────────────────────┐ ┌─────────────────────┐
│ inputs │ │ build pipeline │ │ canister │
├──────────────────────────┤ ├───────────────────────────┤ ├─────────────────────┤
│ │ │ │ │ │
│ AOT story │ │ dotnet publish │ │ │
│ ─ Program.cs │───▶│ /p:IlcLlvmTarget= │───▶│ HelloWorld │
│ ─ Wasp.IcCdk │ │ wasm32-wasi │ │ .canister.wasm │
│ │ │ │ │ │
│ │ │ icp-publish.sh │ │ ┌──────────────┐ │
│ │ │ (rename exports) │ │ │ ic0 imports │ │
│ │ │ │ │ └──────────────┘ │
│ │ │ wasi-stub │ │ │
│ │ │ (no-op WASI) │ │ │
│ │ │ │ │ │
│ │ │ dfx canister install │ │ │
│ │ │ │ │ │
├──────────────────────────┤ ├───────────────────────────┤ ├─────────────────────┤
│ │ │ │ │ │
│ runtime story (WIP) │ │ cargo build │ │ │
│ ─ WaspHost.dll │ │ wasp_canister.wasm │ │ merged.canister │
│ ─ MS dotnet.native.wasm │───▶│ │───▶│ .wasm │
│ ─ wasp_canister (Rust) │ │ wasm-merge │ │ │
│ ─ corelib + refpack │ │ ─ resolve dotnet's │ │ ┌──────────────┐ │
│ │ │ env+wasi imports │ │ │ Mono engine │ │
│ │ │ │ │ ├──────────────┤ │
│ │ │ icp-publish + wasi-stub │ │ │ Rust shim │ │
│ │ │ │ │ ├──────────────┤ │
│ │ │ upload corelib + dlls │ │ │ ic0 imports │ │
│ │ │ to stable memory │ │ └──────────────┘ │
└──────────────────────────┘ └───────────────────────────┘ └─────────────────────┘
| Concern | aot/ |
runtime/ |
|---|---|---|
| Status | shipped, alpha | Phase A in progress |
| Canister wasm size | small (~1–3 MB per canister) | larger (~6–8 MB shared engine + uploaded dlls) |
| Cold start | fast | slower (engine init + assembly load) |
| Hot-path instructions / call | low | higher (interp; jiterpreter disabled) |
| Reflection (read-only) | very limited (trim-safe only) | full |
Reflection.Emit / dynamic IL |
not supported | full |
| Full BCL | partial (NativeAOT trimmed) | full |
| Managed exceptions | yes | v0.1: ban / trap (Emscripten C++ EH stubbed) |
| ASP.NET Core minimal API | not realistic | Phase C target |
| EF Core / dynamic ORMs | no (relies on Reflection.Emit) |
yes (Phase C onward) |
Crypto via System.Security.* |
mostly PlatformNotSupported |
works (full BCL) |
| Best fit | tight, performance-sensitive logic | porting existing .NET code, dynamic frameworks |
- No
Reflection.Emit. NativeAOT explicitly forbids it. Frameworks that rely on runtime IL generation (EF Core, Newtonsoft.Json's reflection path, many DI containers) will not work. - No full BCL. Trimming is aggressive; many APIs link out. Source-gen
alternatives exist for JSON (
System.Text.Jsonwith the source generator) and similar. System.Security.Cryptography.SHA256.HashData()isPlatformNotSupportedunder wasi-wasm.Wasp.IcCdkships a hand-rolled SHA-256 to work around this. The same applies to most ofSystem.Security.Cryptography.- No threading. The IC canister model is single-threaded; user code must be too.
- macOS arm64 hosts cannot build directly. NativeAOT-LLVM has no Mac
arm64 host package yet, so all wasm builds run inside the
wasp-dotnet-buildLinux x64 Docker image. Linux x64 hosts can build natively (seeaot/docker/Dockerfile.buildfor the toolchain set). - C++ exception ABI / Emscripten SJLJ is stubbed; managed code that throws will trap the canister. Catch at boundaries you control.
| Sample | Role |
|---|---|
aot/samples/HelloWorld |
Smallest possible canister: one query method, no state. |
aot/samples/Counter |
[CanisterQuery] / [CanisterUpdate] + StableCell<ulong>. |
aot/samples/HelloWeb |
http_request handler — serves HTML over the IC HTTP gateway. |
aot/samples/HelloFetch |
Outbound HTTPS via Wasp.Outcalls — IC HTTPS outcalls from C#. |
aot/samples/HelloChat |
Wasp.WebSockets server — IC-WebSocket protocol implementation. |
aot/samples/BlazorChat |
Blazor WebAssembly front-end talking to HelloChat. Browser side. |
BlazorChat is also the source of the pre-built dotnet.native.wasm the
runtime story re-hosts.
Tracked on GitHub.
- Issues
- Milestones
- P0: Bootstrap — repo, docs, CI for the AOT story
- Phase A: Hello-world via wasm-merge — Rust shim +
wasm-mergespike - Phase B: Friendly C# CDK — same
[CanisterQuery]ergonomics, runtime-side - Phase C: ASP.NET Core integration —
IcServer : IServer, asyncify chunking - Phase D: Polish + mainnet — perf table, NuGet 0.1.0-preview, mainnet IDs
wasp-dotnet/
aot/ # shipped CDK + samples (NativeAOT-LLVM)
runtime/ # in-progress runtime path (wasm-merge dotnet.native.wasm)
shared/tools/ # wasi-stub, icp-publish — used by both stories
docs/
.github/workflows/
MIT — copyright 2026 miadey.
Standing on the shoulders of:
dotnet/runtime— .NET 10, NativeAOT-LLVM, and Mono's WASM builddfinity/sdk—dfx, the Internet Computer SDKomnia-network/ic-websocket-cdk-rs— the IC-WebSocket protocol thatWasp.WebSocketsportsbytecodealliance/wasm-tools— wasm parsing, printing, component toolingWebAssembly/binaryen—wasm-merge, the linker that makes the runtime story possiblewalrus— wasm rewriter behind ourwasi-stubtool