DotNetCurry Logo

Building Node.js Applications in Visual Studio (MEAN stack)

Posted by: Ravi Kiran , on 8/5/2014, in Category Node.js
Views: 85669
Abstract: NTVS is an open source plugin that turns Visual Studio into a Node.js IDE. In this article, we will build a Movie list application using Node.js, Express.js, Mongo DB and Angular JS in Visual Studio

Ryan Dahl introduced Node.js in his talk at JSConf 2009 and his talk received a standing ovation from the audience. Node.js is not a JavaScript library; it is a platform for creating web applications on the server side, using JavaScript. Built with C++ and JavaScript, Node.js uses V8 (JavaScript engine that comes with Chrome) as its engine to process JavaScript on the server. Using Node.js, one can quickly build and run a web application within a few minutes. Node.js works the same way as JavaScript works on any modern browser.

Node.js is event based and asynchronous. It assumes that all I/O operations are slow. So, they are all executed asynchronously. This makes execution of server, non-blocking.

This article is published from the DotNetCurry .NET Magazine – A Free High Quality Digital Magazine for .NET professionals published once every two months. Subscribe to this eMagazine for Free and get access to hundreds of free tutorials from experts

Node executes every operation as an Event. Events are executed in an event loop. The server has only one thread to execute all the operations. Event loop keeps listening to the server events. When it encounters an asynchronous event like fetching data from a database, the operation is performed outside the event loop. Event loop then frees up the thread and responds to any other event that comes in. Once the asynchronous operation (here assuming it is fetching data from a database) completes, the Event loop receives a message about its completion and the result is processed once the event loop is free.

The pipeline of Node.js is very light weight. Unlike other server technologies, Node.js doesn’t have a lot of components installed by default. It has just the right number of components to start the server. Other components can be added as they are needed.

Pre-requisites:

In this article, we will build a Movie list application using Node.js, Express.js, Mongo DB and Angular JS on Visual Studio. I have used Windows 7 64-bit and Visual Studio 2013 Ultimate to develop the sample. You can use any OS that supports Visual Studio 2012 or 2013. Node Tools for Visual Studio can be used with Visual Studio 2012 Web Developer Express, Visual Studio 2013 Web Developer Express, or any paid versions of Visual Studio 2012 or 2013 (Professional, Premium or Ultimate).

As for the pre-requisites, you must have the following tools installed on your system:

1. Visual Studio 2012 or 2013

2. Node.js

3. NodeJS tools for Visual Studio (NTVS)

4. Mongo DB

The first three installations are straight forward. You just need to download and install the tools. For Mongo DB, you will get a zip file containing a set of binaries. Extract the zip to any location. I prefer it to be inside D:\MongoDB\bin. Once extracted, follow these instructions:

- In the folder named MongoDB, create a folder named ‘data’ and inside this folder, create another folder and name it ‘db’

- Now go to the D:\MongoDB\bin folder and create a text file. Change name of the text file as ‘mongod.conf’ and paste the following statements in it:

dbpath = D:\MongoDB\data\db
logpath = D:\MongoDB\mongo-logs.log
logappend = true

Feel free to modify dbpath and logpath as per the path in your system.

- Run the command prompt as ‘Run as administrator’, change path to the bin folder of MongoDB on your system and run the following commands:

c:\Mongodb\bin\mongod.exe --config c:\MongoDB\mongod.conf --install
net start mongodb

Once these commands are executed, MongoDB is up and running on your system as a service.

Building a Movie List Application

Open Visual Studio 2012 or 2013 and choose File > New > Project. If you have installed Node tools for Visual Studio, you must be able to see the Node.js option under JavaScript and a number of project templates for creating Node.js application as shown in Figure 1:

nodejs-project-types

Figure 1: Node.js templates in Visual Studio

What’s in the template?

From the list, choose Blank Node.js Web Application and change the name to ‘NodeMovieList’. Once the project is created, observe the structure of the project in the Solution Explorer. You will find the following items:

  • npm: Displays the node.js packages installed in the project. As we started with an empty project, it doesn’t show anything as of now
  • package.json: This file contains the list of Node.js packages and their versions needed by the project. It is similar to packages.config file used with NuGet
  • server.js: This file is the starting point for the Node.js application. It defines the port on which the application has to run, contains calls to any middle wares required and defines actions for routes

If you check the server.js file, it has a very simple response defined. It sends Hello World in response to any incoming request. Run the application now and you will see a “Hello World” on your browser. When the application is running, you will see a console popping up. It is not a console created by Visual Studio, it is the console installed with Node.js.

Debugging server.js in Visual Studio

We can place a breakpoint in the server.js file and debug the file just as we debug C# code files.

debugging-nodejs

Figure 2: Debugging server.js in Visual Studio

All variables and objects in the code can also be inspected as seen in Figure 3:

nodejs-variable-inspection

Figure 3: Viewing contents of an object

Our favourite Visual Studio debugging window namely Locals, Immediate Window, Call Stack and Watch window can also be used:

debug-windows

Figure 4: Visual Studio Debugging windows

 

Getting Express.js

The code in the server.js file doesn’t do anything more than just starting a server on a specified port and writing some plain text to it. One can follow the same technique to respond with HTML, JSON or any type of data in response. But, this is done at a very low level. To write more complex applications, we need an abstraction layer that would make our job easier. To do so, we have a popular server framework called Express.js. Express has a number of middle wares defined that can be added to the Node.js pipeline to build robust applications. Express.js can be installed in the project using NPM.

NPM packages can be installed using either command line or using the GUI provided by Visual Studio. Node.js tools are smart enough to detect any package installed in the application, irrespective of the way you chose to install and list them under the NPM node in the Solution Explorer.

Right click on NPM and choose Manage NPM Packages.

node-package-manager

Figure 5: NPM Package Manager

Using the above dialog, we can do the following:

- View all local NPM packages under the ‘Local Packages’ tab. Any package installed using the dialog when Local Packages is selected, gets installed locally in the project

- View Packages installed globally. These packages are available for all Node.js applications. Any package installed when under ‘Global packages’ tab, is installed globally

- If you know the name and version of the package to be installed, you can specify the details in them under “Specify Package Details” tab and install it

- You can search for a package and install its latest version using the ‘Search npm Repository’ tab

- Using the ‘Install As’ drop down (at the bottom), the package can be installed either as:

  • Standard dependency: Package gets listed in package.json file and will be installed automatically if any of the mentioned packages is missing when the project is opened in Visual studio
  • Dev dependency: Package gets listed under devDependencies in package.json. These packages are installed and used only during development
  • Optional dependency: Package is listed in optionalDependency. These packages are not mandatory for the application

Let’s install express.js as a standard dependency locally. After installing the package, notice the Solution Explorer after installing the package. Express depends on a number of other packages; they are all installed and displayed under the express package.

express-package-dependencies

Figure 6: Express.js and dependencies

Along with it, we need to install another NPM package body-parser which is a Node.js body parsing middleware. Once done with this, replace the code in server.js with the following:

var http = require('http');
var express = require('express');
var bodyParser = require('body-parser');

var port = process.env.port || 1337;

var app = express();
app.use(bodyParser());

app.get('/', function (request, response) {    
response.send("This response is generated from Express router!!");
});

app.listen(port);

Editorial Note: Use bodyParser with caution as it contains a vulnerability using which attackers can fill up your disk space by creating an unlimited number of temp files on the server. For a possible solution check http://andrewkelley.me/post/do-not-use-bodyparser-with-express-js.html

The above code starts the Node.js server at port 1337 and when it gets a request at the home URL, it responds with the HTML we specified in response.send. Instead of creating the server on our own using HTTP, we are now relying on express.js to do that.

Let’s add an HTML page to the site and use it in response to the request to the home URL. Add a new folder to the project and change its name to ‘views’. In this folder, add a new HTML file and change its name as ‘MoviesList.html’ and place the following mark-up in the file:





    
    


    Node-Express Movie List



Now modify the response to home URL as:

app.get('/', function (request, response) {
    response.sendfile("views/MoviesList.html");
});

Now modify the response to home URL as:

app.get('/api/list', function (request, response) {
    response.send(
        { "movieId": 1, "name": "The Pacific Rim" },
        { "movieId": 2, "name": "Yeh Jawani Hai Deewani" });
});

Save and run the application. You will see the MoviesList.html getting rendered in your browser.

Let’s create a simple REST API that sends some JSON data back to the client. Add the following snippet to server.js:

app.get('/api/list', function (request, response) {
response.send(
{ "movieId": 1, "name": "The Pacific Rim" },
{ "movieId": 2, "name": "Yeh Jawani Hai Deewani" });
});

In your browser, enter the URL http://localhost:1337/api/list. You will see that the JSON data sent above gets displayed on the browser. Similarly, you can create APIs for POST, PUT, DELETE or PATCH by replacing get in the above snippet with the corresponding method.

But working with hard-coded in-memory objects is no fun. Let’s use storage instead. With Node.js, it is preferred to use a NoSQL database rather than a traditional RDBMS based database. This is because most of the NoSQL databases work directly with JSON and the framework doesn’t have to worry about converting the data. MongoDB is the most widely used database with Node.js. Let’s briefly look at MongoDB before we start using it in our application.

Introduction to Mongo DB

Mongo DB is a NoSQL database. It stores data in the form of BSON (Binary JSON) documents. Unlike traditional RDBMS databases, NoSQL databases need not know about the structure of the data stored in them. The same holds true for MongoDB as well. MongoDB needs a folder to be mapped with, where it creates files to store the data.

To continue further, install and setup MongoDB (if you haven’t already) by following the instructions specified at the beginning of this article.

Now, open a command prompt and move to the folder where the binaries of MongoDB are located and run the command mongo

>mongo

To check which database we are connected to, just type db and hit enter.

>db

test

So ‘test’ is the default database used by MongoDB. To create a DB, just type use followed by the DB name you would like to create:

>use studentDb

use does one of the two things:

  • If the DB exists, it points to the DB
  • If the DB doesn’t exist, it creates the DB and then points to it

If you run the db command now, you should see studentDb. In MongoDB we don’t create tables; rather, we create collections. To see how to create a collection and work with it, let’s create a collection to store student information. The commands that we write in MongoDB don’t look like SQL commands. They look like function call chains or LINQ queries. The following statement creates a collection and adds data to it:

>db.students.insert({"studentId":1,"name":"Ravi"})

Let’s see if the collection is created and if it has any data in it:

>show collections  : Lists all collections in the current DB

>db.students.find()  : Shows contents of the collection students

Now insert another row, with a different structure:

>db.students.insert({"studId":2,"firstname":"Harini","lastname":"Kumari","dob":"05-29-1987","occupation":"Govt Employee”})

To check data in the collection, we have to execute the find() function on the collection:

>db.students.find()

As you see, to identify each entry in the collection, MongoDB adds the property _id and assigns a unique value to it. To remove all entries from the collection, execute the following command:

>db.students.remove()

Now you have some basic idea on how to use MongoDB. This understanding is just enough to continue further. If you want to master MongoDB, check the documentation on their official site.

Interacting with MongoDB from Node.js

Like any other DB, we need a driver to interact with MongoDB from Node/Express. The most popular Node.js driver for MongoDB is Mongoose. It can be installed from NPM. Let’s use the command line to install this package:

npm install mongoose --save

Check the NPM node in the Solution Explorer. You should be able to see the new package there. NTVS (NodeJS tools for Visual Studio) is smart enough to detect any new NPM package and immediately display it in the IDE.

Create a new folder and change the name of the folder as ‘server’. We will place our server code in this folder, to keep the code separated. Add a new JavaScript file to this folder and change the name to ‘MongoOperations.js’. To work with Mongoose, just like the other packages, we need to load the module using require:

var mongoose = require(‘mongoose’);

To connect to a database, we need to invoke the connect method with a url:

mongoose.connect(“mongodb://localhost/moviesDb”);
var db=mongoose.connection;

If the DB doesn’t exist yet, MongoDB will create it for us. Mongoose is almost like an ORM. It needs schema of the data to work with a collection stored in MongoDB. This doesn’t sound good, because it induces the strictness that the database itself doesn’t have. But, it still is the most popular driver for MongoDB for Node.js.

Let’s create a schema to store details of the movies. Each movie would have three fields: name of the movie, a Boolean field showing if the movie is released and a Boolean field showing if you have watched it already.

var movieSchema = mongoose.Schema({
    name: String,
    released: Boolean,
    watched: Boolean
});
var MovieModel = mongoose.model('movie', movieSchema);

Notice that I didn’t add an ID field to the collection; we will use the _id field that is automatically added by MongoDB.

When the application runs for the first time, the collection wouldn’t have any value. Let’s seed some data into the collection if the collection is empty. We can do it by listening to the open event on the database object created above.

db.on('error', console.error.bind(console, "connection error"));
db.once('open', function () {
    console.log("moviesDb is open...");

    MovieModel.find().exec(function (error, results) {
        if (results.length === 0) {
            MovieModel.create({ name: "The Amazing Spider-Man 2", released: true, watched: false });
            MovieModel.create({ name: "The Other Woman", released: true, watched: true });
            MovieModel.create({ name: "Shaadi ke Side Effects", released: false, watched: false });
            MovieModel.create({ name: "Walk of Shame", released: true, watched: false });
            MovieModel.create({ name: "Lucky Kabootar", released: false, watched: false });
        }
    });
});

Before adding data to the collection, we are checking if the collection already has any data to prevent duplicates. You can replace names of the movies with your favourite ones J.

Also, notice the pattern of execution of the find() method in the above snippet. The method exec() is executed asynchronously. The first parameter that it sends to its callback is error, which is set in case the operation fails. The second parameter is the result of the operation. All asynchronous operations in Node.js follow the same pattern.

In the application, we will perform the following operations on movies:

1. Adding a new movie

2. Listing movies

3. Modifying released and watched status of the movie

As a first step, add require statement to server.js to include MongoOperations.js:

var mongoOps = require('./server/MongoOperations.js');

Following are the REST API methods that respond to GET, POST and PUT operations on movies collection:

app.get('/api/movies', mongoOps.fetch);

app.post('/api/movies', mongoOps.add);

app.put('/api/movies/:movieId', mongoOps.modify);

We are yet to define the fetch, add and modify methods in MongoOperations.js. To get the list of movies in the DB, we need to invoke find() method. Similarly to add a new movie, we need to invoke the create() method on the Mongoose model. The add() method looks like the following:

exports.fetch = function (request, response) {
    MovieModel.find().exec(function (err, res) {
        if (err) {
            response.send(500, { error: err });
        }
        else {
            response.send(res);
        }
    });
};

exports.add = function (request, response) {
        var newMovie = { name: request.body.name, released: false, watched: false };
        MovieModel.create(newMovie, function (addError, addedMovie) {
            if (addError) {
                response.send(500, { error: addError });
            }
            else {
                response.send({ success: true, movie: addedMovie });
            }
        });
};

Similarly, for modifying we need to call the update() method. But this method needs a condition to be applied to fetch rows to be updated and to check if the update is on multiple rows.

exports.modify = function (request, response) {
    var movieId = request.params.movieId;
    MovieModel.update({ _id: movieId }, { released: request.body.released, watched: request.body.watched }, { multi: false },
        function (error, rowsAffected) {
            if (error) {
                response.send(500, { error: error });
            }
            else if (rowsAffected == 0) {
                response.send(500, { error: "No rows affected" });
            }
            else {
                response.send(200);
            }
        }
    );
};

With this, we are done with our work on server side. Let’s build the client components now.

Design a HTML Page for Movie List

I chose Angular to write the client-side JavaScript for several good reasons. Angular JS makes it easy to interact with REST APIs and data binding support that it brings in, is a cool breeze. You can refer to articles in older versions of DNC Magazine to learn more on Angular JS (January 2014 edition for Angular JS with ASP.NET MVC and May 2014 edition for Writing Angular code with TypeScript).

The UI would be a simple HTML page that has the following components:

  • a textbox to accept name of new movie that you want to watch
  • one column listing released movies
  • another column listing upcoming movies

Dividing the movies into two sets is very easy if you use Angular’s filters with repeater binding. Following is the HTML mark-up of the page:




    
    Node-Express Movie List
    
    



    

Node-Express Movie List

Released Movies

  {{movie.name}}

Coming Up...

{{movie.name}}

Add a folder to the application and change the name to ‘public’. This folder would contain all static resource files like JavaScript files, CSS styles for the application. In this folder, add two more folders and name them ‘styles’ and ‘scripts’. We will add scripts and styles to make our HTML page look similar to the one shown in Figure 7:

node-express-movie-list

Figure7: Node-Express Movies List

While referring static files in the HTML page, we didn’t include the folder path ‘public’ in it; we need to add the following statement to the server.js to automatically prepend ‘public’ to the path of the static files:

app.use(express.static(path.join(__dirname, 'public')));

You can copy the CSS from the downloadable demo app. Let’s write the client script to interact with the Node.js API.

 

Angular JS Script to consume REST API and bind data

Create a module and add a factory to interact with the REST API using $http. The service would contain methods to get, update and add movies.

var app = angular.module('moviesApp', []);

app.factory('moviesCRUD', function ($http, $q) {
    function getAllMovies() {
        var deferred = $q.defer();

        $http.get('/api/movies').then(function (result) {
            deferred.resolve(result.data);
        }, function (error) {
            deferred.reject(error);
        });

        return deferred.promise;
    }

    function addMovie(newMovie) {
        var deferred = $q.defer();

        $http.post('/api/movies', newMovie).then(function (result) {
            deferred.resolve(result.data.movie);
        }, function (error) {
            deferred.reject(error);
        });

        return deferred.promise;
    }

    function modifyMovie(updatedMovie) {
        var deferred = $q.defer();

        $http.put('/api/movies/' + updatedMovie._id, updatedMovie).then(function (data) {
            deferred.resolve(data);
        }, function (error) {
            deferred.reject(error);
        });

        return deferred.promise;
    }

    return {
        getAllMovies: getAllMovies,
        addMovie: addMovie,
        modifyMovie: modifyMovie
    };
});

and finally, we need a controller to respond to the actions on the page. The actions include:

  • Getting list of movies at the beginning
  • Marking a movie’s status as released
  • Marking a movie’s status as watched or not watched
  • Add a new movie
app.controller('MoviesCtrl', function ($scope, moviesCRUD) {
    $scope.released = { released: true };
    $scope.notReleased = { released: false };
    
    function init() {
        moviesCRUD.getAllMovies().then(function (movies) {
            $scope.movies = movies;
        }, function (error) {
            console.log(error);
        });        
    }

    $scope.movieReleased = function (movie) {

        moviesCRUD.modifyMovie({ _id: movie._id, name: movie.name, released: true, watched: movie.watched })
                  .then(function (result) {
                      if (result.status === 200) {
                          movie.released = true;
                      }
                  }, function (error) {
                      console.log(error);
                  });        
    };

    $scope.movieWatched = function (movie) {
        moviesCRUD.modifyMovie(movie)
                  .then(function (result) {
                      if (result.status === 200) {
                          console.log("Movie updated");
                      }
                  }, function (error) {
                      movie.watched = !movie.watched;
                  });        
    };

    $scope.addMovie = function () {
        moviesCRUD.addMovie({ name: $scope.newMovieText }).then(function (newMovie) {
            $scope.movies.push(newMovie);
            $scope.newMovieText = "";
        }, function (error) {
            console.log(error);
        });        
    };

    init();
});

And that’s our end-to-end application using NodeJS.

Deploying NodeJS applications on IIS

Now that we have built a small end-to-end application using NodeJS, let’s deploy it to a server to keep it running all the time. Internet Information Services (IIS) doesn’t support deploying NodeJS applications by default, as IIS doesn’t understand NodeJS. To make it understand, we need to install an IIS module. IISNODE is an open-source project that makes it possible to host NodeJS applications on IIS. You can download and install the module from its Github page. Download the installer that suits your system requirements and install the setup. The installer adds a new module to IIS. You should be able to see it in the list of modules in your local IIS:

iisnode-module

Figure 8: IIS Modules list containing iisnode

Process of deploying a NodeJS application in IIS is somewhat similar to that in case of ASP.NET. We need to have a web.config file added to the folder. Add a file to the project and change its name as web.config. First and the most important configuration is to add the server JavaScript file as an HttpHandler.


  
    
      
    
  


The web server may receive a request for either static content or a dynamic content. The web.config file should be able to show the right direction to IIS so that the request would be sent to the right destination. The following URL rewriting rules are used for this purpose:


  
    
      
    
    
      
        
      
      
            
  


But this rule doesn’t work for HTTP PUT requests by default. We need to add the following configuration under system.webServer to make it work:


  


Now you can deploy the application to IIS like any other ASP.NET application. Open IIS, right click on Default Web Site and choose Add New Application:

iis-add-application

Figure 9: Adding new application in IIS

Enter the name and select the physical location of the NodeJS application to be deployed. Physical path of the folder should be the one that contains the web.config file. Choose an application pool of your choice and click OK.

iis-application-details

Figure 10: Configuring path and application pool in IIS

Browse the application in your favorite browser and you should be able to see the same screen as you saw earlier.

Conclusion

We saw how Node.js Tools for Visual Studio makes it easy to develop an end-to-end JavaScript application in Visual Studio. As you keep using it, you will find the value that this toolset brings in. You may also face some difficulties as the toolset is still in beta. But Node as a platform has a huge community and the ecosystem is growing by heaps. Though Visual Studio was a .NET IDE till sometime back, Microsoft has been investing a lot of time and resources to make it single IDE for developing almost anything you can think of. NTVS is one such project that demonstrates this effort from Microsoft. IISNODE brings NodeJS closer to .NET developers by making it possible to deploy the NodeJS apps on IIS. IISNODE is used by hosting providers like Azure to support hosting of NodeJS application easier.

It’s Open Source, it’s awesome, and it now comes with.NET. What else do you need to get started?

Download the entire source code from our GitHub Repository at bit.ly/dncm13-nodejs

Was this article worth reading? Share it with fellow developers too. Thanks!
Share on Google+
Further Reading - Articles You May Like!
Author
Rabi Kiran (a.k.a. Ravi Kiran) is a developer working on Microsoft Technologies at Hyderabad. These days, he is spending his time on JavaScript frameworks like AngularJS, latest updates to JavaScript in ES6 and ES7, Web Components, Node.js and also on several Microsoft technologies including ASP.NET 5, SignalR and C#. He is an active blogger, an author at SitePoint and at DotNetCurry. He is rewarded with Microsoft MVP (Visual Studio and Dev Tools) and DZone MVB awards for his contribution to the community


Page copy protected against web site content infringement 	by Copyscape




Feedback - Leave us some adulation, criticism and everything in between!
Comment posted by sm on Saturday, August 23, 2014 3:10 PM
excellent article - great job ravi (sean from ntvs project)
Comment posted by Ravi on Tuesday, September 2, 2014 11:41 AM
Thanks Sean!
Comment posted by Ashley Chapman on Monday, October 13, 2014 9:40 AM
Excellent article, thank you.

Two little errors:-
I found that the command to install mongodb as a service is not "mongod.exe -f mongod.conf –service", but "d:\Mongodb\bin\mongod.exe --config d:\MongoDB\mongod.conf --install".  Well this is for mongodb version 2.6.5.
NB. Both --config and --install have TWO hyphens.

The link to NTVS points to a file on your hard-drive.
Comment posted by Ravi on Tuesday, October 14, 2014 11:55 AM
Ashley,
Thanks for pointing the errata. We will get them corrected.
Comment posted by Suprotim on Wednesday, October 15, 2014 10:27 PM
Thanks Ashley and Ravi. The errors have been fixed!
Comment posted by Rohit on Sunday, November 9, 2014 1:59 AM
Thanks for this nice post.
Comment posted by Cristian on Sunday, March 1, 2015 1:21 PM
I think you're missing something. How do you add AngularJs to the project?
Comment posted by Ravi on Monday, March 2, 2015 11:57 AM
Cristian,
To keep the article simple, I loaded Angular and Bootstrap from CDN. Check references in the HTML file, you will find them there.
Comment posted by Stas Ustimenko on Wednesday, April 22, 2015 7:09 AM
I prefer to use Codelobster: http://www.codelobster.com