Run C# in my browser with WebAssembly?

I read an article on Blazor, which stated how Microsoft teams were experimenting with running C# code in web browsers, not just IE. Naturally, that made me curious about how this would work. How can I run C# code, which requires some form of the .Net Runtime in Chrome, or Firefox on my mac? Does it require an install of a .Net Framework on my machine? Wait that would not be very web friendly. So let’s dig in…

What is WebAssembly?

WebAssembly (abbreviated Wasm) is a binary instruction format for a stack-based virtual machine. Wasm is designed as a portable target for compilation of high-level languages like C/C++/Rust, enabling deployment on the web for client and server applications.

https://webassembly.org/

Ok so I can compile down C#, Go, C++, C, Rust, etc. into a low-level binary format, an instruction set that my browser understands. This makes my browser essentially a VM that can run my language of choices code. Compiling to WebAssembly also lets us run said languages code at near-native speed and has has been designed to interoperate with JavaScript.

We can think of its use for completely new UI/SPA frameworks based on popular programming languages that are not JavaScript, or as a canvas within a larger JavaScript-based web application or an alternative browser runtime options that might offer better speed or code reuse for your use case.

Are people using it?

A few examples of success and usage are the AutoCAD team which found this technology useful in reusing its vast C++ codebase when looking for a maintainable and scalable browser solution. Unity is another example who have made the switch and you can also read about eBay’s journey to adopting WebAssembly for its barcode scanner feature here. An experimental version of Google Earth was released allowing it to run in additional browsers like Edge, FF – where in the past it was only available in Chrome.

How does WebAssembly work? A C/C++ example

We will start with the example in the Developer Guide which will explain how we can compile a simple C program to Wasm – hello world of course. It asks us to download the Emscripten SDK which provides us relevant tools/packages we will need when using Emscripten to compile our C program. Emscripten is built using LVVM allowing compilation to WebAssembly and asm.js. For C# it needs to first be in a bitcode LLVM format and make use of an LLVM WebAssembly backend. It’s compiling to binary and with an option for more readable bytecode Intermediate Representation (IR) as JavaScript or Wasm binaries. IR is Intermediate language representation which is ready to be compiled further into executable code. LVVM is a compiler infrastructure project aimed at making compiler development easier, more reusable and modular by the means of frameworks, libraries, and built-in tools.

If you are following the example, Developer Guide, we first download the toolchain. *I ran this on a Mac OS

$ git clone https://github.com/emscripten-core/emsdk.git
$ cd emsdk
$ ./emsdk install latest
$ ./emsdk activate latest

Then, to enter an Emscripten compiler environment we run,

$ source ./emsdk_env.sh --build=Release

Now, to create and compile our sample program, from C to Wasm,

$ mkdir hello
$ cd hello
$ cat << EOF > hello.c
#include <stdio.h>
int main(int argc, char ** argv) {
  printf("Hello, world!\n");
}
EOF
$ emcc hello.c -s WASM=1 -o hello.html

And finally to lets run the built in server…

$ emrun --no_browser --port 8080 .

Now we can visit http://localhost:8080/ and see the following files:

  • hello.c – our c code we created above
  • hello.html – HTML file generated by Emscrepten compilation command “emcc hello.c -s WASM=1 -o hello.html”. This file contains mostly template style/markup and includes our hello.js.
  • hello.js – Support/helper file to run and execute our Wasm code
  • hello.wasm – Wasm compiled code – binary

For more of a shell like experience, run…

node hello.js

What browsers support WebAssembly

WebAssembly was announced in 2015, in November 2017 Mozilla declared support in all major browsers and as of June 2018, 85.57% of installed browsers had support. And for older browsers, there is an asm.js polyfill. Things began with C, C++ and now many languages have Wasm compilation targets including Rust & .Net. – See Wikipedia support page for more detail.

WebAssembly was built with some specific design goals in mind..

  • Safe – ensure its sandboxed, enforces same-origin and other browser policies
  • Speed – to be able to execute at near-native performance benchmarks
  • Portable – Hardware, language, and platform independent – support compilation to all major processor architectures accept all languages and run in a browser
  • Work well with existing Web technologies

And a few example use Cases..

  • Image / video editing.
  • Games
  • Image Recognition
  • Live video augmentation
  • Scientific visualization and simulation
  • CAD

What is Blazor?

Blazor lets you build interactive web UIs using C# instead of JavaScript. Blazor apps are composed of reusable web UI components implemented using C#, HTML, and CSS. Both client and server code is written in C#, allowing you to share code and libraries. – MSFT

Blazor gives us the ability to run C# applications directly in our browser UI thread, its fully component based and allows us to write custom or import libraries like Telerik or DevExpress. We can write cshtml/razor files with markup and C# code, leverage the .Net language features and ecosystem, run code both client and server side and communicate using SignalR, and share code like data models or validation logic. We get the vast .Net framework for our client application. This makes tasks like generating an Excel doc much simpler as there is no need for a roundtrip to the server to generate and send the binary and also less integration work for teams. Other features supported are routing, layouts, JS interop, Forms, DI, Server-side rendering.

What Microsoft did was compile Mono to Wasm. Mono is the preferred .Net “portable” runtime that Microsoft supports – so the Mono Wasm module is imported via JavaScript and runs in the Browser UI Thread and no .Net framework install dependencies.

This is interesting because it solves the problem of garbage collection for a non manual memory management language. It looks as though GC might be on the roadmap for WebAssembly in the future.

Blazor also follows suit with other JS based SPA frameworks like React and will render a diff of the changes based on in-memory models of the rendering/DOM. I did not find details on the algorithms used so I’ll just comment that it could be conceptually similar to how React handles the tree diffing. See this video for additional detail.

Let’s look at how Blazor works…

  • We still need a place to serve our HTML, assets, and Wasm files (this could be any web server as depending on the hosting model we don’t have a .Net dependency on the server).
  • We will have an HTML page that contains our regular dependencies for CSS, JS, images, etc.
  • We also have a webassembly.js file that is responsible for loading Mono.wasm and other Wasm modules.
  • From here we can load regular .Net dependencies, dll files, and eventually precompiled other Wasm files. At the time of this recording the mono.wasm binary was around 2mb. So the use cases for the everyday web might be limited based on your app download size requirements until they are able to optimize the Mono framework size.

They do have thin client modes that host the Blazor on the server which means the client has no Wasm files but rather communicates to the server via a SignalR tunnel that the framework exposes, but that is really a whole different thing altogether – its not running C# in the browser anymore.

And to close,

You probably will not see everyone drop JavaScript UI/SPA based frameworks in favor of their favorite programming language compiled to WebAssembly, but it will be interesting to see the use cases as they develop and how Blazor or similar frameworks evolve.

There is great potential for opening up the toolset and languages that can be the runtime for browser-based applications and also new design decisions with the client/server hosting models that Razor has put forth.

Links:

Leave a Reply

Leave a Reply

Your email address will not be published. Required fields are marked *