How to run C# code in a browser.

Diyaz Yakubov
Dec 11, 2019 · 7 min read

Nowadays, there are a lot of talks about WebAssembly and how it would penetrate the front-end world. In fact, it has not yet. There are tones of articles about web assembly and how it works. I want to show you a use-case of running C# code in a browser.

Short description from the MDN: WebAssembly is a new type of code that can be run in modern web browsers — it is a low-level assembly-like language with a compact binary format that runs with near-native performance and provides languages such as C/C++ and Rust with a compilation target so that they can run on the web. It is also designed to run alongside JavaScript, allowing both to work together.

There are several ways of how to do it. I would like to mention three of them.

  • The first one is to use a Blazor Framework. It hides the complexity and gives a solid tool for building SPA applications (there is a very good article about WebAssembly and Blazor).
  • The second way is to use a mono-wasm compiler and compile your code to a WASM file. It does Ahead of Time compilation and it works very well (there is an article about MONO and WASM and a good explanation of how mono compiles C# into wasm).
  • The third scenario is to run .Net libraries in a browser, as a Blazor framework does, but without Blazor. As was mentioned in the article above, there is a very good explanation of how Blazor works. Furthermore, it tells that for running .net assemblies we need a mono-compiled version of the .NET Runtime which was compiled to a WASM module to execute .NET Standard modules. Is it overhead? Of course, there are some lacks. To be honest, I don’t know. We will see ;).

Another question is: “Do we really need it?”. The 3rd scenario might be useful for someone who wants to upgrade a front-end app and play with it. Nevertheless, I recommend using AoT compiled wasm file with React, Angular or Vue applications. Blazor framework can be even used if a project has just started.

Here is an example of how to use this approach. There is a react based front-end application, which is hosted by NodeJs (of course, there are no talks about Blazor). Users can load any .Net standard modules(library assemblies) and retrieve metadata from them or even call some methods and use results for configuring higher modules. Assemblies represent small modules with some logic and certain responsibility (Ex.: calculation of material strength). There are some dynamic behaviors and reflections that’s why developers can’t use AOT compilation for it. Pass and retrieve assemblies, and relative data through Http is a heavy payload. Assemblies shouldn’t be saved somewhere, they should be extracted and executed, that’s it.


Before going forward I want to define a task: Recreate the example case mentioned above.

Let’s create a web application:

dotnet new web -n playDllAndWasm

Next, create the “wwwroot” folder within index.html file, and modify the Startup.cs file as shown below.

Startup.cs

Furthermore, We need to add precompiled WASM .Net runtime (mono-wasm) and the mono script (mono.js) to run it. You can get them from the mono-wasm GitHub page. There is also a link to Binary releases. Get a packager and use it to generate the whole bunch of libraries for running .Net module. I have done all these, but here is my suggestion: if you want to play around and do not kill yourself, you can easily clone this demo project repo.

Note: If you want to play with mono-wasm AOT compilation you have to deal with packager. There are might be some changes, as it is under development.

After that, let’s create a “managed” folder which will contain all .Net assemblies. Put there the first and the most important assembly — “mscorlib.dll”. We need it to run assemblies because it is a Multilanguage Standard Common Object Runtime Library. Go forward and add an index.html file to the “wwwroot” folder and modify it as it is shown below.

index.html

What does the code above? The first script tag creates an empty object “Module” and declares only one method where we can place calls to the MONO instance. Through the MONO instance, developers can configure and act with the .Net world. The second script tag loads mono.js file that contains commands which load and run mono.wasm. In addition, it triggers “onRuntimeInitialized” when everything is initialized (for ex.: MONO instance)and prepared to work. Run and see what it does.

The first running.

It shows only “Hello world!”. However, if you open a dev console you’ll see some logs from the mono. It tells that the runtime environment is ready which consequently shows that we can continue the development.

Next, we need to create our first, but not last, .Net standard module and run it. Let’s execute the next command:

dotnet new classlib -n SomeComputing

There will be only one class with the code below:

TestComputing.cs

Index.html should be modified. Now it needs some extra libraries to be able to point what to call, and of course our “SomeComputing” library. Check out the changes:

Part of index.html

A function above initializes .Net WebAssembly bindings and points to a method which should be called. If it runs, the dev console will show you the result of method execution.

The result of calling the Execute method from C# TestCompution class.

A common way of calling some .Net functionality was implemented above. It could be done by mono-wasm AoT compilation and got only one WASM file, without any .Net assembly dependencies. For continuing the development, the front-end needs some extra libraries. Create several new netstandard projects:

dotnet new classlib -n CommonLibrary
dotnet new classlib -n ComputeFibonacci
dotnet new classlib -n ComputeDateTimes

A “CommonLibrary” project has only one .cs file with an interface.

IExecutable interface.

The “IExecutable” interface is an assembly’s entry point. The “Execute” method is a common declaration of methods that will be executed on a front-end side. “ComputeFibonacci” and “ComputeDateTimes” projects will depend on the “CommonLibrary” project. Next, add a new class to SomeComputing project that will load assemblies and run them.

Computing.cs

WebAssembly can’t pass any complex data structures. In addition, we can not pass assemblies or bytes. Javascript itself writes bytes in an allocated buffer and sends a pointer to .Net module. .Net module, in its turn, will take care of reading this buffer, converting bytes to some structure (in our case it’s an assembly) and process certain job.

Part of index.html

A response can be written in some buffer and retrieved as a pointer. After that, this buffer can be read in JavaScript directly. Nevertheless, I’m a lazy person and I think you got the main idea of passing and retrieving. That’s why the “executeMethod” returns a string value. Simple and crutch ;).

ComputeFibonacci and ComputeDateTimes contain only one class that implements the“IExecutable” interface.

DateTimeComputing.cs (left side) and FibonacciComputing.cs (right side).

These two projects should be built and their assemblies should be taken for loading and executing. Ohh right, I think it’s time for a demo.

Demo!

This technology is pretty young. It has many issues but it also shows potential. It is a fast, safe, light, portable and open standard. In this article, I wanted to show one of the “use cases” of this technology. This article is more about encouraging. In my opinion, we will see some new libraries or even frameworks which will be based on WASM. There is also a good news about the fourth language for the Web. So, don’t waste time, jump on a train :).

Thanks Niki for awesome illustration.

Thanks to sreejesh Nair and Nikita Gavrilenko

Diyaz Yakubov

Written by

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade