NodeJS and .NET are incredibly successfully and widely adopted platforms. What if we could transparently use both in the same project?
With xcorenode nodeJS plugin it is possible to create .NET objects, call methods, properties, subscribe events and take advantage of asynchronous (Task) methods.
During the session, we will deep dive into the key points of the plugin sources: setting up a basic V8 plugin, hosting the CLR Core in C++, mastering the libuv threading library, dynamically generating the marshalling code to invoke classes, managing the object lifecycle and finally using the plugin within nodejs … but not only!
This will also be a great occasion for myself to gather wishes and suggestions for the next upcoming version of xcorenode.
TrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
ITCamp 2017 - Raffaele Rialdi - A Deep Dive Into Bridging Node-js with .NET Core
1. @ITCAMPRO #ITCAMP17Community Conference for IT Professionals
A deep dive into bridging
NodeJS with NET Core
Raffaele Rialdi
@raffaeler
raffaeler@vevy.com
https://www.linkedin.com/in/raffaelerialdi/
3. @ITCAMPRO #ITCAMP17Community Conference for IT Professionals
Who am I?
• I am Raffaele Rialdi, Senior Software Architect in Vevy Europe – Italy
• I am also consultant in many industries
– manufacturing, racing, healthcare, financial, …
• But also Speaker in italian and international conferences
– Trainer as well
• And very proud to have been awarded as a Microsoft MVP
– Since 2003
@raffaeler
raffaeler@vevy.com
github.com/raffaeler
4. @ITCAMPRO #ITCAMP17Community Conference for IT Professionals
NodeJS and .NET? What do you mean?
• We do NOT want to
serialize the data across
processes
– Too easy ☺
– Poor performance
• All the code in the same
process
– Hard way ☺☺
– Good performance ☺
NodeJS
Process
Json Serialize
C#
Process
One Process
NodeJS
Code
C#
Code
6. @ITCAMPRO #ITCAMP17Community Conference for IT Professionals
xcore in action
• Load and initialize xcore
• Load the .net metadata
– Just the first needed class
• Create an instance
• Call methods
• Walk the graph
– new metadata is
loaded automatically
• Asynchronous calls
(and much more!)
var xcore = require('bindings')('xcore');
xcore.initialize(__dirname + "Sample",
"SampleLibrary.dll", "SampleLibrary.Initializer");
xcore.loadClass("SampleLibrary.OrderSample.
OrderManager, SampleLibrary");
var om = new xcore.OrderManager("raf");
console.log(om.Add("Hello, ", "world"));
console.log(om.SelectedOrder.Name);
om.AddAsync(2, 3, function(res){
console.log(res);
});
7. @ITCAMPRO #ITCAMP17Community Conference for IT Professionals
• Node.js® is a well-known runtime environment for javascript
• It leverages the power of "V8", the engine of Google Chrome
– V8 conforms to the ECMAScript 262 standard
– runs cross-platforms
• NodeJs has a vivid ecosystem with tons of 3rd party libraries
• V8 can be extended with native addons (C++):
– When you need more performance
– To access operating system's resources and services
– To interoperate with external systems / hardware
Node.JS and V8 https://nodejs.org
8. @ITCAMPRO #ITCAMP17Community Conference for IT Professionals
• Including the libraries
• Declare the Entry-Point using
the NODE_MODULE macro
• Implement the entry-point and
declare javascript-friendly
methods
• The "Method" will be available
as "hello" to javascript
The basic structure of a C++ V8 addon
#include <node.h>
#include <v8.h>
NODE_MODULE(addon, init)
void init(Local<Object> exports)
{
NODE_SET_METHOD(exports, "hello", Method);
}
void Method(const FunctionCallbackInfo<Value>& args)
{
Isolate* isolate = args.GetIsolate();
args.GetReturnValue().Set(
String::NewFromUtf8(isolate, "world"));
}
// javascript code
const addon = require('./myAddon');
console.log(addon.hello()); // 'world'
9. @ITCAMPRO #ITCAMP17Community Conference for IT Professionals
V8 Object Wrapping
• By deriving the ObjectWrap class, we can expose objects to JS
• Object members are added dynamically
– Constructors, methods, properties, indexers
– Just set the members spcifying the class name
• All member are static void functions
– Their input parameter is a "const FunctionCallbackInfo<Value>& args"
• The args contain the runtime values of the arguments
– The wrapper instance is get using ObjectWrap:Unwrap
– The return value is set using "args.GetReturnValue().Set(…);"
exports->Set(v8className, constructorTemplate->GetFunction());
10. @ITCAMPRO #ITCAMP17Community Conference for IT Professionals
• LibUV is the threading library used by NodeJs and V8
• The JS code must be always executed in the main thread
• .NET methods returning Task<T> must to be marshalled back to the
main thread
• The LibUV library gives a very basic support for enqueuing
messages in its threads
Threading and the libuv threading library
12. @ITCAMPRO #ITCAMP17Community Conference for IT Professionals
Hosting the CoreCLR
• What does it mean hosting the CLR?
– A native (C++) application can load the CLR, some assemblies and
run managed (.NET) code
– SQL Server is a great example of native application hosting the CLR
– You can do it too!
• The CLR in .NET Framework could be hosted only on
Windows
– It is based on the COM infrastructure
• Net Core can be hosted as well but cross-platform
– It mimics the COM interfaces, but the infrastructure is not COM-
dependent
15. @ITCAMPRO #ITCAMP17Community Conference for IT Professionals
• Metadata for the CLR type is loaded
–The C++ layer dynamically add the class definition to V8
• A member is invoked
–The C++ layer gets the arguments of the call
–A Reverse PInvoke is done to C#
–The instance identifier is retrieved from a global table
–If not available, the marshaller code is generated
–The code is invoked
xcore execution flow
16. @ITCAMPRO #ITCAMP17Community Conference for IT Professionals
• The call was synchronous
–The return value is marshalled back to C++ and V8
• The call was asynchronous
–In C++ the return value is queued in LibUV main thread
• The call was an exception
–It is propagated to the caller
xcore execution flow
17. @ITCAMPRO #ITCAMP17Community Conference for IT Professionals
Performance profile
• There are still many possible improvements
• The add use-case is not realistic
– it just measures infrastructure and marshalling
– 4 marshalling involved: (JS C++ .NET C++ JS)
1 Million calls
js: 6.156 ms
c++: 56.352 ms
.net: 1294.254 ms
console.time("net");
for(var i=0; i<loop; i++)
{
om.NetAdd(i, i);
}
console.timeEnd("net");
console.time("c++");
for(var i=0; i<loop; i++)
{
xcore.add(i, i);
}
console.timeEnd("c++");
console.time("js");
for(var i=0; i<loop; i++)
{
LocalAdd(i, i);
}
console.timeEnd("js");
js: 6.156ms c++: 56.352ms .net: 1294.254ms
var om = new xcore.OrderManager();
om.Add(2, 2); // jitting
LocalAdd(2,2); // jitting
xcore.add(2, 2); // jitting
var loop = 1000000; // 1 Million
function LocalAdd(x, y)
{ return x + y; }
prepare the benchmark local javascript C++ only xcore + C#
18. @ITCAMPRO #ITCAMP17Community Conference for IT Professionals
Use-cases
1. Node.js applications
2. UI created with the Electron framework
– Ability to create .NET ViewModels for Angular (by Google)
3. Using JS to script Windows Powershell
4. Nativescript Mobile applications
– Nativescript is a project by Progress Software Corporation
https://www.nativescript.org/
5. Anything else based on V8
http://electron.atom.io