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!
What is Blazor WebAssembly?
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.
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!
Although this flexibility is great, it comes with a price: It is rather slow. Check the next section to know more.
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.
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
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.
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.
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!