Skip to main content
October 14, 2021

Master Blazor WebAssembly on .Net6

Did you know that it is possible to create “vanilla” WebAssembly projects in .Net6? Yes, it is possible! Although it is not officially supported, the new Blazor WebAssembly SDK is flexible enough to allow you to build pure wasm projects.

This is extremely useful in many scenarios where you just want to build a web client application but leverage all the power of WebAssembly for high-demanding algorithms using .Net. Here at the Plain Concepts Research Team, we have developed a set of samples that illustrates multiple “hidden” functionalities that you can do with WebAssembly on .Net6, to cover the most common use cases for high-performance applications. We can even use the debugger in Visual Studio 2022!

Moreover, we added some missing functionality to easily interact with Javascript, to have the possibility to use the Virtual File System (calling System.File in .Net), and Brotli/GZip compression for production environments. Keep reading to master Web Assembly on .Net6.

What is Blazor WebAssembly?

Blazor is a framework developed by Microsoft designed to bring C# to the browser, in addition to allowing the creation of SPA applications. It is similar to other Javascript frameworks such as Angular or React, but with .Net code. To work, it uses WebAssembly to compile the .Net code and generate smooth pages that do not require reloading all the content. As with any other client web application, this means that no external server is needed to run, so you save money.

In other words, WebAssembly is a technology that allows binary code to be executed in the browser, providing superior performance to Javascript.

Where does Blazor WebAssembly run?

As Microsoft explains, with Blazor WebAssembly, the client application and its dependencies are compiled into binary code and downloaded in parallel to the web browser. When a user accesses the application, it runs very quickly in the browser the end user uses, because, thanks to WebAssembly, the code is highly optimized.

Authentication in Blazor WebAssembly

Microsoft describes on its website how to secure a standalone Blazor WebAssembly application using the Blazor WebAssembly authentication library.

Thus, when an application is designed for individual user accounts, it instantly receives a reference from Microsoft.AspNetCore.Components.WebAssembly.Authentication package. With this, users can be verified, and tokens can be obtained.

What are the components of Blazor?

In Blazor, a component is a tool used to create what the end user sees. For example, in a web page, it would be the home page, another one of its URLs, one of the drop-down elements…

Razor components can be used in Blazor applications, automatically making them Blazor components. Razor is a .NET based code syntax for creating web pages and uses extensions such as .cshtml or .razor.

Blazor vs. React or Angular

Blazor, React, and Angular are all open-source frameworks. Blazor uses C#, while React and Angular use TypeScript. The former is from Microsoft, while React was created by Facebook and Angular was created by Google.

Using one or the other depends on the developer’s needs: the programming language he prefers, the developer community behind it (React and Angular are older than Blazor)… But there is no doubt that with Blazor, it is very easy to use all the power of WebAssembly to create web applications that take advantage of all the system’s resources.

Vanilla wasm project

First of all, for every web assembly project, you will need a csproj that uses .net6 framework, the Microsoft.NET.Sdk.BlazorWebAssembly SDK to enable the wasm targets, and the references to the WebAssembly and DevServer nugets. Additionally, we need to add a Program.cs static class with a Main method that creates the host builder, and a wwwroot folder with an index.html file that calls blazor.webassembly.js entrypoint. Finally, to print something to the console, you could just call Console.WriteLine in the main method. To enable the debugger, a lauchSettings.json with “inspectUri” property needs to be in the properties folder.

vanilla wasm project

If it feels a little messy don’t worry, you will understand it much better looking at the console sample. You can just use this sample as your default WebAssembly template. Another easy way would be just to create a Blazor WebAssembly App from Visual Studio 2022, and then delete all razor files and remove from Program.cs the lines that add RootComponents and scoped services.

Once that everything is in place, put a breakpoint on Program.cs and run the debugger using the name of the project profile, or the IIS Express profile (we recommend the first as it seems to be faster). Your web app will stop in the breakpoint at the .Net6/WebAssembly code!

net6 webassembly code

Javascript <-> .Net interaction

Back and forth interaction between Javascript and .Net is possible using the JSRuntime exposed by the blazor host. However, out of the box you can only invoke global javascript functions from .Net. Therefore, we built a JSRuntime wrapper (look at the jsinteraction sample) that exposes an API like the one that was previously available in mono. It enables not only invoke js functions but also manipulate “JSObjects” like getting/setting properties or adding event listeners that call back to .Net.

javascript net interaction

Although this flexibility is great, it comes with a price: It is rather slow. Check the next section to know more.

Fast Javascript interaction: Linking to a native library, and callback

The functionality available in the above samples is great but it is not enough to build high-performance applications. For example, when you add an event listener which callback needs to access js properties and methods, multiple calls between js and .net are performed every time it is triggered. This is especially harmful on events that trigger often, like “mousemove”.

To solve this, like many other problems like interacting with native browser libraries like WebGL, OpenAL or WebXR, the best option here is to create a custom C++ or Rust library and then call them using P/Invoke.

Check the console-native example to know how to compile a C++ library using emscripten, that also makes a callback to .Net very fast.

console wasm sample

This is the most optimum way to work with the browser, but its architecture is a bit more complex. We recommend keeping the JSRuntime wrapper for no real-time algorithms, like initializations or sporadic events, and leave the native libraries approach for the rest, like operations that occur inside a draw loop.

Use the Virtual File System

Blazor SDK doesn’t support (at least for now) working with the virtual file system. That means loading web assets to a Javascript virtual file system, which then can be accessed from .Net just using System.File API, as if you were in a real OS. This has many advantages, like reusing .Net code or libraries that were originally built to work for Windows or any other OS.

Fortunately, we have implemented a VFS system that instructs your web assembly application to load the files described at your csproj into the virtual file system, to be used later by your app seamlessly. Check it out the source code at the filesystem sample.

console wasm sample

Production: Brotli/Gzip compression

Load times are very important in every app. As you probably know, in web apps file size is critical to load time. The Blazor WebAssembly SDK targets already allow us to compress our web assets using GZip or Brotli, but it doesn’t provide an out-of-the-box solution to serve those files when the client asks for them.

Fortunately, we found a simple solution: Create an “empty” ASP.net server and configure it to serve compressed files automatically when a compressed version of a file exists in the server. Check the full source code at the filesystem-server sample.

Final notes

We hope you find these samples useful and helps you boost your wasm apps. All this work is framed in the efforts made to bring WaveEngine to .Net6 in web. With these building blocks, we were able to render with WebGL at a great performance, as well as other technologies like OpenAL or WebXR. The samples repositories already have a WebXR sample that we are using as a sandbox for testing the technology, and maybe soon we will add WebGL and OpenAL ones in a new article. Keep posted to know more!

javier carnero
Author
Javier Carnero
Plain Concepts Research