Friday, 27 June 2014

Using Promises in NodeJS Apps

To separate logic of accessing data from the routes, we create separate modules to handle the task of data access. When I started learning Node.js, a common pattern that I saw in some samples to separate the data access logic from routing was as follows:

//Route
app.get(‘/api/students’, getAllStudents);

//In data access file
exports.getStudents = function(request, response){
  mongoDbObj.students.find().toArray(function(err, data){
    if(err){
      console.log(err); 
      response.send(500,{error: err});
    }
    else{
      console.log(data);
      response.send(data);
    }
  });
};


Though this approach separates the logic, we are dealing with request and response inside the data access logic. I am personally not a fan of this approach. But, we cannot return the data or error from the above function as we will get them asynchronously. This is where I started thinking of using promises to refactor the above function.

We have several promise libraries available for Node.js. These days, I am playing with Bluebird. It can be installed using npm.

One of the nice features that bluebird provides is, promisifying existing methods. To turn operations defined by an object into asynchronous, we need to pass the object inside the promisifyAll() method.


var Promise=require('bluebird');
var mongodb=Promise.promisifyAll(require('mongodb')); 


The above snippet creates asynchronous versions of each of the function created inside the object mongodb. Let’s convert some of the snippets from my previous post to use async. Code for establishing a connection to MongoDB changes to:

mongoClient.connectAsync('mongodb://localhost/studentsDb')    
           .then(function(db){
              console.log("Connected to MongoDB");
              mongoDbObj={
                db:db,
                students:  db.collection('students')
              };
            }, function(error){
                console.log(error);
            });


Let’s fetch details of all students and return the results asynchronously to the caller. On the result of calling find() method, we need to call the asynchronous method toArray() to convert data from documents to array. It makes sense to return a promise in such scenario as we can’t say when the result will be available. Following is the snippet for fetching data that returns a promise:

exports.getAllStudentsAsync=function(){
  return new Promise(function(resolve, reject){
    mongoDbObj.students.find()
              .toArray(function(err, result){
                 if(err)
                 {
                   reject(err);
                 }
                 else{
                   resolve(result);
                 }
            });
    });
};


Finally, the REST API that sends the student data to the browser changes to:

app.get('/api/students, function(request, response){
  mongoOps.getAllStudentsAsync()
          .then(function(data){
            response.send(data);
          }, function(err){
            response.send(500,{error: err});
          });
});


To me, this seems to be a cleaner approach as the request and response are sent to the model for manipulation. Feel free to express your opinions in the comments.

Happy coding!

Monday, 23 June 2014

Performing CRUD Operations on MongoDB in Node.js Application Using mongodb Driver

A NoSQL database is the go-to choice while writing applications using Node.js. In particular, MongoDB has got a lot of popularity in the community. Thanks to the awesome MEAN (MongoDB-Express-Angular-Node) stack, that makes everyone realize that an entire web app can be written using just one language (JavaScript).

There are a number of drivers created by the community to interact with MongoDB from a Node.js app. The official mongodb driver seems to be the simplest of them. Because, the JavaScript API it provides to interact with MongoDB is quite similar to the way one talks to MongoDB from console. In this post, we will learn to perform simple CRUD operations on a MongoDB document store using the mongodb driver.

We will be dealing with a set of students that is initially loaded with the following data:


{
 "studentId" : 1,
 "class" : 8, 
 "name" : "Ravi", 
 "marks" : [
  { "totalMarks" : 500, "percent" : 83.3 },
  { "totalMarks" : 510, "percent" : 85 } ], 
},
{ 
 "studentId" : 2,
 "name" : "Rupa", 
 "class" : 8, 
 "marks" : [
  { "totalMarks" : 570, "percent" : 95 },
  { "totalMarks" : 576, "percent" : 96 } ] 
}


To be able to work with the above data, we need to establish a connection with MongoDB first. Before that, we need to get the driver installed in the current project. Following command will install the driver when it is ran in the folder where the target Node.js project is located:

npm install mongodb

I prefer placing the code interacting with MongoDB in a separate file. As first thing, we need to get a reference to the MongoDB client and establish a connection:


var mongoClient=require('mongodb').MongoClient;
var mongoDbObj;

mongoClient.connect('mongodb://localhost/studentDb', function(err, db){
  if(err)
    console.log(err);
  else{
    console.log("Connected to MongoDB");
    mongoDbObj={db: db,
      students: db.collection('students')
    };
}


Retrieving values:

In the above connection URL, studentDb is name of the database. If the database doesn’t already exists, it is created automatically. I cached the students collection in the mongoDbObj object to avoid calling collections() over and over. Following statement fetches all students from the database:

mongoDbObj.students.find().toArray(function(err, data){
  if(err){
    console.log(err);
  else{
    //operate with the deta
  }
});


The find() method returns the objects in the form of documents. We need to convert the data obtained to a JavaScript array to operate with it easily. This is done by the toArray method.

Following are some examples showing using find with conditions:

mongoDbObj.students.find({studentId:1})    //Fetches the student with value of studentId 1
mongoDbObj.students.find({studentId:{$gte:2}})    //Fetches the student with value of studentId greater than or equal to 2
mongoDbObj.students.find({"marks.totalMarks":500})    //Fetches the student with at least one of the values of totalMarks 500
mongoDbObj.students.find({"marks.totalMarks":{$lte:500}})    //Fetches the student with at least one of the values of totalMarks less than or equal to 500


Inserting data:

Inserting data is a straight forward operation. It needs the object to be inserted, an optional options object and a callback to handle the success or failure.


mongoDbObj.students.insert(newStudent,{w:1},function(err, result){
  if(err){
    //Handle the failure case
  }
  else{
    //Handle the success case 
  }
});


The value of options object passed in above call to insert method is used to get acknowledgement of write operations.

Updating data:

Following statement replaces the matched object:

mongoDbObj.students.update({studentId:1},{name:”Ravi Kiran”},{w:1}, function(err, result){
    //Handle success and failure
});


The issue with the above approach is, as it does a full replace, there is a possibility of losing data of other fields in the matched record. Following statement updates the specified fields leaving unspecified fields untouched:

mongoDbObj.students.update({studentId:1},{$set: {name:”Ravi Kiran”}},{w:1}, function(err, result){
  //Handle success and failure
});


Deleting data:

Calling remove() method without any conditions deletes all records in a collection:


mongoDbObj.students.remove(function(err, result){
    //Handle success and failure
});


If a condition is passed in, it deletes the records that match the criteria:

mongoDbObj.students.remove({studentId:studentId},{w:1},function(err, result){
    //Handle success and failure
});
We will discuss more about MongoDB and Node.js in future posts.

Happy Coding!

Sunday, 8 June 2014

Expanding my Writing Zone

I started this blog as a novice blogger less than 2 years back and I had an amazing writing experience till now. I just can’t say enough about the accolades I received from the readers of this blog and also some constructive criticism that helped me in writing better. Thanks to each one of you that are reading this blog. I will continue writing good content here. In addition to writing for my blog, I started writing content for two of leading content publishers on the internet.

DotNet Curry Magazine:
DotNet Curry Magazine (DNC Magazine) is a free magazine for .NET developers around the world. It is started and ran by a set of technology experts including Suprotim Agarwal, a Microsoft MVP for ASP.NET/IIS. Suprotim is the Editor-in-chief for the magazine. The magazine releases an issue on every alternate month with high quality content on latest Microsoft Technologies. I am one of the thousands of subscribers to the magazine and I highly recommend subscribing to the magazine. The authors are MVPs and experts around the world. I am fortunate to have joined the team of authors. My first article for DNC was published during the May 2014 edition of the magazine and the article is now available on their website too, you can check it here. Stay tuned for lots of .NET content on DNC Magazine from all the authors.

Site Point:
Sitepoint is a very well-known site for many developers as a source of knowledge on several topics including HTML, CSS, JavaScript, Mobile, UX, Design and other topics. They publish articles, books, courses and also have forums for Q&A. I read several of their articles focussed on front-end web technologies. I contacted Sitepoint to know I could write for them and the editor-in-chief Ophelie Lechat accepted me as an author for their site. As most of you would have already guessed, I will be posting articles focused on JavaScript for Sitepoint. My first article for Sitepoint is published, you can read it here. Also check articles by other authors, they will help you for sure. I have a nice set of articles planned to be published for Sitepoint. Follow their twitter feed for tweets on their articles and also for technology news.

I was busy in initiating my work for these writing assignments and writing articles. So, I couldn't get enough time to blog. But, I have a nice series planned for this blog and you will see the posts popping up soon.

Happy coding!

Thursday, 8 May 2014

Building a Todo list application using Node.js and Express.js on Visual Studio

Some of you might have surprised to see the title containing Node, Express and Visual Studio together. Yes, it is possible to build Node.js applications on Visual Studio. In case, if you don’t know Visual Studio also has an extension for developing Python applications, you need to install the PTVS (Python Tools for Visual Studio) to be able to do it. The team that developed on PTVS also developed NTVS (Node.js Tools for Visual Studio) with help from a couple of community folks. NTVS is open source right from the beginning and accepts community contributions. The project is still in beta, so it has some pain points, but still it works pretty well. To follow along with this post, download and install the extension from its codeplex site. It works with the 2012 and 2013 versions of Visual Studio.

After installing NTVS, fire up Visual Studio and choose File -> New -> Project. In the dialog, expand Other Languages, and the node JavaScript under that. You will see a new option Node.js added here. Under this, you will find a number of project templates to start developing Node.js applications.


If you have TypeScript installed, you will find the same set of templates under TypeScript node as well.

Let us start building a simple Todo list application using NTVS. From the new project dialog, select Blank Express Application, change name of the application to Express-Todo and hit OK.

The new project we just created has all the set up ready for developing a Node – Express application. The project has the following NPM packages installed; you can find them under the npm node in Solution Explorer.



Express is a light weight server framework to develop Node.js applications. Jade is the most popular view engine used with express to compose the pages. Stylus defines a way to write CSS, takes many pain points of writing CSS away.

The app.js file generated with the project template has a number of middle-wares invoked for us to set up the node application.


app.set('port', process.env.PORT || 3000);  //Port number configured for the application
app.set('views', path.join(__dirname, 'views'));  //Folder under which the view files are stored
app.set('view engine', 'jade');  //Configuring view engine so that express parses them before rendering
app.use(express.favicon());  //Invoking favicon on startup
app.use(express.logger('dev')); 
app.use(express.json());
app.use(express.urlencoded());
app.use(express.methodOverride());
app.use(app.router);
app.use(require('stylus').middleware(path.join(__dirname, 'public')));  //Stylus middleware invocation
app.use(express.static(path.join(__dirname, 'public')));  //Defining relative path for static files


Now run the application. You should be able to see a simple hello World kind of view in the browser.

We need another NPM package, underscore.js. It can be installed in two ways. One is using the dialog offered by NTVS or using npm command on the command prompt. Let us use the GUI dialog to install the package. Right click on the NPM node and choose “Manage npm Modules…”. Go to the tab “Search npm Repository” and type underscore. Choose the package highlighted in the screenshot and hit Install Locally. This step adds the package to the project and adds an entry of underscore to package.json as well.


Check the contents under npm node, you should be able to see the package underscore there.

Add a new JavaScript file to the folder routes and name it todos.js. This file will contain the API service to display and add todo items against an in-memory collection. Following is the code in the file:


var _ = require('underscore');

var listItems =
[
    {
        "id": 1,
        "text": "Get Up"
    },
    {
        "id": 2,
        "text": "Brush teeth"
    },
    {
        "id": 3,
        "text": "Get Milk"
    },
    {
        "id": 4,
        "text": "Prepare coffee"
    },
    {
        "id": 5,
        "text": "Have a hot cup of coffee"
    }
];

exports.list = function(req, res){    
    res.send(listItems);
};

exports.addToList = function (req, res) {
    var maxId = _.max(listItems, function (item) { return item.id });
    console.log(maxId);
    var newTodoItem = { "id": maxId.id + 1, "text": req.body.text };
    listItems.push(newTodoItem);
    res.send({ success: true, item: newTodoItem });
};


I used underscore to calculate the next ID of the todo item. To use underscore, we need to add the require declaration at the beginning of the file, it is similar to the using statements in C# code files. All members to be exposed to the outside world have to be added to the exports object.

In order to expose the above methods as APIs, we need to define the HTTP method and attach a route path to them. In the app.js file add the following statement at the top:

var todos = require('./routes/todos');


This statement brings the module object exposed by the todos.js file. Now all we need to do is define routes, they are done as follows:


app.get('/api/todos', todos.list);
app.post('/api/todos', todos.addToList);


That’s pretty easy, isn’t it? With this, we are done with the work on the server side. Let’s define the components on the client side. As first thing, let’s add jQuery to the layout page. You can install the package using bower and use it or you can point to a CDN as well. Let’s use Google’s CDN path to refer jQuery. Following is the jade tag that does this:


script(src="http://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js")


Now, let’s update the index.jade file to contain the list items. Following is the mark-up of the modified index.jade file:

extends layout

block content
  h1= title
  p Welcome to #{title}
  ul(id="todoList")
  br
  br
  input(type="text" id="txtNewTodo")
  button(id="btnAddTodo") Add New Todo
  script(src="/javascripts/todoOperations.js")


As you see, in jade, one doesn’t require angle brackets to define the tags. It understands nesting through indentation. For indenting the tags, one can use either spaces or tabs; but not both. We are yet to define the todoOperations.js file referred above. Let’s do it now. Add a JavaScript file to the javascripts folder under public folder and name it todoOperations.js. Code in this file is pretty straight forward, if you know jQuery.

var todoOperations = function () {
    var todos;

    function getAllTodos() {
        //var deferred=$.defer();

        return $.get("/api/todos", function (data) {
            todos = data;
        });
    }

    function addTodo(todoItem) {
        return $.post('/api/todos', todoItem);
    }

    return {
        getAllTodos: getAllTodos,
        addTodo: addTodo
    }
}();

var list;

function refreshTodos() {
    todoOperations.getAllTodos().then(function (data) {
        $.each(data, function () {
            list.append("<li data-id='" + this.id + "'>" + this.text + "</li>");
        });
    });
}

$(function () {
    list = $("#todoList");

    $("#btnAddTodo").click(function () {
        var textBox = $("#txtNewTodo");
        if (textBox.val() !== "") {
            todoOperations.addTodo({ "text": textBox.val() }).then(function (data) {
                if (data.success === true) {
                    list.append("<li data-id='" + data.item.id + "'>" + data.item.text + "</li>");
                    textBox.val('');
                }
            });
        }
    });

    refreshTodos();
});


Now run the application. You will be able to see the list of todo items populated on the page and you will also be able to add new todo items. 
 
To update and delete the todo items, you need to define the methods in the todos,js file and add routes for them in the app.js file using app.put and app.delete methods. I am leaving it as an exercise for you :)

Happy coding!

Thursday, 17 April 2014

$parsers and $formatters in Custom Validation Directives in Angular JS

While writing applications using Angular JS, sometimes we need to define our own validators. Custom validations in Angular JS are created as directives with a dependency on the ng-model directive. At times, key part of the validation depends on controller of the ng-model directive.

The ng-model directive provides two arrays of functions to which the custom validation logic can be hooked: $parsers and $formatters. Usage of both of these arrays looks similar, but they are invoked under different conditions.

$parsers:
In most of the cases, $parsers is the right option to handle the logic of custom validation. Functions added to $parsers are called as soon as the value in the form input is modified by the user. As an example, consider the following directive:


app.directive('evenNumber', function(){
  return{
    require:'ngModel',
    link: function(scope, elem, attrs, ctrl){
      ctrl.$parsers.unshift(checkForEven);
      
      function checkForEven(viewValue){
        if (parseInt(viewValue)%2 === 0) {
          ctrl.$setValidity('evenNumber',true);
        }
        else{
          ctrl.$setValidity('evenNumber', false);
        }
        return viewValue;
      }
    }
  };
  
});


This is a simple directive that checks if the number entered in the textbox is even. If we apply validation on a textbox, the validator works as long as the value is modified in the textbox.

$formatters:
Formatters are invoked when the model is modified in the code. They are not invoked if the value is modified in the textbox. $formatters are useful when there is a possibility of the value getting modified from the code. $formatters can be applied in the above directive using a simple statement:


ctrl.$formatters.unshift(checkForEven);


Now, the validation on the textbox containing the evenNumber is fired when the value is directly modified or even when the value is modified in the code.

A demo of the directive is available on plnkr.

Happy coding!

Sunday, 30 March 2014

Basics: Benefits of Writing Unit Tests

Quite often people ask the reasons of writing unit tests for their code. There are several benefits of writing unit tests that add value to the code as well as the developers writing the tests. I am listing a set of points here that came to my mind while thinking about the benefits of Unit testing.

Benefits to code:
  • The code will have very few bugs as most of them are identified and resolved while running tests
  • Silly mistakes are inevitable while writing code. Identifying them while running the application is difficult at times. Unit tests catch them instantly
  • Code doesn’t need documentation. Names of the behaviours or methods defined in unit tests shout the purpose of their part
  • Testable code is easily extensible too. Adding new features to the code becomes easy
  • If Unit tests are written right from beginning of development, the underlying code automatically follows a set of quality measures that are otherwise very difficult to achieve
  • After applying some modifications, the code can be shipped within very less amount of time, as most of the regression testing is also done by the unit tests


Benefits to Programmers:
  • Unit testing teaches good programing practices to developers
  • Unit tests force programmers to use some of the features of the language and framework that would otherwise remain just as theories in programmers’ minds
  • As we write more code, our thinking about code starts maturing. With unit tests, we are bound to write a lot of additional code than the usual production code. So, it improves the programmer’s ability to think logically
  • Programmers gain the experience of writing clean, loosely coupled code and learn the ways to avoid anti-patterns
  • It becomes very easy for any new member to understand and start working on the code


These are just my opinions. The list is definitely not limited to the above set of points. Feel free to put a comment on anything that I didn’t mention in the above list.

Happy coding!

Sunday, 9 March 2014

A Closer Look at the Identity Client Implementation in SPA Template

Sometime back, we took a look at the identity system in ASP.NET and its support for both local and remote accounts. In this post, we will take a closer look at the way it is used in the Single Page Application template that comes with Visual Studio 2013.

The SPA application is a JavaScript client that uses an authenticated Web API. The Web API exposes a number of API methods to manage users. The JavaScript code uses jQuery for AJAX and Knockout for data binding has a number of methods that accomplish the task of managing the user. Let’s take a look at how the local users are authenticated.

Identity Client Implementation for Local Users:
If you check the Web API’s authentication configuration class, it exposes an endpoint at /Token for serving authorization token. Login credentials of the user have to be posted to this URL to get the user logged in. In response, the endpoint sends some data of which access token is a component. The access token has to be saved and used for subsequent requests to indicate the session of the logged in user.

Following code in the app.datamodel.js file sends a post request to the ‘/Token’ endpoint to login the user:


self.login = function (data) {
    return $.ajax(loginUrl, {
        type: "POST",
        data: data
    });
};

Following is the snippet from login.viewmodel.js that calls the above method:
dataModel.login({
    grant_type: "password",
    username: self.userName(),
    password: self.password()
}).done(function (data) {
    self.loggingIn(false);

    if (data.userName && data.access_token) {
        app.navigateToLoggedIn(data.userName, data.access_token, self.rememberMe());
    } else {
        self.errors.push("An unknown error occurred.");
    }
});


There are a couple of things to be noticed in the above code:

  • The property grant_type has to be set in the data passed to the login method
  • The navigateToLoggedIn method stores the access token in browser’s local storage to make it available for later use

To sign up for a new user, we just need to post the user’s data to the endpoint at ”/api/Account/Register”. Once the user is successfully registered, it sends a login request to the token endpoint discussed above to login the user immediately. Code for this can be found in the register method of register.viewmodel.js file. Following is the snippet that deals with registering and logging in:


dataModel.register({
    userName: self.userName(),
    password: self.password(),
    confirmPassword: self.confirmPassword()
}).done(function (data) {
    dataModel.login({
        grant_type: "password",
        username: self.userName(),
        password: self.password()
    })
    ......


Identity Client Implementation for External Login Users:
Identity implementation for external accounts is a bit tricky; because it involves moving the scope to a public web site and a number of API calls. When the application loads, it gets the list of external login providers by sending an HTTP GET request to “/api/Account/ExternalLogins”. Following method in app.datamodel.js does this:


self.getExternalLogins = function (returnUrl, generateState) {
    return $.ajax(externalLoginsUrl(returnUrl, generateState), {
        cache: false,
        headers: getSecurityHeaders()
    });
};

The parameter returnUrl used in the above method is where the user would be redirected after logging in from the external site.

Based on the providers obtained from the server, the provider specific login buttons are shown on the page. When a user chooses to use an external login provider, the system redirects him to the login page of the chosen provider. Before redirecting, the script saves the state and the URL redirected in session storage and local storage (both are used to make it work on most of the browsers). This information will be used once the user comes back to the site after logging in. Following snippet in login.viewmodel.js does this:


self.login = function () {
    sessionStorage["state"] = data.state;
    sessionStorage["loginUrl"] = data.url;
    // IE doesn't reliably persist sessionStorage when navigating to another URL. Move sessionStorage temporarily
    // to localStorage to work around this problem.
    app.archiveSessionStorageToLocalStorage();
    window.location = data.url;
};


Once the user is successfully authenticated by the external provider, the external provider redirects the user to the return URL with an authorization token in the query string. This token is unique for every user and the provider. This token is used to check if the user has already been registered to the site. If not, he would be asked to do so. Take a look at the following snippet from the initialize method in app.viewmodel.js:
......       
 } else if (typeof (fragment.access_token) !== "undefined") {
    cleanUpLocation();
    dataModel.getUserInfo(fragment.access_token)
    .done(function (data) {
    if (typeof (data.userName) !== "undefined" && typeof (data.hasRegistered) !== "undefined"
            && typeof (data.loginProvider) !== "undefined") {
        if (data.hasRegistered) {
            self.navigateToLoggedIn(data.userName, fragment.access_token, false);
        }
        else if (typeof (sessionStorage["loginUrl"]) !== "undefined") {
            loginUrl = sessionStorage["loginUrl"];
            sessionStorage.removeItem("loginUrl");
            self.navigateToRegisterExternal(data.userName, data.loginProvider, fragment.access_token,                              loginUrl, fragment.state);
        }
        else {
            self.navigateToLogin();
        }
    } else {
        self.navigateToLogin();
    }
})
......


It does the following:

  • Clears the access token from the URL
  • Queries the endpoint ‘/api/UserInfo’ with the access token for information about the user
  • If the user is found in the database, it navigates to the authorized content
  • Otherwise, navigates to the external user registration screen, where it asks for a local name

The external register page accepts a name of user’s choice and posts it to ‘/api/RegisterExternal’. After saving the user data, the system redirects the user to login page with value of state set in the session and local storages and also sends the authorization token with the URL. The login page uses this authorization token to identify the user.


dataModel.registerExternal(self.externalAccessToken, {
        userName: self.userName()
    }).done(function (data) {
        sessionStorage["state"] = self.state;
        // IE doesn't reliably persist sessionStorage when navigating to another URL. Move sessionStorage
        // temporarily to localStorage to work around this problem.
        app.archiveSessionStorageToLocalStorage();
        window.location = self.loginUrl;
    })


For logout, an HTTP POST request is sent to ‘/api/Logout’. It revokes the claims identity that was associated with the user. The client code removes entry of the access token stored in the local storage.

Happy coding!

Monday, 17 February 2014

Consuming ASP.NET Web API OData Batch Update From JavaScript

Consuming OData with plain JavaScript is a bit painful, as we would require handling some of the low-level conversions. datajs is a JavaScript library that simplifies this task.

datajs converts data of any format that it receives from the server to an easily readable format. The batch request sent is a POST request to the path /odata/$batch, which is made available if batch update option is enabled in the OData route configuration.

As seen in the last post, a batch update request bundles of a number of create put and patch requests. These operations have to be specified in an object literal. Following snippet demonstrates it with a create, an update and a patch request:


var requestData = {
    __batchRequests: [{
        __changeRequests: [
            {
                requestUri: "/odata/Customers(1)",
                method: "PATCH",
                data: {
                    Name: "S Ravi Kiran"
                }
            },
            {
                requestUri: "/odata/Customers(2)"
                data: {
                    Name: "Alex Moore",
                    Department: "Marketing",
                    City:"Atlanta"
                }
            },
            {
                requestUri: "/odata/Customers",
                method: "POST",
                data: {
                    Name: "Henry",
                    Department: "IT",
                    City: "Las Vegas"
                }
            }
        ]
    }]
};

Following snippet posts the above data to the /odata/$batch endpoint and then extracts the status of response of each request:

OData.request({
    requestUri: "/odata/$batch",
    method: "POST",
    data: requestData,
    headers: { "Accept": "application/atom+xml"}
}, function (data) {
    for (var i = 0; i < data.__batchResponses.length; i++) {
        var batchResponse = data.__batchResponses[i];
        for (var j = 0; j < batchResponse.__changeResponses.length; j++) {
            var changeResponse = batchResponse.__changeResponses[j];
        }
    }
    alert(window.JSON.stringify(data));
}, function (error) {
    alert(error.message);
}, OData.batchHandler);


Happy coding!

Sunday, 16 February 2014

Batch Update Support in ASP.NET Web API OData

The ASP.NET Web API 2 OData includes some new features including the support for batch update. This features allows us to send a single request to the OData endpoint with a bunch of changes made to the entities and ask the service to persist them in one go instead of sending individual request for each change made by the user. This reduces the number of round-trips between the client and the service.

To enable this option, we need to pass an additional parameter to the MapODataRoute method along with other routing details we discussed in an older post. Following statement shows this:


GlobalConfiguration.Configuration.Routes.MapODataRoute("ODataRoute", "odata", model,new DefaultODataBatchHandler(GlobalConfiguration.DefaultServer));


I have a CustomerController that extends EntitySetController and exposes OData API to perform CRUD and patch operations on the entity Customer, which is stored in a SQL Server database and accessed using Entity Framework. Following is code of the controller:

public class CustomersController : EntitySetController<Customer, int>
{
    CSContactEntities context;

    public CustomersController()
    {
        context = new CSContactEntities();
    }

    [Queryable]
    public override IQueryable<Customer> Get()
    {
        return context.Customers.AsQueryable();
    }

    protected override int GetKey(Customer entity)
    {
        return entity.Id;
    }

    protected override Customer GetEntityByKey(int key)
    {
        return context.Customers.FirstOrDefault(c => c.Id == key);
    }

    protected override Customer CreateEntity(Customer entity)
    {
        try
        {
            context.Customers.Add(entity);
            context.SaveChanges();
        }
        catch (Exception)
        {
            throw new InvalidOperationException("Something went wrong");
        }

        return entity;
    }

    protected override Customer UpdateEntity(int key, Customer update)
    {
        try
        {
            update.Id = key;
            context.Customers.Attach(update);
            context.Entry(update).State = System.Data.Entity.EntityState.Modified;

            context.SaveChanges();
        }
        catch (Exception)
        {
            throw new InvalidOperationException("Something went wrong");
        }

        return update;
    }

    protected override Customer PatchEntity(int key, Delta<Customer> patch)
    {
        try
        {
            var customer = context.Customers.FirstOrDefault(c => c.Id == key);

            if (customer == null)
                throw new InvalidOperationException(string.Format("Customer with ID {0} doesn't exist", key));

            patch.Patch(customer);
            context.SaveChanges();
            return customer;
        }
        catch (InvalidOperationException ex)
        {
            throw ex;
        }
        catch (Exception)
        {
            throw new Exception("Something went wrong");
        }
    }

    public override void Delete(int key)
    {
        try
        {
            var customer = context.Customers.FirstOrDefault(c => c.Id == key);

            if (customer == null)
                throw new InvalidOperationException(string.Format("Customer with ID {0} doesn't exist", key));

            context.Customers.Remove(customer);
            context.SaveChanges();
        }
        catch (InvalidOperationException ex)
        {
            throw ex;
        }
        catch (Exception)
        {
            throw new Exception("Something went wrong");
        }
    }
}


Let’s use the batch update feature in a .NET client application. Let’s try adding a new customer and update an existing customer in the Customers table. Following code does this:

Container container = new Container(new Uri("http://localhost:<port-no>/odata"));

var firstCustomer = container.Customers.Where(c => c.Id == 1).First();
firstCustomer.Name = "Ravi Kiran";
container.UpdateObject(firstCustomer);

var newCustomer = new Customer() { Name="Harini", City="Hyderabad", Department="IT"};
container.AddToCustomers(newCustomer);

var resp = container.SaveChanges(SaveChangesOptions.Batch);


The last statement in the above snippet sends a batch request containing two requests: one to add a new customer and one to update an existing customer. The update operation calls the patch operation exposed by the OData API.

In next post, we will see how to perform batch update in a JavaScript client.

Happy coding!

Monday, 27 January 2014

Creating a Todo List using Indexed DB and Angular JS

In last post, we saw how to use Indexed DB with promise API implemented inside the browsers. In this post, we will rewrite the same sample using Angular JS. So, instead of using promise API of the browser, we will use Angular’s $q, as it makes the data binding system happy. And instead of performing the CRUD operations on Indexed DB inside a revealing module, we will do it inside a factory.

Indexed DB is available to the global scope. This means, it is a property of the window object. The best practice to use it in a factory is through the $window object, as it is injectable and makes the factory testable. Following snippet shows first few statements of the factory:

var app = angular.module('indexDBSample', []);
app.factory('indexedDBDataSvc', function($window, $q){
  var indexedDB = $window.indexedDB;
  var db=null;
  var lastIndex=0;
  ....
  ....
  ....
});


We need to add methods to open DB, get todo items, add new item and delete an item just as we did in the last post. Logic in the methods remains the same, except usage of the promise.

The open method opens the database, checks for upgrade and handles the call back if it needs. It specifies the key property of the database while creating a new database.

var open = function(){
  var deferred = $q.defer();
  var version = 1;
  var request = indexedDB.open("todoData", version);
  request.onupgradeneeded = function(e) {
    db = e.target.result;
    e.target.transaction.onerror = indexedDB.onerror;
    if(db.objectStoreNames.contains("todo")) {
      db.deleteObjectStore("todo");
    }
    var store = db.createObjectStore("todo",
      {keyPath: "id"});
  };
  request.onsuccess = function(e) {
    db = e.target.result;
    deferred.resolve();
  };
  request.onerror = function(){
    deferred.reject();
  };
  
  return deferred.promise;
};


The getTodos method fetches all available items in the DB and resolves promise with the results once all results are obtained. The fetch operation is performed using a cursor request, which returns the items individually from the indexed DB.

var getTodos = function(){
  var deferred = $q.defer();
  
  if(db === null){
    deferred.reject("IndexDB is not opened yet!");
  }
  else{
    var trans = db.transaction(["todo"], "readwrite");
    var store = trans.objectStore("todo");
    var todos = [];
  
    // Get everything in the store;
    var keyRange = IDBKeyRange.lowerBound(0);
    var cursorRequest = store.openCursor(keyRange);
  
    cursorRequest.onsuccess = function(e) {
      var result = e.target.result;
      if(result === null || result === undefined)
      {
        deferred.resolve(todos);
      }
      else{
        todos.push(result.value);
        if(result.value.id > lastIndex){
          lastIndex=result.value.id;
        }
        result.continue();
      }
    };
  
    cursorRequest.onerror = function(e){
      console.log(e.value);
      deferred.reject("Something went wrong!!!");
    };
  }
  
  return deferred.promise;
};


The addTodo method generated the next value for the key column and adds it to the Indexed DB.

var addTodo = function(todoText){
  var deferred = $q.defer();
  
  if(db === null){
    deferred.reject("IndexDB is not opened yet!");
  }
  else{
    var trans = db.transaction(["todo"], "readwrite");
    var store = trans.objectStore("todo");
    lastIndex++;
    var request = store.put({
      "id": lastIndex,
      "text": todoText
    });
  
    request.onsuccess = function(e) {
      deferred.resolve();
    };
  
    request.onerror = function(e) {
      console.log(e.value);
      deferred.reject("Todo item couldn't be added!");
    };
  }
  return deferred.promise;
};


Finally, the deleteTodo method accepts value of key property of the item to be deleted and invokes the delete method of the store to delete the item.

var deleteTodo = function(id){
  var deferred = $q.defer();
  
  if(db === null){
    deferred.reject("IndexDB is not opened yet!");
  }
  else{
    var trans = db.transaction(["todo"], "readwrite");
    var store = trans.objectStore("todo");
  
    var request = store.delete(id);
  
    request.onsuccess = function(e) {
      deferred.resolve();
    };
  
    request.onerror = function(e) {
      console.log(e.value);
      deferred.reject("Todo item couldn't be deleted");
    };
  }
  
  return deferred.promise;
};


Implementation of the controller is pretty straight forward. The controller invokes the members of the factory and updates the data items that are used to bind data on the UI.

app.controller('TodoController', function($window, indexedDBDataSvc){
  var vm = this;
  vm.todos=[];
  
  vm.refreshList = function(){
    indexedDBDataSvc.getTodos().then(function(data){
      vm.todos=data;
    }, function(err){
      $window.alert(err);
    });
  };
  
  vm.addTodo = function(){
    indexedDBDataSvc.addTodo(vm.todoText).then(function(){
      vm.refreshList();
      vm.todoText="";
    }, function(err){
      $window.alert(err);
    });
  };
  
  vm.deleteTodo = function(id){
    indexedDBDataSvc.deleteTodo(id).then(function(){
      vm.refreshList();
    }, function(err){
      $window.alert(err);
    });
  };
  
  function init(){
    indexedDBDataSvc.open().then(function(){
      vm.refreshList();
    });
  }
  
  init();
});




The complete sample is available on this plunk: http://plnkr.co/edit/7oSOUHC9hSnD8d6COkSK?p=preview

Happy coding!