Running .NET 7 apps on WASI on arm64 Mac

WASI stands for WebAssembly System Interface, and allows to run WebAssembly code independently of the browsers, as it provides access to operating system features such as file system access or networking. It is highly experimental, but at the same time a tremendously interesting project, and one that has the potential of contributing to a massive paradigm-shift in the industry, making WebAssembly truly ubiquitous.

The great mad scientist of web things at Microsoft, Steve Sanderson, recently published the first version of an experiemental WASI SDK for .NET, which allows building .NET 7 and ASP.NET Core applications into standalone WASI compliant apps, and running them from WASI hosts. Steve's repo provides the easy to follow steps to get going on Windows and Linux, in this post I will walk through some additional hoops that one may need to jump on arm64 Macs.

Getting started and building

The prerequisite to get going is to have a .NET 7 SDK installed. As we will discover later, the latest official preview 7.0.100-preview.2 will not be enough, but for now we can use it to bootstrap the project – in this case a regular bare-bones ASP.NET Core web application

Once the project is created, the following package references need to be added to bring in the experimental Wasi.Sdk and the corresponding ASP.NET Core server implementation that Steve built:

In addition to that, an extra property under the main PropertyGroup is needed, one that will correspond to the port used by your application in launchSettings.json:

Since our app will need to listen on networking interface from inside of a WASI host, an additional change is needed in the generated code, namely UseWasiConnectionListener() needs to be added to the default WebApplication builder:

At this point the application will build correctly, but it will not run yet, since we have no WASI host at our disposal yet.

Running the application

In order to run this WASI-based application, we need a WASI runtime. An excellent lightweight runtime is wasmtime, and it happens to be the one used by this experimental Wasi.Sdk by default – it simply expects it to be available on the PATH. Unfortunately, there is no official distribution of wasmtime for arm64 MacOS (yet). If you attempt to execute the regular wasmtime installation command, you will see the following:

Thankfully, this apparent significant problem is relatively easy to solve. While wasmtime is not distributed for arm64 MacOS, it can actually build for that target without any problems. We will need Rust to be installed on our machine first, and in case you do not, this can be done easily with Rustup

With that available, we can clone the official wasmtime repository and simply run the build, specifying aarch64-apple-darwin as the build target.

This should take less than a minute, and will build wasmtime executable into the target/aarch64-apple-darwin/release folder. We can easily verify that we built it successfully, by simply executing it.

At this point, we can go back to our initial ASP.NET Core project and set the WasiRunner property to the path to wasmtime we just built.

Alternatively, you can simply add the path to the wasmtime executable to your PATH, which will be picked up by the SDK automatically, without any additional changes to the project file.

Next, when we run this project, even though wasmtime is reachable now, we will still get the following error, coming from Quic implementation (or rather it being missing) for arm64 Mac:

Steve recently made a PR fixing this exception, though it has not been released as the official preview release yet – the latest SDK version is 7.0.100-preview.2, and the change will be part of 7.0.100-preview.3. A related PR on the runtime side can be found here. All things considered, since it is already fixed, just not “officially available”, the best idea is to install a daily build of the .NET SDK for arm64 MacOS from the daily feed; the stable link to the latest one is this. For example, at the time of writing the current version available there is 7.0.100-preview.4.22179.13.

Once this SDK is installed, we should be able to run the application:

All that is left, is to navigate to that http://localhost:5100/ URL in the browser, where we should now see our hello world. In a quite spectacular fashion, we now have an ASP.NET Core application, running as WebAssembly application in a WASI runtime, and being reachable from the browser.