Skip to content
 
 

Latest commit

 

History

24 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Hosting .NET OWIN applications in node.js

Owin allows you to host .NET code in a node.js application. It helps with:

  • implementing express.js handlers and connect middleware for node.js application using .NET 4.5,
  • implementing CPU-bound computations in .NET and running them in-process with node.js application without blocking the event loop,
  • using C# and .NET instead of writing native node.js extensions in C/C++ and Win32 to access Windows specific functionality from a node.js application.

Owin is a native node.js module for Windows. It hosts OWIN handlers written in .NET 4.5 (think C#) in a node.js application. Owin allows integration of .NET code into express.js applications by providing a connect wrapper around OWIN .NET handlers. Owin also provides an easy way to run CPU bound computations implemented in .NET without blocking the node.js event loop.

Read more about the background and motivations of the project here.

What you need

  • Windows x64
  • node.js 0.8.x x64 (developed and tested with v0.8.19)
  • .NET 4.5

How to: express.js request handler in .NET

First get the owin module and express.js:

npm install owin
npm install express

Implement your Startup.cs OWIN handler in C# as follows:

using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Threading.Tasks;

namespace OwinHelloWorld
{
    public class Startup
    {
        public Task Invoke(IDictionary<string, object> env)
        {
            env["owin.ResponseStatusCode"] = 200;
            ((IDictionary<string, string[]>)env["owin.ResponseHeaders"]).Add(
                "Content-Type", new string[] { "text/html" });
            StreamWriter w = new StreamWriter((Stream)env["owin.ResponseBody"]);
            w.Write("Hello, from C#. Time on server is " + DateTime.Now.ToString());
            w.Flush();

            return Task.FromResult<object>(null);
        }
    }
}

Compile it to OwinHelloWorld.dll with:

csc /target:library /out:OwinHelloWorld.dll Startup.cs

Then in your server.js, create an express.js application and register two handlers. One is implemented in JavaScript, and the other uses the Owin module to load the .NET handler in OwinHelloWorld.dll:

var owin = require('./lib/owin.js')
	, express = require('express');

var app = express();
app.use(express.bodyParser());
app.all('/jazz', owin('OwinHelloWorld.dll'))
app.all('/rocknroll', function (req, res) {
	res.send(200, 'Hello from JavaScript! Time on server ' + new Date());
});

app.listen(3000);

Now start your server:

node server.js

(Make sure OwinHelloWorld.dll is in the current directory, or specify the full file path to it in the call to the owin() function in your server.js)

Now open the web browser and navigate to http://localhost:3000/jazz. Welcome to .NET!

jazz

Now navigate to http://localhost:3000/rocknroll. Hello JavaScript!

rocknroll

How to: CPU-bound in-process worker

This is how you can execute CPU-bound code written in .NET within the node.js process without blocking the node.js event loop. Read more about the scenario and goals here.

First install the owin module with:

npm install owin

Then implement your CPU bound code in .NET and save it to Startup.cs:

namespace CalculateBudget
{
    public class Startup : Owinjs.Worker
    {
        protected override IDictionary<string, string> Execute(IDictionary<string, string> input)
        {
            int revenue = int.Parse(input["revenue"]);
            int cost = int.Parse(input["cost"]);
            int income = revenue - cost;

            Thread.Sleep(5000); // pretend it takes a long time

            return new Dictionary<string, string> { { "income", income.ToString() } };
        }
    }
}

The Execute method can conatin any long-running, CPU-blocking code. You can accept a dictionary of strings as input and return another dictionary of strings as the result of the computation.

Now compile the .NET into a CalculateBudget.dll (the name of the assembly should by convention match the namespace name and reference the Owinjs.dll included with the owin module:

copy node_modules\owin\lib\clr\Owinjs.dll
csc /target:library /r:Owinjs.dll /out:CalculateBudget.dll Startup.cs

Lastly implement your node.js application that imports the owin module and calls into the blocking .NET code from CalculateBudget.dll:

var owin = require('owin')

console.log('Starting long running operation...');
owin.worker(
    'CalculateBudget.dll',
    { revenue: 100, cost: 80 },
    function (error, result) {
        if (error) throw error;
        console.log('Result of long running operation: ', result);
    }
);

setInterval(function () { 
    console.log('Node.js event loop is alive!')
}, 1000);

Save the file as test.js and run it with node test.js. You will see output similar to this one:

C:\projects\owin_test>node test.js
Starting long running operation...
Node.js event loop is alive!
Node.js event loop is alive!
Node.js event loop is alive!
Node.js event loop is alive!
Node.js event loop is alive!
Result of long running operation:  { income: '20' }
Node.js event loop is alive!
Node.js event loop is alive!

This proves that the node.js event loop is not blocked while the CPU-bound computation runs on a CLR thread separate from the main event loop thread in node.js.

How to: debugging

You can debug the .NET code running as part of your node.js application by attaching a managed code debugger(e.g. Visual Studio) to node.exe. Since the node.exe process runs both native and managed code, make sure to select the appropriate language to target:

debug

How to: exceptions

Exceptions thrown within the .NET code are propagated to the calling node.js application and re-thrown there by the owin module. For example:

C:\projects\owin_test>node test.js
Starting long running operation...

C:\projects\owin_test\test_worker.js:8
                if (error) throw error;
                                 ^
System.AggregateException: One or more errors occurred. ---> System.Exception: Sample exception
   at CalculateBudget.Startup.Execute(IDictionary`2 input)
   at Owinjs.Worker.<>c__DisplayClass1.<Invoke>b__0()
   at System.Threading.Tasks.Task.Execute()
   --- End of inner exception stack trace ---
---> (Inner Exception #0) System.Exception: Sample exception
   at CalculateBudget.Startup.Execute(IDictionary`2 input)
   at Owinjs.Worker.<>c__DisplayClass1.<Invoke>b__0()
   at System.Threading.Tasks.Task.Execute()<---

In case of express request handlers written in .NET, express framework will return them back to the browser client. For example:

exception

More

Issues? Feedback? You know what to do. Pull requests welcome.

About

Hosting .NET OWIN applications in node.js

Resources

Stars

0 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors