不知小伙伴们有没有遇到过这样的需求,在web前端里需要调用其他语言编写的方法,再具体一点,比如集成一个硬件设备,一般来说,硬件配套的会有一个windows桌面应用的客户端,也就是.net。然后我们的浏览器应用要与这个硬件设备交互,那么可不可以省去客户端,让前端直接调用.net的C#函数呢?
为了应对这种需求,出现了WebAssembly技术。
WebAssembly是一种运行在现代网络浏览器中的新型代码,并且提供新的性能特性和效果。它设计的目的不是为了手写代码而是为诸如 C、C++和Rust等低级源语言提供一个高效的编译目标。
简单来说,将C#等代码编译为.wasm格式的文件,就可以给js调用,当然,还包括各种运行环境,dll链接库等,这些都会被打包在一个“沙箱”里。
React集成
下面我们以一个React项目中集成为例说明一下具体使用。
项目结构如下
我们看下C#代码结构,csproj配置文件里配置如下
net8.0
browser-wasm
Library
true
main.js
true
true
full
true
true
true
false
里面有这么一些关键点,首先指定main.js为调用入口,相当于js和C#的桥梁,里面会定义具体的可调用函数。然后RemoveVendor和CopyVendor会把编译后的一堆文件放到前端的public文件夹下,这个操作想必大家都能理解了。
下面我们看一下主文件Program.cs
这里简单定义了一个方法MyMethod,加上JSExport注解导出使用。
然后在main.js中将其暴露给前端调用。main.js内容如下
import {dotnet} from './_framework/dotnet.js'
globalThis.window = globalThis;
let dotnetRuntimePromise = undefined;
let exports = undefined;
async function createRuntime() {
try {
return dotnet
.withDiagnosticTracing(false)
.withModuleConfig({
locateFile: (path, prefix) => {
return '/' + path;
}
})
.create();
} catch (err) {
console.error(err);
throw err;
}
}
export async function initializeRuntimeExports(){
if (!dotnetRuntimePromise) {
dotnetRuntimePromise = createRuntime();
const { getAssemblyExports, getConfig } = await dotnetRuntimePromise;
const config = getConfig();
exports = await getAssemblyExports(config.mainAssemblyName)
}
}
// C#方法
export async function nativeMyMethod(param) {
return exports.Demo.Demo.MyMethod(param);
}
其中nativeMyMethod就可以给前端js调用了。
我们简单看一下如何调用
const demo = await import('./vendor/main.js')
await demo.initializeRuntimeExports();
const result = await demo.nativeMyMethod("xiaowai");
类似这样调用即可。
dotnet编译命令如下
dotnet publish -c Release
最后我们看一下编译后放在public里面的是哪些东西吧
除了main.js外,在_framework文件夹下是各种编译出来的wasm文件等,包括依赖的各种System动态链接库等,这里还是dll文件格式,如果把csproj中WasmEnableWebcil这个配置改成true就会是wasm格式啦,具体区别大家可以自行了解一下。
最后
WebAssembly技术的成熟度其实并没有很高,文档资料也比较混乱,涉及一些高深的用法歪哥也无法搞清楚,欢迎一起交流指正。