Blog entries

Balzor Webassembly call from JS

Matthias Hempel (2025-04-23 21:34:46)

Short topic description

The goal is to load Blazor Webassembly functionality into JavaSript / TypeScript. In other wods: we want to call a Blzor method from javascript side.


Precondition

✔️ Typescript

✔️ Webpack

✔️ Blazor Webassembly project


The Blazor class

First of all the class

- needs an Attribute which makes it platform specific regarding the usage in a browser and

- the class needs to be partial

as follows

namespace MyNamespace
{
   [SupportedOSPlatform('browser')]
   public partial class Main
   {
      ...

   // The Blazor method need the JSxprt Attribute the method hae to be static
   [JSExport]
   public static string AMethod(string data)
   {


Thats all from C# side...


After building the Blazor project we get a '_framework' folder insinde the 'wwwroot' folder (in my case: net8.0\wwwroot\_framework).

This folder is needed in the webproject.

In our index.html / index.php we need to reference the following script:

<script type='module' src='/js/_framework/blazor.webassembly.js'></script>

(I put the '_framework' folder inside the 'js' folder)


Now we can write another script (I save it in the 'js' folder as worker.js) to call our blazor method. This call will depend on a 'message' event

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

let mainController = null;
self.addEventListener('message', async function(e) {
   // `e.data` contains data sent from main thread

   // get the objects needed to run exported C# code
   const { getAssemblyExports, getConfig } = await dotnet.create();

   // config contains the web-site configurations
   const config = getConfig();

   // exports contain the methods exported by C#
   const exports = await getAssemblyExports(config.mainAssemblyName);

   // get C# class
   mainController = exports.WebAppWasm.Controllers.Main;
   //const fileData = JSON.parse(e.data);
   const data = e.data.data;
   execute(data); // reconstructed and callable
});


This event will call the execute message, which will call the C# method and afterwards post data to event subsribers:

async function execute(fileData) {
   const data = await mainController.AMethod(fileData);
   postMessage(data);
}


On Javascript / Typescript side we will need a worker to subscribe and listen to the message event:

this.worker = new Worker(URLROOT + '/js/worker.js', { type: 'module' });


We need a data object which shows whether we got some data from the worker thread (here it is an interface ICallData):

const callData: ICallData = { called: false };


And we need to post our data to the worker thread to trigger the worker an send the data to the wasm library (as method parameter):

this.worker.postMessage({
   data: fileData
});


The data object callData will be set to true if the worker is ready, which is done within the following function:

function fctWorker(e: any) {
   data = e.data;
   callData.called = true;
}


Then we wait for it to be ready:

await this.wait(callData);


And the wait funcion is defined as follows:

public async wait(callData: ICallData) {
   function timeout(ms) {
      return new Promise((res) => setTimeout(res, ms));
   }

   while (!callData.called) {
      await timeout(1000);
   }
}

In this function we set a timeout every 1000 ms until callData.called is set to true.


To get this working we need to attach the fctWorker function to the event message listener of the worker:

this.worker.addEventListener('message', fctWorker);


html import under Typescript / Webpack

Matthias Hempel (2025-03-12 22:57:55)

Short topic description

Sometimes it is necessary to red some html code within typescript / javascript. To get the file content the import functionality can be used. The following steps will illustrate how to do that.


Precondition

✔️ Typescript

✔️ Webpack


Installation of raw-loader

to load other module types we need to install raw loader:

npm i raw-loader --save-dev


Global typescript definition

In our project root folder we need to create this file (in case it is not there yet): global.d.ts

Here we add the following code to define the html module import

declare module '*.html' {
   const content: string;
   export default content;
}


Add module rule to the webpack.config.js

we add the following code to the module: { rules array:

{
   test: /\.html$/,
   use: 'raw-loader'
}


Define html file

Now we can define the html file with some code e.g.:


tag1
tag2


Import into typescript

And import it into typescript with

import html from './TheFileName.html';

🖋️ html: this is your variable name holding the resulting string

🖋️ ./TheFileName.html: this is the relative path to your file name (int this case it is located in the same folder)