Develop a Node.js addon module in C#
For a minimal example of this scenario, see /examples/dotnet-module/.
Create a .NET Class library project that targets .NET 6 or later. (.NET 8 for AOT.)
shellmkdir ExampleModule cd ExampleModule dotnet new classlib --framework net6.0
Add a reference to the
Microsoft.JavaScript.NodeApi
andMicrosoft.JavaScript.NodeApi.Generator
packages:shelldotnet add package --prerelease Microsoft.JavaScript.NodeApi dotnet add package --prerelease Microsoft.JavaScript.NodeApi.Generator
Afterward you should have the two references in your project file:
xml<ItemGroup> <PackageReference Include="Microsoft.JavaScript.NodeApi" Version="0.7.*-*" /> <PackageReference Include="Microsoft.JavaScript.NodeApi.Generator" Version="0.7.*-*" /> </ItemGroup>
Add one or more public types to the project with the
[JSExport]
attribute. Types tagged with this attribute, along with any types referenced in public properties or methods of tagged types, are exported to JavaScript. It is also possible to export module-level properties and methods by using[JSExport]
onpublic static
properties or methods of a class that is otherwise not exported.C#using Microsoft.JavaScript.NodeApi; [JSExport] public class Example {
Build the project, to produce the assembly (
.dll
) file.shelldotnet build
The build also automaticaly produces a
.d.ts
file with type definitions for APIs in the module that are exported to JavaScript.✨ TIP
If you're curious, you can check out the generated marshalling code for exported APIs at
obj/{Configuration}/{TargetFramerwork}/{RuntimeIdentifier}/generated/ Microsoft.JavaScript.NodeApi.Generator/Microsoft.JavaScript.NodeApi.Generator.ModuleGenerator/
. Read about marshalling code-generation to learn more about what's going on in there.Switching over to the JavaScript project, add a dependency on the
node-api-dotnet
npm package:shellnpm install node-api-dotnet
Import the
node-api-dotnet
package in your JavaScript or TypeScript code. The import syntax depends on the module system the current project is using.JavaScriptimport dotnet from 'node-api-dotnet';
TypeScriptimport * as dotnet from 'node-api-dotnet';
JavaScriptconst dotnet = require('node-api-dotnet');
To load a specific version of .NET, append the target framework moniker to the module name. A
.js
suffix is required when using ES modules, optional with CommonJS.JavaScriptimport dotnet from 'node-api-dotnet/net8.0.js';
TypeScriptimport * as dotnet from 'node-api-dotnet/net8.0';
JavaScriptconst dotnet = require('node-api-dotnet/net8.0');
Currently the supported target frameworks are
net472
,net6.0
, andnet8.0
.Load your .NET module assembly from its path using the
dotnet.require()
function:JavaScriptconst ExampleModule = dotnet.require('./bin/ExampleModule');
Exported APIs in the assembly are projected as properties on the loaded module object. So then you can use those to call static methods, construct instances of classes, etc:
JavaScriptExampleModule.StaticClass.ExampleMethod(); const exampleObj = new ExampleModule.ExampleClass(...args);
Of course you can access properites, pass arguments to methods, get return values, and so on. Most types get automatically marshalled between JavaScript and .NET as you'd expect. For details, see the JavaScript / .NET type mappings reference.