Run .NET and Node.js code in-process on Windows, MacOS, and Linux
Edge.js allows you to run Node.js and .NET code in one process on Windows, MacOS, and Linux.
You can call .NET functions from Node.js and Node.js functions from .NET. Edge.js takes care of marshalling data between CLR and V8. Edge.js also reconciles threading models of single threaded V8 and multi-threaded CLR. Edge.js ensures correct lifetime of objects on V8 and CLR heaps. The CLR code can be pre-compiled or specified as C#, F#, Python, or PowerShell source: Edge.js can compile CLR scripts at runtime. Edge can be extended to support other CLR languages or DSLs.
Edge.js provides an asynchronous, in-process mechanism for interoperability between Node.js and .NET. You can use this mechanism to:
- script Node.js from a .NET application (console app, ASP.NET, etc.)
- script C# from a Node.js application on Windows, MacOS, and Linux
- access MS SQL from Node.js using ADO.NET more...
- use CLR multi-threading from Node.js for CPU intensive work more...
- write native extensions to Node.js in C# instead of C/C++
- integrate existing .NET components into Node.js applications
Read more about the background and motivations of the project here.
Follow @tjanczuk for updates related to the module.
Scripting CLR from Node.js
If you are writing a Node.js application, this section explains how you include and run CLR code in your app. It works on Windows, MacOS, and Linux.
What you need
Edge.js runs on Windows, Linux, and MacOS and requires Node.js 0.8 or later, as well as .NET Framework 4.5. or Mono 3.4.0.
Windows
- Node.js 0.8.x or later (developed and tested with v0.8.22, and v0.10.0, both x32 and x64 architectures)
- .NET 4.5
- to use Python, you also need IronPython 2.7.3 or later
- to use F#, read Dave Thomas blog post
Linux
- Node.js 0.8.x or later (developed and tested with v0.10.26 x64)
- Mono 3.4.0 x64
- Check out Ubuntu 12.04 setup instructions
MacOS
- Node.js 0.8.x or later (developed and tested with v0.10.26 x64)
- Mono 3.4.0 x64
- Check out Mac OS setup instructions
Docker
Edge.js is available as a Docker image on the tjanczuk/edgejs repository on Docker Hub. The image is based on Ubuntu 14.04, and contains Node.js 0.10.30 x64, Mono 3.4.0 x64, and globally installed Edge.js:
> docker run -it tjanczuk/edgejs:0.9.3
> cd samples
> node 101_hello_lambda.js
.NET welcomes Node.js
How to: C# hello, world
Follow setup instructions for your platform.
Install edge:
npm install edge
In your server.js:
var edge = require('edge');
var helloWorld = edge.func(function () {/*
async (input) => {
return ".NET Welcomes " + input.ToString();
}
*/});
helloWorld('JavaScript', function (error, result) {
if (error) throw error;
console.log(result);
});
Run and enjoy:
$>node server.js
.NET welcomes JavaScript
How to: integrate C# code into Node.js code
Edge provides several ways to integrate C# code into a Node.js application. Regardless of the way you choose, the entry point into the .NET code is normalized to a Func<object,Task<object>> delegate. This allows Node.js code to call .NET asynchronously and avoid blocking the Node.js event loop.
Edge provides a function that accepts a reference to C# code in one of the supported representations, and returns a Node.js function which acts as a JavaScript proxy to the Func<object,Task<object>> .NET delegate:
var edge = require('edge');
var myFunction = edge.func(...);
The function proxy can then be called from Node.js like any asynchronous function:
myFunction('Some input', function (error, result) {
//...
});
Alternatively, if you know the C# implementation will complete synchronously given the circumstances, you can call this function as any synchronous JavaScript function as follows:
var result = myFunction('Some input', true);
The true parameter instead of a callback indicates that Node.js expects the C# implementation to complete synchronously. If the CLR function implementation does not complete synchronously, the call above will result in an exception.
One representation of CLR code that Edge.js accepts is C# source code. You can embed C# literal representing a .NET async lambda expression implementing the Func<object,Task<object>> delegate directly inside Node.js code:
var add7 = edge.func('async (input) => { return (int)input + 7; }');
In another representation, you can embed multi-line C# source code by providing a function with a body containing a multi-line comment. Edge extracts the C# code from the function body using regular expressions:
var add7 = edge.func(function() {/*
async (input) => {
return (int)input + 7;
}
*/});
If your C# code is more involved than a simple lambda, you can specify entire class definition. By convention, the class must be named Startup and it must have an Invoke method that matches the Func<object,Task<object>> delegate signature. This method is useful if you need to factor your code into multiple methods:
var add7 = edge.func(function() {/*
using System.Threading.Tasks;
public class Startup
{
public async Task<object> Invoke(object input)
{
int v = (int)input;
return Helper.AddSeven(v);
}
}
static class Helper
{
public static int AddSeven(int v)
{
return v + 7;
}
}
*/});
If your C# code grows substantially, it is useful to keep it in a separate file. You can save it to a file with *.csx or *.cs extension, and then reference from your Node.js application:
var add7 = edge.func(require('path').join(__dirname, 'add7.csx'));
If you integrate C# code into your Node.js application by specifying C# source using one of the methods above, edge will compile the code on the fly. If you prefer to pre-compile your C# sources to a CLR assembly, or if your C# component is already pre-compiled, you can reference a CLR assembly from your Node.js code. In the most generic form, you can specify the assembly file name, the type name, and the method name when creating a Node.js proxy to a .NET method:
var clrMethod = edge.func({
assemblyFile: 'My.Edge.Samples.dll',
typeName: 'Samples.FooBar.MyType',
methodName: 'MyMethod' // This must be Func<object,Task<object>>
});
If you don't specify methodName, Invoke is assumed. If you don't specify typeName, a type name is constructed by assuming the class called Startup in the namespace equal to the assembly file name (without the .dll). In the example above, if typeName was not specified, it would default to My.Edge.Samples.Startup.
The assemblyFile is relative to the working directory. If you want to locate your assembly in a fixed location relative to your Node.js application, it is useful to construct the assemblyFile using __dirname.
You can also create Node.js proxies to .NET functions specifying just the assembly name as a parameter:
var clrMethod = edge.func('My.Edge.Samples.dll');
In that case the default typeName of My.Edge.Samples.Startup and methodName of Invoke is assumed as explained above.
How to: specify additional CLR assembly references in C# code
When you provide C# source code and let edge compile it for you at runtime, edge will by default reference only mscorlib.dll and System.dll assemblies. In applications that require additional assemblies you can specify them in C# code using a special hash pattern, similar to Roslyn. For example, to use ADO.NET you must reference System.Data.dll:
var add7 = edge.func(function() {/*
#r "System.Data.dll"
using System.Data;
using System.Threading.Tasks;
public class Startup
{
public async Task<object> Invoke(object input)
{
// ...
}
}
*/});
If you prefer, instead of using comments you can specify references by providing options to the edge.func call:
var add7 = edge.func({
source: function() {/*
using System.Data;
using System.Threading.Tasks;
public class Startup
{
public async Task<object> Invoke(object input)
{
// ...
}
}
*/},
references: [ 'System.Data.dll' ]
);



浙公网安备 33010602011771号