Run .NET and Node.js code in-process with Edge.js
The Edge.js project enables you to run Node.js and .NET code in one process. In this article I discuss the motivation behind the project, describe the basic mechanisms Edge.js provides, and explore a few scenarios where it can help you develop your Node.js application.
Why use Edge.js?
While many applications can be written exclusively in Node.js, there are situations that require or benefit from a combination of Node.js and .NET. You may want to use .NET and Node.js in your application for several reasons. .NET framework and NuGet packages provide a rich ecosystem of functionality that complements that of Node.js and NPM modules. You may have pre-existing .NET components you want to reuse in a Node.js application. You may want to use multi-threaded CLR to run CPU-bound computations that are not well suited for single-threaded Node.js. Or you may prefer to use .NET Framework and C# as opposed to writing native Node.js extensions in C/C++ to access mechanisms specific to the operating system not already exposed through Node.js.
Once you decided that your application will use both Node.js and .NET, you have to separate the Node.js and .NET components with a process boundary and establish some form of inter-process communication between the processes, which could be HTTP:
Edge.js provides an alternative way of composing heterogeneous systems like the one above. It allows you to run Node.js and .NET code in a single process and provides an interop mechanism between V8 and CLR:
There are two main benefits of using Edge.js to run Node.js and .NET in one process instead of splitting the application into two processes: better performance, and reduced complexity. Performance measurements of one scenario show that in-process Edge.js call from Node.js to C# is 32 times faster than the same call made using HTTP between two local processes. Dealing with a single process instead of two processes with a communication channel between them reduces the deployment and maintenance complexity you need to handle.
.NET welcomes Node.js
I will use this basic example of calling from Node.js to C# to explain key concepts of Edge.js:
The first line imports the edge module previously installed from NPM. Edge.js is a native Node.js module. What is special about Edge.js is that the moment it is loaded it starts hosting CLR inside the node.exe process.
The interop pattern does not prevent you from accessing any parts of .NET framework, but it will often require you to write an extra adapter layer to expose the desired .NET functionality as a Func<object,Task<object>> delegate. This adapter layer requires that you explicitly address the issue of blocking APIs in .NET by possibly running the operation on a CLR thread pool to avoid blocking the Node.js event loop.
Data and functions
Edge.js marshals all data by value, so a copy of the data is created on the V8 or CLR heap when execution crosses the V8/CLR boundary. This rule has one notable exception: separately from marshaling data by value, Edge.js will marshal functions by reference. Let’s have a look at this example to illustrate this powerful concept:
Functions following the prescriptive interop pattern can also be marshaled from .NET to Node.js. Being able to marshal functions in either direction between V8 and CLR is a very powerful concept, especially when combined with a closure. Consider the following example:
The ability to marshal functions between V8 and CLR combined with the concept of a closure is a very powerful mechanism. It enables .NET code to expose functionality of CLR objects to Node.js. The local variable in line 3 in the last example could as well be an instance of a Person class.
Let’s build something
Let’s have a look at a few practical examples of how you can use Edge.js in a Node.js application.
Another example where Edge.js comes handy is accessing data in MS SQL. None of the options of accessing MS SQL data available for a Node.js developer today are as complete or mature as ADO.NET functionality in .NET Framework. Edge.js gives you a simple way of using ADO.NET in your Node.js application. Consider this Node.js application:
In line 1, Edge.js creates the sql function by compiling ADO.NET code in the sql.csx file. The sql function accepts a string with a T-SQL command, executes it asynchronously using ADO.NET, and returns the results back to Node.js. The sql.csx file supports the four CRUD operations against MS SQL database using less than 100 lines of ADO.NET code in C#:
The implementation in sql.csx file uses asynchronous ADO.NET APIs to access MS SQL and execute T-SQL command provided to it from Node.js.
The two examples above represent just a small portion of scenarios where Edge.js helps you write Node.js applications. You can see more samples at the Edge.js GitHub site.
Edge.js is an open source project licensed under Apache 2.0. It is currently under active development and contributions are welcome. You can check the list of work items that could use your time and expertise.
Although all the examples in this article were using C#, Edge.js supports running code in any CLR language within a Node.js application. Current extensions provide support for scripting F#, Python, and PowerShell. The language extensibility model allows you to easily add compilers for other CLR languages.
Edge.js currently requires .NET Framework and therefore only works on Windows. However, support for Mono is under active development and will enable running Edge.js application on MacOS and *nix in addition to Windows.
About the Author
Tomasz Janczuk is a software engineer at Microsoft. His current focus is node.js and Windows Azure. Before that he worked on .NET Framework and web services. In his free time he engages in a lot of outdoor activities in the Pacific Northwest and beyond. You can follow him on Twitter, @tjanczuk, check out his GitHub page or read his blog for more information.
Mike Amundsen May 29, 2015
Ben Linders May 28, 2015