microsoft / microsoft/node-api-dotnet

Importing `node-api-dotnet` into node into a dotnet app

Open
#330 6 comments 1 reaction 1 assignee View on GitHub

@jasongin is already working on this.

Since Jul 24, 2024.

enhancement
Dominant language
C#
Stars
783
Forks
80
PR merge metrics
No merged PRs in 30d

Description

The use case here is to create a runtime "script editor" that uses javascript/typescript as the language.

So the goal is:

  1. Running in dotnet host program
  2. User writes javascript that can interop with net objects
  3. Javascript is executed by the dotnet side.

I'm having issues calling the javascript import of node-api-dotnet when it's running inside the host process. Here's a reproducible example, where the TEST_MS flag just makes sure it does work with the simple ms package.

//#define TEST_MS

// See https://aka.ms/new-console-template for more information
using Microsoft.JavaScript.NodeApi;
using Microsoft.JavaScript.NodeApi.Runtime;
using System.Reflection;

Console.WriteLine("Hello, World!");

string baseDir = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location)!;

File.WriteAllText(Path.Combine(baseDir, "package.json"), $"{{\"type\":\"module\"}}");

NodejsPlatform platform = new NodejsPlatform(Path.Combine(baseDir, "native", "win-x64", "libnode.dll"));

NodejsEnvironment env = platform.CreateEnvironment(baseDir);

await env.RunAsync(async () =>
{
#if TEST_MS
    JSValue console = JSValue.CreateObject();
    console.SetProperty("info", JSValue.CreateFunction("info", (args) =>
    {
        for (int i = 0; i < args.Length; i++)
        {
            Console.WriteLine(args[i].GetValueExternalOrPrimitive()!.ToString());
        }
        return JSValue.Undefined;

    }));
    JSValue.Global.SetProperty("console", console);

    JSValue.RunScript("const ms = require(\"C:/node_modules/ms\"); " +
        "console.info(\"data\", ms(1231234));");
#else
    JSValue.RunScript("const dotnet = require(\"C:/node_modules/node-api-dotnet\");");
    Console.WriteLine("Finished.");
#endif

});

The exception I get here is:

Unhandled Exception: System.EntryPointNotFoundException: Arg_EntryPointNotFoundExceptionParameterizedNoLibrary, napi_create_string_utf16
   at System.Runtime.InteropServices.NativeLibrary.GetSymbol(IntPtr, String, Boolean) + 0x57
   at Microsoft.JavaScript.NodeApi.Runtime.NodejsRuntime.CreateString(JSRuntime.napi_env, ReadOnlySpan`1, JSRuntime.napi_value&) + 0x62
   at Microsoft.JavaScript.NodeApi.JSValue.CreateStringUtf16(String) + 0x72
   at Microsoft.JavaScript.NodeApi.JSValue.op_Implicit(String) + 0x15
   at Microsoft.JavaScript.NodeApi.DotNetHost.NativeHost.InitializeModule(JSRuntime.napi_env, JSRuntime.napi_value) + 0x435

Which is the same when using await env.ImportAsync("C:/node_modules/node-api-dotnet/net8.0", null, true);

It did occur to me that the Microsoft.JavaScript.NodeApi.dll exists in both the dotnet project and the node module here. Any ideas on how to resolve this?

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.