Neil Mackenzie is an Azure Architect for Satory Global. He has worked with computers for nearly three decades. Neil started by doing large-scale numerical simulations for scientific research and business planning. Since then, he has primarily been involved in healthcare software, developing electronic medical record systems. He has been using Microsoft Azure since PDC 2008, and has used nearly all parts of the Azure platform — including those parts that no longer exist. Neil is a Microsoft MVP for Azure. Neil is a DZone MVB and is not an employee of DZone and has posted 16 posts at DZone. You can read more from them at their website. View Full User Profile

Node.js, Windows Azure (and socket.io)

10.21.2012
| 2933 views |
  • submit to reddit

The Windows Azure Platform now supports various application-hosting environments including:

.NET has always been the primary development environment for Windows Azure. Java and PHP have been around for many years and applications developed in these environments have been deployable to Windows Azure for some time.

Node.js is a lightweight platform, developed by Ryan Dahl (@ryah), for building highly-scalable network applications written in JavaScript. In particular, it can be used to develop and deploy web servers. socket.io is a Node.js package that provides a simple way to access HTML5 web sockets thereby facilitating the creation of applications supporting browser-to-browser conversation. The Node.js documentation is here.

This post is a brief introduction to Node.js and socket.io with that introduction being focused on the implementation of Node.js inside the Windows Azure environment.

Node.js

Node.js is an application hosting environment developed in C++ and using the Google V8  JavaScript engine to host applications written in JavaScript. An essential feature of applications written in Node.js is the heavy use of callbacks making support for an asynchronous programming model more natural. Node.js can be downloaded directly from the Node.js website.

Hello World in Node.js

The following example demonstrates how easy it is to write a website serving a single Hello World web page.

var port = 81;
var http = require('http');

var app = http.createServer(function (req, res) {
  res.writeHead(200, {‘Content-Type’: ‘text/plain’});
  res.end(‘Hello World\n’);
});

app.listen(port);
console.log(‘Server running on port ‘ + port);

When the above code is saved in a file named server.js the following command can be used to launch the web server:

node server.js

The require() statement imports the Node.js http module into the application where it is used to create an HTTP server. The parameter to the createServer() method is an anonymous callback function invoked each time the server receives a request. This callback is passed the request and response streams for the request. In the example, a response header is added before res.end() is invoked to write Hello World to the response and flush the response back to the client. app.listen() starts the server listening on port 81.

This simple program demonstrates several features common to Node.js applications:

  • the use of require()to import modules into the application
  • the creation of a server
  • the use of listen() to start the listening process
Application Frameworks

A web application can be coded directly in JavaScript and deployed as a website hosted in Node.js. As in other web-development environments it is common to use an application framework to structure the application and enforce a separation of concerns that aids the development of large-scale applications.

Many Node.js samples use the Express framework. This uses routes and views directories to store application routes and views. Express supports various view engines including Jade and EJS(embedded JavaScript). These provide different ways to specify the appearance of a web page.

The following commands can be invoked to download the Express module and create a default Node.js web server using the Express framework and the Jade view engine:

npm install express
.\node_modules\.bin\express
npm install

node app.js

This starts a web server, listening on port 3000, which responds with the web page defined in views\index.jade.

Node Package Manager (NPM)

The Node Package Manager (NPM) is an application that simplifies the local installation for the thousands of packages that have been created for Node.js. NPM stores downloaded packages in a node_modules folder under the invocation directory. It is possible to specify that downloaded packages be stored globally but, in general, they should be regarded as part of the application they are being used in and stored locally (which is the default).

The package.jsonfile associated with a downloaded package specifies dependencies on other packages that it may have. NPM recursively downloads these dependent packages into a node_modules directory associated with the initial package. The NPM is invoked as follows:

npm install packageName

Windows Azure

Microsoft supports Node.js as a first-class development environment for Windows Azure. The Windows Azure developers portal has a section devoted to Node.js that contains various samples and a download link for the Windows Azure SDK for Node.js.

The SDK is installed in the following directory:

%ProgramFiles(x86)%\Microsoft SDKs\Windows Azure\Nodejs

The installation process creates a link on the Start menu for the Windows Azure PowerShell for Node.js which launches a PowerShell console with the Windows Azure Node.js cmdlets preloaded. These cmdlets can be used to manage the creation and deployment of hosted services both in the development and Windows Azure environment. As is typical with Windows Azure development environments, the PowerShell console should be launched using Run as Administrator.

The cmdlets include the following:

  • New-AzureService serviceName
  • Add-AzureNodeWorkerRole roleName
  • Add-AzureNodeWebRole roleName
  • Start-AzureEmulator
  • Stop-AzureEmulator

These can be used sequentially to create a Windows Azure hosted service with zero or more web and worker roles and then deploy them to the compute emulator before tearing down the service. The developer portal has a sample that does precisely this. Other cmdlets support the deployment of the hosted service to Windows Azure.

Web Roles and Worker Roles

The Windows Azure SDK for Node.js implements web and worker roles in different ways leading to differences in the supported functionality. Specifically, since http.sys does not support HTML5 web sockets it is not possible to use them in a Node.js (or any) application deployed to a web role. Web sockets are supported for Node.js (or any) application deployed to a worker role. One benefit of using a web role is that, as shown by Aaron Stannard (@Aaronontheweb) in this post, IIS can handle the launching of multiple node.exe instances automatically. Otherwise, Node.js would only be able to use a single core, even in a multi-core instance.

A web role is implemented using a special IISNode module which is loaded as additional ASP.NET module in IIS. When creating a Windows Azure package for deployment, the packager creates a startup task to perform various tasks including installing IISNode in the web role instance. In the development machine, IISNode is installed in:

%ProgramFiles(x86)%\Microsoft SDKs\iisnode

A worker role is implemented using the new ProgramEntryPoint functionality exposed in ServiceDefinition.csdef which allows an arbitrary program to be specified as the role entry point. Specifically, on startup a worker role hosting a Node.js application invokes the following program entry point:

node.exe .\server.js

An obvious implication is that the Node.js application must be in a file named server.js – although it can import additional modules.

It is remarkably easy to port a Node.js application to Windows Azure. A particularly impressive sample on the Windows Azure developer portal takes a standard example from the socket.io website and ports it to Windows Azure by changing only two lines of code. One change is simply to the location of a module while the other is the specification of the port to listen on in a Windows Azure friendly manner. Specifically, when using Windows Azure SDK for Node.js it is necessary to specify the listening port using:

process.env.port

which allows the application to access the correct Windows Azure endpoint.

Furthermore, it can sometimes be helpful to test Node.js applications directly, using node.exe, without launching the Windows Azure development environment. This is feasible because of the simple manner with which Node.js applications are inserted into the development environment.

Node.js Packages for Windows Azure

The Windows Azure SDK for Node.js does not provide access to the various Windows Azure SDKs. In keeping with the style of Node.js applications, this SDK is instead deployed as a set of Node.js packages for Windows Azure which are downloaded into a Node.js application using

npm install azure

The packages expose Node.js APIs for:

  • Windows Azure Storage Service (blobs, tables and queues)
  • Service Bus Brokered Messaging (queues, topics and subscriptions)

The Windows Azure developer portal has a complete example showing how to access Windows Azure Table service from a Node.js application developed using Express/Jade. When the azure packages are installed, examples of all the supported functionality are installed in the node_modules\azure\examples directory for the application.

Some Node.js on Windows Azure Links

Glenn Block (@gblock) has an interesting Channel 9 interview in which he describes Node.js on Windows Azure. Matt Harrington (@mh415) has a post describing the environment variables available when using the Node.js azure packages as well as a post showing how to log messages. Aaron Stannard has a post on using the Node.js packages for Windows Azure outside the compute emulator.

socket.io

Guillermo Rauch (@rauchg) developed socket.io, a Node.js package that simplifies the creation of web applications supporting real-time communication between browsers and devices. The github repository and documentation for socket.io is here. The canonical example of a socket.io application is a chat application supporting a conversation between clients.

socket.io supports various transports including:

  • web socket
  • html file
  • xhr-polling
  • jsonp – polling

By default, the transports are used in that priority and socket.io automatically degrades a connection when the transport is not supported. Web sockets are not supported by IIS so, as mentioned earlier, a worker role must be used if web socket support is desired for a socket.io application hosted in Windows Azure. Similarly, IE9 does not support web sockets so IE9 use again leads to a degraded connection. (Hint: the Chrome browser provides a better development experience since it does not suffer any connection degradation delay.)

socket.io implements the Node.js EventEmitter interface and so provides a nice demonstration of idiomatic Node.js. The EventEmitter interface comprises:

  • emitter.addListener(event, listener)
  • emitter.on(event, listener)
  • emitter.once(event, listener)
  • emitter.removeListener(event, listener)
  • emitter.removeAllListeners([event])
  • emitter.setMaxListeners(n)
  • emitter.listeners(event)
  • emitter.emit(event, [arg1], [arg2], [...])
  • Event: ‘newListener’
This interface supports the association of named events (or messages) with callbacks. Specifically, emitter.emit() sends a named event while emitter.on() listens for a named event and associates a callback with it. A socket.io application is created by the mutual exchange of named events between the client and the server.

A core sockets object manages connections. It handles a connection event by creating a socket object and passing that to the callback associated with the connection event. The socket object handles individual connections and listens for the disconnect event.  It also supports named events that contain the conversation messages providing the application functionality.

Simple Windows Azure Application using socket.io

A very basic socket.io application hosted in the Windows Azure development environment can be created as follows:

  • Start the Windows Azure PowerShell for Node.js console (using Run as Administrator)
  • cd to some directory
  • Type New-AzureService chat
  • Type Add-AzureNodeWorkerRole
  • cd WorkerRole1
  • Type npm install socket.io
  • Open server.js in some editor (e.g., Sublime Text 2) and replace the contents with the following:
// Import various modules and start listening for socket.io connections
var app = require('http').createServer(handler)
  , io = require('socket.io').listen(app)
  , fs = require('fs');

// Configure the port to run in the Windows Azure emulator
var port = process.env.port || 81;

// start listening for HTTP connections
app.listen(port);
 
// The handler function returns index.html to the browser
function handler (req, res) {
  fs.readFile(__dirname + '/index.html',  function (err, data) {
    if (err) {
      res.writeHead(500);
      return res.end('Error loading index.html');
    }
    res.writeHead(200);
    res.end(data);
  });
}

// Handle 'connection' events
io.sockets.on('connection', function (socket) {
  socket.emit('fromServer', { message: 'Connected' });

  socket.on('message', function (data) {
    socket.emit('message', { message: 'I sent: ' + data.message });
    socket.broadcast.emit('message', { message: data.message });
  });
});

Create a file named index.html (in the same directory) and copy the following into it:

<html>
<head>
<script src="/socket.io/socket.io.js"></script>
<script src="http://ajax.aspnetcdn.com/ajax/jQuery/jquery-1.7.1.min.js"></script>
<script>
var socket = io.connect(window.location);

socket.on('fromServer', function (data) {
    displayMessage(data.message);
});

socket.on('message', function (data) {
    displayMessage(data.message);
});

function sendMessage()
{
    socket.emit('message', { message: $('#MessageText').val() });
};

function displayMessage( message ) {
    $('#Output').append(message + '<br/>');   
};
</script>
<head>
<body>
Message:<input id="MessageText" type="text"/> 
<input type="button" value="Send message" onclick="sendMessage();"/>
<div id="Output">
<br/>
</body>
</html>

  • Type Start-AzureEmulator –launch

Start multiple browser windows pointing to http://localhost:81.

The UI is simple – with a message box, a Send message button and a status line below. After a few seconds, the status line should display Connected. When a message is typed in one of the message boxes and submitted, the status line in the current windows displays “Message forwarded” while the status line in the other windows displays the message text. Using the appropriate developer tools for the browser it is possible to find out the transport used for communication between the browser and the server.

  • Type Stop-AzureEmulator to shutdown the compute emulator.

This demonstration is very simple with the Node.js server serving up a simple web page to the browsers. The server listens for socket.io connections and on receiving one sends a connected message back to the client and sets up a socket listener for an event named message. On receiving such an event the socket responds by sending an event named fromServer with content Message forwarded back to the client and broadcasts an event named message, containing the message text, to all other clients. On loading, the browser connects to the server and, on connection, adds listeners for two events named fromServer and message. On receiving an event, the response is displayed in the status line. When the button is clicked, socket.emit() is invoked to send the message to the server.

This is a trivial demonstration that shows how easy it is to implement a Node.js application using socket.io inside Windows Azure. Mariano Vazquez uses an equally simple demonstration in a blog post in which he provides additional information about configuring the transport used by the connection.

 

 

 

 

 

 

 

Published at DZone with permission of Neil Mackenzie, author and DZone MVB. (source)

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)