Performing CRUD on OData Service using DataJS

Standard

Recently i had released a project by name Netflix Catalog using HTML + ODATA + DATAJS + JQUERY. I had a request from a reader asking for a CRUD example using DataJS. This post is about a demo application for performing Create, Read, Update and Delete on a OData service all by just using the DataJS client side framework. I have become a big fan of DataJS and i will do whatever it takes to promote it. So this post is kind of a walkthrough and a step by step guide for using DataJS and performing CRUD with the help of it. So stay with me and follow carefully.

Pre-Requisites:

To follow along with this demo, you do not need Visual Studio.NET licenced version like Developer or Professional or Ultimate edition. As far as possible i tend to create my demos and example using the free express versions available. So here are the pre-requisites:

I prefer IIS Express because, its as if you are developing on a production level IIS but which runs locally on your desktop as a user services rather than a machine level service. More information on this from Scott Gu here.

Also i am using SQL CE or SQL Server Compact Edition – as my backend store. My EF Model is tied to this database. But if you want to replace it with SQL Express you can. You need to change the connection string EF data model in the web.config. But if you want to pursue my path then you need to do the following:

If you have finished the pre-requisite part, then now the real fun begins. Read on:

Step 1: Create ASP.NET Web Site

Fire up Visual Web Developer 2010 express and select File > New Web Site.  Select the “Visual C#” from the installed templates and “ASP.NET Web Site” from the project template. Select File System for the web location and provide a path for the project. Click Ok to create the project.

Note: I will be developing this demo using C# as a language.

DataJSCRUD1 

Step 2: Clean Up

Once the project is created, it will have some default files and folder system as shown below.

DataJSCRUD2

For this demo we do not need any of those. So lets clean up those files and folder. I will be deleting the “Account” folder, “About.aspx”, “Default.aspx” and “Site.master”. We will need the Scripts, App_Data, Styles folders. So lets leave them as is for now. Here is how the solution looks after clean up:

DataJSCRUD3

Step 3: Set Web Server

By default when you create any web site projects, Visual Studio will use the “Visual Studio Development Server”. In order to use IIS Express as the web server for the project, right click on the solution and select the option “Use IIS Express”.

DataJSCRUD4

Step 4: Create SQL CE Database

As i have said earlier, i will be using SQL CE as the back end store. So lets create a simple database for maintaining User account details – userid, username, email, and password. Right click on the solution and select “Add New Item”. I have named my database as “users”. Note that the extension for the data file is .SDF and it will be stored as a file in your App_Data folder. So if you want to deploy this somewhere you can just zip and send this and app will be up and running after installation.

DataJSCRUD5

Note: You will get the following warning when adding the database. Select “Yes”. All it says is we are adding a special file and will place it in App_Data folder.

DataJSCRUD6

Step 5: Create Table

Lets create a new table in the database. It will be a simple table with 4 columns. namely:

  • UserID which is the PK and Identity column
  • UserName, string column
  • Email, string column
  • Password, string column

Expand App_Data folder and double click on Users.sdf file. This will open the Database Explorer with a connection to Users database.

DataJSCRUD7

Right click on Tables and select “Create Table”. You will get the table creation UI. My table definition looks like below:

DataJSCRUD8


Step 6: Create Entity Framework Model

Right click on solution and select “Add New Item”. Select “ADO.NET Entity Data Model” item type. I have named my model as “UsersModel.edmx”.

DataJSCRUD9

When asked to choose Model contents select “Generate From Database” and click next.

DataJSCRUD10

Next you will have to choose the data connection. By default the Users.sdf that we created will be listed in the database listing. Give name for the entities and click next.

DataJSCRUD11

Next you would have to choose the database objects. Expand Tables and select Users. Give a name for the Model Namespace. In my case i have named it as UsersModel. Click finish.

DataJSCRUD12

After this, UsersModel.edmx will be added to the App_Code folder. So we now have the EDMX ready for creating an OData service.

Step 7: Create OData Service

Now we will create a OData service to expose our Users data. Right click on the Solution and select “Add New Item”. Select WCF Data Service from the item template. Give it a name – in my case i have named it as “UsersOData.svc”.

DataJSCRUD14

The SVC file will be kept at the root folder where as the code behind for that will be placed in App_Code folder. At this point here is how our solution looks like:

DataJSCRUD15

Open the UsersOData.cs file from the App_Code folder. You will see the following code set up for you.

   1:  public class UsersOData : DataService< /* TODO: put your data source class name here */ >
   2:  {
   3:      // This method is called only once to initialize service-wide policies.
   4:      public static void InitializeService(DataServiceConfiguration config)
   5:      {
   6:          // TODO: set rules to indicate which entity sets and service operations are visible, updatable, etc.
   7:          // Examples:
   8:          // config.SetEntitySetAccessRule("MyEntityset", EntitySetRights.AllRead);
   9:          // config.SetServiceOperationAccessRule("MyServiceOperation", ServiceOperationRights.All);
  10:          config.DataServiceBehavior.MaxProtocolVersion = DataServiceProtocolVersion.V2;
  11:      }
  12:  }

If you see the highlighted portion, there is a TODO and it says to put our data source class name here. Remember from the step where we added the Entity Framework, you need to put the EF entity container name here. In my case i had named it as UsersEntities. Also we need to set some entity access rules. After those changes here is the modified code:

   1:  public class UsersOData : DataService<UsersEntities>
   2:      {
   3:          // This method is called only once to initialize service-wide policies.
   4:          public static void InitializeService(DataServiceConfiguration config)
   5:          {
   6:              config.SetEntitySetAccessRule("*", EntitySetRights.All);
   7:              config.DataServiceBehavior.MaxProtocolVersion = DataServiceProtocolVersion.V2;
   8:              config.UseVerboseErrors = true;
   9:          }
  10:      }


At this point if you run the application and navigate to UsersOData.SVC you will receive an error which is:

DataJSCRUD16

Well it says it cant fine the type that implements the service. Thanks to the tip provided at the following location – http://ef4templates.codeplex.com/documentation – came to know that the .SVC file has a attribute called Service and it points to the implementation class which is in our class UsersOData.cs. But we need to qualify the class with a namespace and provide the fully classified name to the Service attribute. Open UsersOData.cs file and wrap the class inside a namespace as below:

   1:  namespace UserServices
   2:  {
   3:      public class UsersOData : DataService<UsersEntities>
   4:      {
   5:          // This method is called only once to initialize service-wide policies.
   6:          public static void InitializeService(DataServiceConfiguration config)
   7:          {
   8:              config.SetEntitySetAccessRule("*", EntitySetRights.All);
   9:              config.DataServiceBehavior.MaxProtocolVersion = DataServiceProtocolVersion.V2;
  10:              config.UseVerboseErrors = true;
  11:          }
  12:      }

13: }


Next open the UsersOData.SVC file and modify the Service attribute to include the Namespace and the class name as below:

   1:  <%@ ServiceHost 
   2:  Language="C#" 
   3:  Factory="System.Data.Services.DataServiceHostFactory" 
   4:  Service="UserServices.UsersOData" %>


If you now navigate to UsersOData.svc in internet explorer you should see the following:

DataJSCRUD17

So we have our OData service up and running with one collection “Users”. Next we will see how we will do a CRUD on this service using the DataJS.

Step 8: Create Index.htm, Import DataJS & JQuery

Now lets create the front end for the application. Right click on the solution and select “Add New Item”. Select a html page and name it as “Index.htm”. I will be using JQuery from the AJAX CDN from Microsoft. The project gets bundled with JQuery 1.4.1. But i prefer using the CDN as i get the latest versions hosted at one of most reliable place on the net. Here is the URL for the JQuery:

   1:  <script 
   2:  type="text/javascript" 
   3:  src="http://ajax.aspnetcdn.com/ajax/jquery/jquery-1.5.1.min.js">
   4:  </script>
   5:  <script 
   6:  type="text/javascript" 
   7:  src="http://ajax.aspnetcdn.com/ajax/jquery.ui/1.8.13/jquery-ui.min.js">
   8:  </script>


Next download the DataJS library from the following location: http://datajs.codeplex.com/

Next we need one more JQuery plugin for templating. Download the Jquery Templating library from: https://github.com/jquery/jquery-tmpl.

Let me give you a sneak preview of what we are building. We will have a <table> which lists down all the available user accounts, ability to create a new user account, ability to update an existing account and ability to delete a user account.

DataJSCRUD18 

I will not get into the UI mark-up now. You can download the code and go through it. Lets start looking at how DataJS was used for the CRUD operation.

Read Operation:

DataJS has a “read” API. This will allow us to read the data from the OData service. In its simplest form Read API takes the URL and a call-back to execute when the read operation succeeds. In this example, what i have done is i have a GetUsers() function and GetUsersCallback() function which handle the read part. Here is the code:

   1:  //Gets all the user accounts from service
   2:  function GetUsers() 
   3:  {
   4:      $("#loadingUsers").show();
   5:      OData.read(USERS_ODATA_SVC, GetUsersCallback);
   6:  }
   7:   
   8:  //GetUsers Success Callback
   9:  function GetUsersCallback(data, request) 
  10:  {
  11:      $("#loadingUsers").hide();
  12:      $("#users").find("tr:gt(0)").remove();
  13:      ApplyTemplate(data.results)
  14:  }

ApplyTemplate() is a helper function which takes the JSON data uses JQuery templating technology to create the UI markup and append it to the user account listing table. 

Create Operation:

If “read” API allows to get the data, DataJS has a “request” API which allows us to do the CUD or Create , Update and Delete operations. There is no specific calls like Create/Update/Delete in OData, rather  we use the HTTP verbs to indicate the server what operation to perform. Create uses “POST” verb, Update uses “PUT” verb and Delete uses “DELETE” verb. As you have seen earlier, i have 3 fields on the User entity. In the example while creating a new entity, i create a JSON representation of the data i need to send over to the server and pass it to the request API. The code for the create is as follows:

  

 

   1:  //Handle the DataJS call for new user acccount creation
   2:  function AddUser() 
   3:  {
   4:      $("#loading").show();
   5:      var newUserdata = { 
   6:      username: $("#name").val(), 
   7:      email: $("#email").val(), 
   8:      password: $("#password").val() };
   9:      var requestOptions = {
  10:          requestUri: USERS_ODATA_SVC,
  11:          method: "POST",
  12:          data: newUserdata
  13:      };
  14:   
  15:      OData.request(requestOptions, 
  16:      AddSuccessCallback, 
  17:      AddErrorCallback);
  18:   
  19:  }
  20:   
  21:  //AddUser Success Callback
  22:  function AddSuccessCallback(data, request) 
  23:  {
  24:      $("#loading").hide('slow');
  25:      $("#dialog-form").dialog("close");
  26:      GetUsers();
  27:  }
  28:   
  29:  //AddUser Error Callback
  30:  function AddErrorCallback(error) 
  31:  {
  32:      alert("Error : " + error.message)
  33:      $("#dialog-form").dialog("close");
  34:  }

As you can see, the high lighted code is where i create the JSON representation of the data that needs to be passed. In this case its username, email and password. Also notice the method set to “POST”. The request API  takes request options, a success call-back and an error call-back. In the success call-back i go and fetch all the users again and re paint the UI.
 
Update Operation:

If we want to update a resource which is exposed as an OData we follow the same construct we used in Create. But the only change is the URL you will need to point to. If i have a User whose UserID (in this example the PK) is 1, then the URL to point to this user is /UsersOData.svc/Users(1">/UsersOData.svc/Users(1">http://<server>/UsersOData.svc/Users(1). If you notice we pass the user id in the URL itself. This is how you navigate to a resource in OData. To update this resource, we need to again prepare the data in JSON representation and call the request API but with method set to “PUT”. PUT is the http verb that lets the server know that we need to update the resource with the new values passed. Here is the code block to handle the Update:

   1:  //Handle DataJS calls to Update user data
   2:  function UpdateUser(userId) 
   3:  {
   4:      $("#loading").show();
   5:      var updateUserdata = {
   6:       username: $("#name").val(), 
   7:       email: $("#email").val(), 
   8:       password: $("#password").val() };
   9:      var requestURI = USERS_ODATA_SVC + "(" + userId + ")";
  10:      var requestOptions = {
  11:          requestUri: requestURI,
  12:          method: "PUT",
  13:          data: updateUserdata
  14:      };
  15:   
  16:      OData.request(requestOptions, 
  17:      UpdateSuccessCallback, 
  18:      UpdateErrorCallback);
  19:   
  20:  }
  21:   
  22:  //UpdateUser Suceess callback
  23:  function UpdateSuccessCallback(data, request) {
  24:      $("#loading").hide('slow');
  25:      $("#dialog-form").dialog("close");
  26:      GetUsers();
  27:  }
  28:   
  29:  //UpdateUser Error callback
  30:  function UpdateErrorCallback(error) {
  31:      alert("Error : " + error.message)
  32:      $("#dialog-form").dialog("close");
  33:  }

 

Delete Operation:

Delete operation is very similar to Update. The only difference is we wont pass any data. Instead we set the URL to the resource that needs to be deleted and mark the method as “DELETE”. DELETE is the HTTP verb which the server will look for if a resource needs to be deleted. For .e.g if i have a user id 1 and i want to delete that resource, we set the URL as /UsersOData.svc/Users(1">/UsersOData.svc/Users(1">http://<server>/UsersOData.svc/Users(1) and set the method as “DELETE”. Here is the code for the same:

 

   1:  //Handles DataJS calls for delete user
   2:  function DeleteUser(userId) 
   3:  {
   4:      var requestURI = USERS_ODATA_SVC + "(" + userId + ")";
   5:      var requestOptions = {
   6:                              requestUri: requestURI,
   7:                              method: "DELETE",
   8:                          };
   9:   
  10:      OData.request(requestOptions, 
  11:      DeleteSuccessCallback, 
  12:      DeleteErrorCallback);
  13:  }
  14:   
  15:  //DeleteUser Success callback
  16:  function DeleteSuccessCallback()
  17:  {
  18:      $dialog.dialog('close');
  19:      GetUsers();
  20:  }
  21:   
  22:  //DeleteUser Error callback
  23:  function DeleteErrorCallback(error)
  24:  {
  25:      alert(error.message)
  26:  }

 

That’s it. With a single HTML file, with DataJS javascript library and a little bit of  JQuery to spice up the UI we built a complete CRUD operations within just a couple of minutes.

DataJS is now getting traction and many people have started to use this and follow this library. Hopefully this demo would give a pointer to all those who wanted to know more on the request API. Main goal was to focus on request API of dataJS and how to use that. Hope i have done the justice to that.

Find attached the source code here:

Till next time, as usual, Happy Coding. Code with passion, Decode with patience.

  • http://twitter.com/AbhijitJana Abhijit Jana

    Very nice . Thanks for sharing with us !

    • http://kashyapas.com Lohith

      Hey Abhijit

      Thanks for the comments man. Appreciate it.

  • Dinu_3gee

    This is Awesome work. Very Thanks for sharing.

  • Dinu_3gee

    Hello Lohith

    Can the similar CRUD datajs operations are possible using mobile emulators?

    regards
    Dhinesh Kumar

  • http://www.dotnetwise.com DotNEtWise

    Source code url is missing. Add it please

    • http://kashyapas.com Lohith

      will do. thanks for pointing it out

    • http://kashyapas.com Lohith

      Hi, please check the post now. I have the source code URL working again. Thanks once again for pointing it out

  • Dinu_3gee

    Hello Lohith
     
    I am sorry for the previous query. I meant to ask whether the similar CRUD operation is possible in a HTML 5 page environment. Is it possible to convert the html file(index.htm) you used into HTML 5 and access in various browsers & mobile devices?
     
    Regards
    Dhinesh Kumar

  • Jxnuzhangwen

    very nice, I am chinese programmer :)

  • Ratheesh K R

    OData.request() is not working for me , the error returns ‘no handler for data’, please help me to update and delete data