Javascript.NodeJS
Invoke Javascript in NodeJS, from C#
Install / Use
/learn @JeringTech/Javascript.NodeJSREADME
Jering.Javascript.NodeJS
Table of Contents
Overview
Target Frameworks
Platforms
Prerequisites
Installation
Usage
API
Performance
Building and Testing
Projects Using this Library
Related Concepts
Contributing
About
Overview
Jering.Javascript.NodeJS enables you to invoke javascript in NodeJS, from C#. With this ability, you can use Node.js-javascript libraries and scripts from your C# projects.
You can use this library as a replacement for the obsoleted Microsoft.AspNetCore.NodeServices.
InvokeFromFileAsync<T>replacesINodeService'sInvokeAsync<T>andInvokeExportAsync<T>.
This library is flexible - it provides both a dependency injection (DI) based API and a static API. Also, it supports invoking both in-memory and on-disk javascript.
Static API example:
string javascriptModule = @"
module.exports = (callback, x, y) => { // Module must export a function that takes a callback as its first parameter
var result = x + y; // Your javascript logic
callback(null /* If an error occurred, provide an error object or message */, result); // Call the callback when you're done.
}";
// Invoke javascript
int result = await StaticNodeJSService.InvokeFromStringAsync<int>(javascriptModule, args: new object[] { 3, 5 });
// result == 8
Assert.Equal(8, result);
DI-based API example:
string javascriptModule = @"
module.exports = (callback, x, y) => { // Module must export a function that takes a callback as its first parameter
var result = x + y; // Your javascript logic
callback(null /* If an error occurred, provide an error object or message */, result); // Call the callback when you're done.
}";
// Create an INodeJSService
var services = new ServiceCollection();
services.AddNodeJS();
ServiceProvider serviceProvider = services.BuildServiceProvider();
INodeJSService nodeJSService = serviceProvider.GetRequiredService<INodeJSService>();
// Invoke javascript
int result = await nodeJSService.InvokeFromStringAsync<int>(javascriptModule, args: new object[] { 3, 5 });
// result == 8
Assert.Equal(8, result);
Target Frameworks
- .NET Standard 2.0
- .NET Framework 4.6.1
- .NET Core 3.1
- .NET 5.0
- .NET 6.0
Platforms
- Windows
- macOS
- Linux
Prerequisites
You'll need to install NodeJS and add the NodeJS executable's directory to the Path environment variable.
Installation
Using Package Manager:
PM> Install-Package Jering.Javascript.NodeJS
Using .NET CLI:
> dotnet add package Jering.Javascript.NodeJS
Usage
This section explains how to use this library. Topics:
Using the DI-Based API
Using the Static API
Invoking Javascript
Debugging Javascript
Configuring
Customizing Logic
Enabling Multi-Process Concurrency
Using the DI-Based API
First, create an INodeJSService. You can use any DI framework that has adapters for Microsoft.Extensions.DependencyInjection.
Here, we'll use vanilla Microsoft.Extensions.DependencyInjection:
var services = new ServiceCollection();
services.AddNodeJS();
ServiceProvider serviceProvider = services.BuildServiceProvider();
INodeJSService nodeJSService = serviceProvider.GetRequiredService<INodeJSService>();
Once you've got an INodeJSService, you can invoke javascript using its invoke methods. All invoke methods are thread-safe.
Here's one of its invoke-from-string methods:
string? result = nodeJSService.InvokeFromStringAsync<Result>("module.exports = (callback, message) => callback(null, message);", args: new[] { "success" });
Assert.Equal("success", result);
We describe all of the invoke methods in detail later on.
No clean up is required when you're done:
the NodeJS process INodeJSService sends javascript invocations to kills itself when it detects that its parent process has died.
If you'd like to manually kill the NodeJS process, you can call INodeJSService.Dispose().
Once the instance is disposed, all invoke methods throw ObjectDisposedException.
This is important to keep in mind since services.AddNodeJS() registers INodeJSService as a singleton (same instance injected every where).
Using the Static API
This library provides a static alternative to the DI-based API. StaticNodeJSService wraps an INodeJSService, exposing most of its public members.
With the static API, you don't need to worry about creating or managing INodeJSService. Example usage;
string result = await StaticNodeJSService
.InvokeFromStringAsync<Result>("module.exports = (callback, message) => callback(null, message);", args: new[] { "success" });
Assert.Equal("success", result);
StaticNodeJSService's invoke methods are thread-safe.
Clean-up wise, StaticNodeJSService.DisposeServiceProvider() kills the NodeJS process immediately.
Alternatively, the NodeJS process kills itself when it detects that its parent process has died.
Whether you use the static API or the DI-based API depends on your development needs. If you're already using DI and/or you want to mock
out INodeJSService in your tests and/or you want to customize services, use the DI-based API. Otherwise,
the static API works fine.
Invoking Javascript
We'll begin with the javascript side of things. You'll need a NodeJS module that exports either a function or an object containing functions. Exported functions can be of two forms:
Function With Callback Parameter
These functions take a callback as their first argument, and call the callback when they're done.
The callback takes two optional arguments:
- The first argument is an error or an error message. It must be of type
Errororstring. - The second argument is the result. It must be a JSON-serializable type, a
string, or astream.Readable.
Note: this is known as an error-first callback. Such callbacks are used for error handling in NodeJS asynchronous code (check out NodeJS Event Loop for more information on asynchrony in NodeJS).
As mentioned before, you'll need a module that exports either a function or an object containing functions. This is a module that exports a valid function:
module.exports = (callback, arg1, arg2, arg3) => {
... // Do something with args
callback(null /* error */, result /* result */);
}
This is a module that exports an object containing valid functions:
module.exports = {
doSomething: (callback, arg1) => {
... // Do something with arg
callback(null, result);
},
doSomethingElse: (callback) => {
... // Do something else
callback(null, result);
}
}
If an error or error message is passed to the callback, it's sent back to the calling .NET process, where an InvocationException is thrown.
Async Function
Async functions are the second valid function form. They're syntactic sugar for the function form described in the previous section (check out Callbacks, Promises and Async/Await for a summary on how callbacks, promises and async/await are related).
This is a module that exports a valid function:
module.exports = async (arg1, arg2) => {
... // Do something with args
return result;
}
And this is a module that exports an object containing valid functions:
module.exports = {
doSomething: async (arg1, arg2, arg3, arg4) => {
... // Do something with args
// async functions can explicitly return promises
return new Promise((resolve, reject) => {
resolve(result);
});
},
doSomethingElse: async (arg1) => {
... // Do something with arg
return result;
}
}
If an error is thrown in an async function, the error message is sent back to the calling .NET process, where an InvocationException is thrown:
module.exports = async () => {
throw new Error('error message');
}
Invoking Javascript From a File
Now that we've covered the javascript side of things, let's invoke some javascript from C#.
If you have a javascript file named exampleModule.js (located in [NodeJSProcessOptions.ProjectPath](#nodejsprocessoptionsprojectpa
Related Skills
node-connect
345.9kDiagnose OpenClaw node connection and pairing failures for Android, iOS, and macOS companion apps
frontend-design
106.4kCreate distinctive, production-grade frontend interfaces with high design quality. Use this skill when the user asks to build web components, pages, or applications. Generates creative, polished code that avoids generic AI aesthetics.
openai-whisper-api
345.9kTranscribe audio via OpenAI Audio Transcriptions API (Whisper).
qqbot-media
345.9kQQBot 富媒体收发能力。使用 <qqmedia> 标签,系统根据文件扩展名自动识别类型(图片/语音/视频/文件)。
