.NET 8 Preview 4: WASI 'Hello World'

Published on Saturday 27 May 2023

This is a simple Hello World with the new WebAssembly WASI coming in .NET 8.

This post is about .NET 8 Preview 4 and I mostly wrote the post for my own sake as a log of what I did when I get the time to pick this up again.

A word of warning: I am a noob at WebAssembly (WASM) and WASI, so some of the stuff in this post is probably superfluous, maybe even wrong. I could not yet find much information online, so I have just been trying stuff.

You can find the source code for this post here. The initial commit is the code as generated by dotnet new and I since made modifications to the README.md to correct the things I could not get to work.

Scenario for this post: Hello World

The scenario I want to try is:

  1. Build a WASI compatible .wasm file using .NET 8 Preview 4.
  2. Use Wasmtime CLI to run that file. Amongst other things the Wasmtime CLI is a standalone WebAssembly runtime.

The .NET code only needs to do something identifiable, e.g. write to the console.

What I found about WASI support in .NET

An issue in the Github repository dotnet/runtime tracking WASI support in the .NET runtime.

There is another Github repository dotnet/dotnet-wasi-sdk, but it looks like this has been abandoned because of the ongoing work in dotnet/runtime.

Steve Sanderson also has an even older Github repository SteveSandersonMS/dotnet-wasi-sdk that also looks abandoned.

Update: Found a Youtube video by Steve Sanderson where he does the same thing and explains how to get a single wasm file. He also showcases a couple of mind-blowing usage examples. Go watch that!

What I ended up having installed

My strategy for the 'Hello World' has been to install everything sounding remotely relevant, because there is little information available and I did not want to have to fight strange error messages.

See specifics on what I installed and how I did it at the end of the article.

Making the 'Hello World' program

I used a Powershell 7 prompt:

  • PS> mkdir wasiconsole-hello-world
  • PS> cd wasiconsole-hello-world
  • PS> dotnet new wasiconsole
  • PS> dotnet build
  • PS> dotnet run

Or if you want to use the Wasmtime CLI directly:

  • PS> cd .\bin\Debug\net8.0\wasi-wasm\AppBundle\
  • PS> wasmtime .\dotnet.wasm --dir . wasiconsole-hello-world

The option --dir . enables the Wasmtime CLI to read the files it needs. My guess the need for this might go away in a later preview, but time will tell.

This is a little different from what's written in the generated README.md, but even after correcting the obvious mistake in the path I could not get the instructions in the generated README.md to work, so I did this instead.

Update: After seeing the video by Steve Sanderson (mentioned above) I tried to make the build create a single WASM file using the property WasmSingleFileBundle in the .csproj file. This failed with this error message:

C:\Program Files\dotnet\packs\Microsoft.NET.Runtime.WebAssembly.Wasi.Sdk\8.0.0-preview.4.23259.5\Sdk\WasiApp.Native.targets(54,5): error : Could not find wasi-sdk. Either set $(WASI_SDK_PATH), or use workloads to get the sdk. SDK is required for building native files.

I found this issue in the dotnet/runtime repository on Github.

  • Downloaded the latest release of WebAssembly WASI-SDK. I am on Windows so I used wasi-sdk-20.0.m-mingw.tar.gz
  • Unpacked it. I used 7-Zip.
  • Set environment variable WASI_SDK_PATH to point to the root folder of the unpacked content, in my case, E:\WASI-SDK\wasi-sdk-20.0+m
  • PS> dotnet build -> Got a new wasiconsole-hello-world.wasm in the AppBundle folder.
  • Simpler to run: PS> wasmtime .\wasiconsole-hello-world.wasm --dir .

I made the WasmSingleFileBundle conditional so that dotnet build + dotnet run still work out of the box, but with no single file WASM.

If you are using the code in my repository and want single file wasm then you'll have to:

  1. Get and "install" the WebAssembly WASI SDK
  2. Set the environment variable WASI_SDK_PATH

Summary and observations

  • Using the wasiconsole template I got a simple program.
  • dotnet could build it into something that could run on the Wasmtime CLI.

There are a couple of observations:

  1. It is not one self-contained .wasm file out of the box. Rather a dotnet.wasm file and a bunch of dlls in a folder. My guess is that dotnet.wasm is the same as used in Blazor WebAssembly.
  2. It was still surprisingly easy to get up and running, especially if you can live without single file WASM.
  3. If you want single file there still is a minor issue.
  4. There is information to be found when you get stuck.

Going forward

I'll either update this post as I find out more or make follow-up posts.

I'll also try to keep this post updated as more .NET 8 previews are released.

My longer term goal is to play with WebAssembly interoperability between different languages outside of the browser.

Details: Installed software

Again, mostly so I know what I did. Nothing fancy here.

.NET SDK

I already had .NET 8 Preview 4 installed.

Visual Studio

I already had Visual Studio Community 2022 Preview 17.7.0 Preview 1 with these relevant "individual components" installed:

  • .NET 6.0 WebAssembly Build Tools
  • .NET 7.0 WebAssembly Build Tools
  • .NET WebAssembly Build Tools

I ended up using the dotnet CLI, but I have no idea if the Visual Studio components contributed in any way.

.NET workloads

I ended up having these .NET workloads installed:

  • wasi-experimental
  • wasm-experimental
  • wasm-tools-net7
  • wasm-tools-net6 (came from Visual Studio)
  • wasm-tools (came from Visual Studio)

I had previously not used workloads and could not find much online except the dotnet CLI reference, so these commands helped me:

NB: The dotnet workload commands are influenced by global.json files.

Remember to check that you are targeting .NET 8 with dotnet --info.

  • dotnet workload list Lists the workloads you have installed for the SDK currently in scope.
  • dotnet workload search Finds all available workloads, but there are not that many yet, so that is OK.
  • dotnet workload install <workload id>

Wasmtime CLI

Installed Wasmtime CLI 9.0.2

I used the MSI because 9.0.2 is not yet available thru winget.

Minor nuisance with Wasmtime CLI on Windows

When upgrading there are a couple of things to note:

  • Upgrading does not correctly uninstall older versions which still show up in "Control Panel -> Programs and Features" and if you are using Winget it will keep insisting that there is an upgrade available.
  • If you after upgrading to latest uninstall any older versions thru "Control Panel" then you need to either:
    • Add the wasmtime CLI to your path again
    • Winget: Remove and re-install to get the path set-up properly
    • In "Control Panel" choose "Repair" to fix the path

So if you do not want older versions lying around then the best way to ensure that everything works:

  1. Uninstall the wasmtime CLI you currently have
  2. Install the new version you want