logo
0
0
WeChat Login

Node.js 调用 .NET AOT DLL 示例

本示例演示了如何在 Node.js 中调用 .NET AOT (Ahead-of-Time) 编译的 DLL 文件。

实现步骤

1. 编译 .NET AOT DLL

步骤 1: 创建 .NET 项目

dotnet new console -o DotNetAotLibrary cd DotNetAotLibrary

步骤 2: 添加 NativeExports.cs 文件

将示例中的 NativeExports.cs 文件添加到项目中。

步骤 3: 修改 csproj 文件

编辑 DotNetAotLibrary.csproj,修改以下配置:

<Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <OutputType>Library</OutputType> <TargetFramework>net9.0</TargetFramework> <PublishAot>true</PublishAot> <AllowUnsafeBlocks>true</AllowUnsafeBlocks> <ImplicitUsings>enable</ImplicitUsings> <Nullable>enable</Nullable> </PropertyGroup> </Project>

步骤 4: 编译 AOT DLL

dotnet publish -c Release -r win-x64

编译完成后,DLL 文件将位于 bin/Release/net9.0/win-x64/publish/ 目录下。

2. 配置 Node.js 项目

步骤 1: 初始化项目

npm init -y

步骤 2: 安装依赖

npm install ffi-napi ref-napi

注意:如果安装 ffi-napi 时遇到构建错误,可能需要:

  • 安装 Visual Studio Build Tools
  • 确保 Python 3.10+ 已安装
  • 使用管理员权限运行命令提示符

3. 运行示例

示例 1: 使用基础脚本

  1. 修改 DLL 路径 编辑 call-aot-dll.js 文件,将 DLL 路径修改为实际编译后的路径(如果需要):

    const myAotLibrary = ffi.Library('./DotNetAotLibrary/bin/Release/net9.0/win-x64/publish/DotNetAotLibrary.dll', { // ... });
  2. 运行基础脚本

    node call-aot-dll.js

示例 2: 使用分组 API

  1. 使用分组 API 创建一个新的 JavaScript 文件,使用分组后的 API:

    const { Math, String, Json, Version } = require('./dotnet-api'); // 调用数学运算 console.log(Math.add(10, 20)); // 调用字符串处理 console.log(String.toUpper('hello')); // 调用 JSON 处理 const result = Json.processJson(JSON.stringify({ id: 1, name: '测试' })); console.log(result); // 调用版本获取 console.log(Version.getVersion());
  2. 运行分组 API 测试

    node test-dotnet-api.js

4. 项目结构

NodeApi/ ├── DotNetAotLibrary/ │ ├── NativeExports.cs # 主要导出功能 │ ├── MathExports.cs # 数学运算功能 │ ├── StringExports.cs # 字符串处理功能 │ └── DotNetAotLibrary.csproj # 项目配置 ├── call-aot-dll.js # 基础调用脚本 ├── dotnet-api.js # 分组 API 封装 ├── test-dotnet-api.js # 分组 API 测试 └── README.md # 项目说明文档

示例说明

C# 代码说明

  1. 多类导出设计

    • MathExports:数学运算方法(Add、Subtract、Multiply、Divide)
    • StringExports:字符串处理方法(GetLength、ToUpper、ToLower、Concat)
    • NativeExports:原始功能方法(CalculateSum、ProcessString、GetVersion、ProcessJsonData)
  2. 函数导出特性

    • 使用 [UnmanagedCallersOnly] 特性导出函数,指定 EntryPoint
    • 不同类的方法使用不同的命名前缀:Math_String_CalculateSum
    • 支持不同类型的参数和返回值
  3. UTF-8 字符串处理

    • StringToUtf8Ptr:将字符串转换为 UTF-8 编码的指针
    • Utf8PtrToString:从指针读取 UTF-8 编码的字符串
  4. JSON 序列化配置

    • 使用 JsonSourceGenerationOptions 配置 JSON 序列化
    • 支持中文编码、允许从字符串读取数字、支持尾随逗号
    • 属性名不区分大小写、写入 null 时忽略属性
    • 使用静态构造函数初始化 JsonSerializerContext,配置编码器支持所有 Unicode 范围

Node.js 代码说明

  1. 分组 API 设计

    • MathApi:封装数学运算方法
    • StringApi:封装字符串处理方法
    • JsonApi:封装 JSON 处理方法
    • VersionApi:封装版本信息获取方法
  2. FFI 调用

    • 使用 ffi-napi 模块加载和调用 DLL
    • 直接使用字符串类型作为参数,ffi-napi 自动处理指针转换
    • 直接接收字符串返回值,无需手动处理指针
  3. 内存管理

    • 自动处理内存分配和释放
    • 无需手动调用 FreeMemory 函数
  4. 异常处理

    • 添加异常处理确保程序稳定性
    • 支持中文数据的传输和处理

支持的类型映射

.NET 类型C 类型ffi-napi 类型
intint'int'
stringchar*'string'
boolbool'bool'
doubledouble'double'
IntPtrvoid*'pointer'

注意事项

  1. 确保 .NET 和 Node.js 运行时架构一致(都是 x64 或都是 x86)
  2. 字符串处理使用自定义的 UTF-8 编码实现,支持中文
  3. 必须调用 FreeMemory 函数释放 DLL 中分配的内存,避免内存泄漏
  4. 异常处理确保程序稳定性
  5. 需要将 OutputType 设置为 Library 而不是 Exe
  6. 使用 JsonSourceGenerationOptions 配置 JSON 序列化,支持多种高级选项
  7. 配置了编码器支持所有 Unicode 范围,确保中文正常显示
  8. 使用静态构造函数初始化 JsonSerializerContext,确保配置正确应用

参考资料