MMS • Alen Genzic
Article originally posted on InfoQ. Visit InfoQ
The release of .NET 7 RC 1 has introduced the new wasm-experimental workload and new JavaScript interop features that allow invoking of .NET code in JavaScript applications running on WebAssembly without using the Blazor UI component model.
Until this release, it was possible to use WebAssembly without the need for Blazor by leveraging the Mono WASM SDK, Uno.Wasm.Bootstrap library or the NativeAOT LLVM. Although the new workload and features are the basis for Blazor WebAssembly, with .NET 7, using .NET code inside a WebAssembly context is possible without use of specialized libraries or Blazor and leveraging only utilities from inside .NET.
To allow usage of .NET code inside JavaScript, you can use the new JSExport attribute to expose a method to JavaScript. When applied to a method in .NET, the dotnet.js runtime exposes it through the getAssemblyExports function and you can use it as follows:
import { dotnet } from './dotnet.js'
const { getAssemblyExports, getConfig, runMainAndExit } = await dotnet.create();
const configuration = getConfig();
const exports = await getAssemblyExports(configuration.mainAssemblyName);
const myValue = exports.MyClass.MyMethod(); // Call into your method from ```js
await dotnet.run(); // Run the Program Main method
To use JavaScript code inside of .NET, you can use the JSImport attribute to expose a JavaScript method to .NET. The following code snippet demonstrates how to allow .NET to import a method.
import { dotnet } from './dotnet.js'
const { setModuleImports, getConfig, runMainAndExit } = await dotnet.create();
const configuration = getConfig();
// Set module imports that can be called from .NET
setModuleImports("main.js", {
window: {
location: {
href: () => globalThis.window.location.href
}
}
});
await dotnet.run(); // Run the Program Main method
Alternatively, instead of needing to call setModuleImports, you can create a ES6 module, export the methods from there and use JSHost to load a JavaScript ES6 module directly in .NET:
await JSHost.ImportAsync("main.js", "./main.js");
And on the .NET side, this is how you can import the method, regardless of the exposure variant you use:
[JSImport("window.location.href", "main.js")]
internal static partial string GetHRef();
Pavel Šavara’s GitHub repository presents additional code samples, along with a more detailed explanation of some parts of the code in the accompanying article. A video overview of the same sample is available in the ASP.NET Community Standup recording.
With this release, the IJSUnmarshalledRuntime interface, previously used to make unmarshalled synchronous calls to JavaScript interop, becomes obsolete, and developers are encouraged to use JSImport and JSExport going forward.
Debugging the interop code is not possible from Visual Studio yet, but the application can be debugged by running the application from the command-line and attaching the Visual Studio Code or Chrome debuggers.
In the context of Blazor WebAssembly, usage of the new interop feature is recommended only in scenarios when you need to use your .NET code on the client side only, IJSRuntime is still the recommended way to do asynchronous JavaScript interop in other scenarios and is supported across all Blazor runtimes.
The .NET 7 RC 1 SDK is available for download and after installation, you can install the new WebAssembly workload and create a new WebAssembly browser application by running the following commands:
dotnet workload install wasm-tools
dotnet workload install wasm-experimental
dotnet new wasmbrowser
This release makes additional improvements for Blazor applications including Debugging Improvements, availability of WebAssembly build tools for .NET 6, and Dynamic authentication requests in Blazor WebAssembly.
Microsoft has a more comprehensive list of updates in .NET 7 RC 1 for ASP.NET Core and the official announcement for further information on what is new in .NET 7 in general.