Building #dotnet code to target WASM in the browser

Overview

WASM Running .NET in a Browser

This solution shows you can compile .NET to target a WASM app bundle that can be used independently of a dotnet application.

Getting Started

You'll need the latest .NET 7 SDK (RC2+), and the workloads of wasm-tools and wasm-experimental.

dotnet workload install wasm-tools
dotnet workload install wasm-experimental

This uses the dotnet new wasmbrowser template.

Run

To run this solution, run the following commands.

dotnet tool restore && dotnet r start

Then open your browser to https://localhost:8080 and be sure to open up the dev tools to see the console output.

console output

Points of Interest

  • Program.cs : Where the .NET code is written that runs in the browser
  • Project: Notice there are no special dependencies, this is part of the SDK and uses the wasm-tools and wasm-experimental workloads. Also notice the <RuntimeIdentifier>browser-wasm</RuntimeIdentifier> element.
  • AppBundle (bin/$(Configuration)/net7.0/browser-wasm/AppBundle): This is the built application along with the static files.
  • Main - Notice how the wasm file is loaded

C#

There are a few things to note in this file worth paying attention to.

  1. This is a top-level statement file, and the Main method is implicit. The Console.WriteLine method calls are the app.
  2. The MyClass implementation uses the JsExport and JsImport attributes. This is our connection to the WASM runtime.
using System;
using System.Runtime.InteropServices.JavaScript;

// ReSharper disable MemberCanBePrivate.Global

Console.WriteLine("Hello, Browser!");
Console.WriteLine(string.Join(" ", args));

public partial class MyClass
{
    [JSExport]
    internal static string Greeting()
    {
        // language=html
        var text = 
        $"""
        <div>
            <h1>Hello, World! Greetings from WASM!</h1>
            <p>Listening at {GetHRef()}</p>
        </div>
        """;
        Console.WriteLine(text);
        return text;
    }

    [JSImport("window.location.href", "main.js")]
    internal static partial string GetHRef();
}

JavaScript

Important notes about this file.

  1. The import of the dotnet.js file pulls in the runtime and helper methods, that allow you to get the exports of the .NET module and set the necessary imports.
  2. The config object is more about the application interface/manifest than what you'd traditionally think of as "configuration"
  3. Accessing C# types is by namespace, class, and method tokens. See how it matches the partial type definition in C#.
  4. The use of runMainAndExit allows you to pass in arguments like you would with any console application.
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

import { dotnet } from './dotnet.js'

const is_browser = typeof window != "undefined";
if (!is_browser) throw new Error(`Expected to be running in a browser`);

const { setModuleImports, getAssemblyExports, getConfig, runMainAndExit } = await dotnet
    .withDiagnosticTracing(false)
    .withApplicationArgumentsFromQuery()
    .create();

setModuleImports("main.js", {
    window: {
        location: {
            href: () => globalThis.window.location.href
        }
    }
});

const config = getConfig();
const exports = await getAssemblyExports(config.mainAssemblyName);
const html = exports.MyClass.Greeting();
console.log(html);


document.getElementById("out").innerHTML = `${html}`;
await runMainAndExit(config.mainAssemblyName, ["dotnet", "is", "great!"]);

Outstanding Questions

  • How do you deploy something like this, especially if you have multiple WASM files?
  • Do you need all the files in the AppBundle?

Thanks

Thanks to Pavel Ε avara for writing this blog post (https://devblogs.microsoft.com/dotnet/use-net-7-from-any-javascript-app-in-net-7/).

You might also like...

Simple Jai to WASM Proof-of-Concept

Simple Jai to WASM Proof-of-Concept Jai does not officially support WebAssembly compilation target. BUT! It allows you to dump LLVM IR via the llvm_op

Dec 14, 2022

High-order Virtual Machine (HVM) wrapper on JavaScript, via WASM

HVM on JavaScript HVM is now available as a JavaScript library! Installing npm i --save hvm-js Examples Evaluating a term to normal form import hvm fr

Nov 24, 2022

A fast, feature rich and simple framework for building dynamic browser applications.

A fast, feature rich and simple framework for building dynamic browser applications.

hyperdom A simple, fast, feature rich framework for building dynamic browser applications. Hyperdom supports a simple event-update-render cycle, promi

Nov 11, 2022

A VS Code extension to practice and improve your typing speed right inside your code editor. Practice with simple words or code snippets.

A VS Code extension to practice and improve your typing speed right inside your code editor. Practice with simple words or code snippets.

Warm Up πŸ”₯ πŸ‘¨β€πŸ’» A VS Code extension to practice and improve your typing speed right inside your code editor. Practice with simple words or code snipp

Dec 12, 2022

🎬 Starter code for building an xNFT

xnft-quickstart Quickstart repo for building your own xNFT. Developing Once you've installed Backpack, get started building your xNFT with these steps

Dec 25, 2022

Remix enables you to build fantastic user experiences for the web and feel happy with the code that got you there. In this workshop, we'll look at some more advanced use cases when building Remix applications.

πŸ’Ώ Advanced Remix Workshop Remix enables you to build fantastic user experiences for the web and feel happy with the code that got you there. In this

Dec 9, 2022

VS Code extension for building with the Ubie Design System.

Ubie Design Tokens for VS Code Installation πŸ‘‰ Install via the Visual Studio Code Marketplace Features Autocomplete Autocomplete suggestions for the U

Sep 12, 2022

Snippets4Dummies is an easy to use Visual Code Extension which is used for building beautiful layouts as fast as your crush rejects you!

Why Snippets4Dummies? Snippets4Dummies is an easy to use Visual Code Extension which is used for building beautiful layouts as fast as your crush reje

Oct 11, 2022

A lightweight extension to automatically detect and provide verbose warnings for embedded iframe elements in order to protect against Browser-In-The-Browser (BITB) attacks.

A lightweight extension to automatically detect and provide verbose warnings for embedded iframe elements in order to protect against Browser-In-The-Browser (BITB) attacks.

Enhanced iFrame Protection - Browser Extension Enhanced iFrame Protection (EIP) is a lightweight extension to automatically detect and provide verbose

Dec 24, 2022
Owner
Khalid Abuhakmeh
Loves @NicoleAbuhakmeh. πŸš€πŸ§  πŸ₯‘@JetBrains dev advocate #Photoshop Whisperer. #OSS supporter. @dotnet developer. @dotnet-foundation member. He/Him
Khalid Abuhakmeh
Init a target by promise only once.

once-init ?? Let Promise Function Executed Only Once. The Promise will be executed when the attribute target is called for the first time, and the Pro

Xmo 65 Dec 26, 2022
Based on Google Chrome recorder, implement UI interface capture and notify the result to the target mailbox

chrome-recoder-crawler README-CN Modify the .js file exported by Google Chrome recorder. By default, the innerText property of the node operated in th

wudu 4 Oct 18, 2022
Calculates dependencies for a Go build-target and submits the list to the Dependency Submission API

Go Dependency Submission This GitHub Action calculates dependencies for a Go build-target (a Go file with a main function) and submits the list to the

GitHub Actions 33 Dec 7, 2022
CLI tool to update caniuse-lite to refresh target browsers from Browserslist config

Update Browserslist DB CLI tool to update caniuse-lite with browsers DB from Browserslist config. Some queries like last 2 version or >1% depends on a

Browserslist 31 Dec 30, 2022
Invadium runs exploit playbooks against vulnerable target applications in an intuitive, reproducible, and well-defined manner.

Invadium Invadium runs exploits against one or more target applications in an intuitive, reproducable, and well-defined manner. It focuses on bridging

Dynatrace Open Source 10 Nov 6, 2022
EasyPen is a GUI program which helps pentesters do target discovery, vulnerability scan and exploitation

EasyPen Alpha 1.0.5 Do not use EasyPen for illegal purposes, this tool is for research only ζŸ₯ηœ‹δΈ­ζ–‡ EasyPen is a GUI program which helps pentesters do ta

null 486 Dec 25, 2022
Drawing Newton's fractal using pure js, rust-wasm, SIMDs, threads and GPU

Newton's fractal Runtime Newton's fractal renderer. >>Click<< to open in your browser Inspired by 3blue1brown's video about Newton's fractal. Drawing

Aleksei 86 Nov 17, 2022
A WASM shell parser and formatter with bash support, based on mvdan/sh

sh-syntax A WASM shell parser and formatter with bash support, based on mvdan/sh TOC Usage Install API Changelog License Usage Install # yarn yarn add

RxTS 7 Jan 1, 2023
Remix sandbox repo for Rust compiled to WASM and to native N-API modules

Rust <-> Remix Sandbox Now with both native Rust and WASM versions! If you want to combine the Web Fundamentals & Modern UX of Remix together with the

Ben Wishovich 26 Dec 30, 2022
A Remix stack setup to run on Deno with support for Rust WASM modules!

Remix + Deno + Rust -> Webassembly - The Air Metal Stack Welcome to the Air Metal Stack for Remix! ?? + ?? This stack is a good choice if you want to

Ben Wishovich 60 Jan 5, 2023