Combine Knockoutjs, Datajs and OData Query[2]

To support OData Query, a few changes had to be made in the code.

1. Need to add a text box and button for OData Query

</pre>
<div>Search:  <input type="text" data-bind="value: Criteria" />
 <button title="Search" data-bind="click: SearchCourse">Search</button></div>
<pre>

2. Add new functions, Handle the query in Javascript

  var Courses = ko.observableArray();

  function GetCourses(courses, criteria) {
    var url = "http://localhost/ODataService/odata/Courses";
    if ((typeof criteria != "undefined") && criteria !== null && criteria !== "") {
      url += "?$filter=" + criteria;
    }
    OData.read(url,
      function (data, response) {
        courses(JSON.parse(data));
      },
      function (err){
        alert(err.message);
      }
    );
  }
  GetCourses(Courses, "");
  var viewModel = {
    Courses: Courses
    ,Criteria :ko.observable("") // new property for OData Query parameter
  }
  //new function for OData Query
  viewModel.SearchCourse = function () {
    GetCourses(this.Courses, this.Criteria());
  }
  ko.applyBindings(viewModel);

if we add something like “DepartmentID gt 2” in the text box, then click search,
the page displays the following

Course ID	Title	        Credits	Department ID
1045	    Calculus	    4	    7
3141	    Trigonometry	4	    7
4022	    Microeconomics	3	    4
4041	    Macroeconomics	3	    4
4061	    Quantitative	2	    4

About the OData query syntax, you can reference.
http://http://www.asp.net/web-api/overview/odata-support-in-aspnet-web-api/supporting-odata-query-options

When I was doing the sample project, I have faced a few problems.
1. Datajs not support cross domain, it means that, if your service has different port in URL,
using OData.read() in javascript, error happens.
For example, if OData Service url is http://servername:8080/odata/Courses,
while the application url is http://servername:33789/webapplicationName/,
because Datajs doesn’t support cross domain access, error happens.

2. Given that the cross domain issue has been fixed, that OData service url is
is http://servername/odata/Courses, and the application url is http://servername/webapplicationName/,
call OData.read still returns an error says “no data handler”, then a data handler should be set to
replace default data handler. So the proper javascript will be the following.

    var Courses = ko.observableArray();

    function GetCourses(courses, criteria) {
      var url = "http://localhost/ODataService/odata/Courses";
      if ((typeof criteria != "undefined") && criteria !== null && criteria !== "") {
        url += "?$filter=" + criteria;
      }
      //**************************
      //***   Create Handler   *** 
      //**************************  
      var jsonHandler = {
        read: function (response, context) {
          var contentType = response.headers["Content-Type"];
          if (contentType && contentType.indexOf("application/json") === 0) {
             response.data = response.body;
          } else {
             odata.defaultHandler.read(response, context);
          }
        },
        write: function (request, context) { }
      }
      //****************************************************
      //*** Replace defaultHandler to handler we created *** 
      //****************************************************  
      OData.defaultHandler = jsonHandler;

      OData.read(url,
        function (data, response) {
          courses(JSON.parse(data));
        },
        function (err){
          alert(err.message);
        }
      );
    }
    GetCourses(Courses, "");
    var viewModel = {
      Courses: Courses
      ,Criteria :ko.observable("") // new property for OData Query parameter
    }
    //new function for OData Query
    viewModel.SearchCourse = function () {
      GetCourses(this.Courses, this.Criteria());
    }
    ko.applyBindings(viewModel);
    

Now we OData.read smoothly gets the data from OData Service and KnockoutJs is responsible
for page presentation. Keep learning.

Combine Knockoutjs, Datajs and OData Query

Days ago, I watched a video on asp.net which displayed how to use OData Parameter Query. 
http://channel9.msdn.com/Shows/Web+Camps+TV/ASPNET-Web-API-Queryable-with-OData
In that video, the guy mentioned that Datajs was used to call OData service and Knockoutjs was used to populate the page. I decide to create something similar myself.
I have done the following steps and will point out a few things which I met in doing this.

1. Create OData ServiceCreate a web API project called “ODataService”  in VS2012, then add an Entity Data Model which is generated from a database.  Add a new web API Controller which for OData Query.

public class CoursesController : ApiController {
  private SchoolEntities context = new SchoolEntities(); // for test project only
  [Queryable] 
  public IQueryable&lt;Course&gt; Get() { 
    return context.Courses.AsQueryable(); 
  } 
}

There Queryable attribute is added to Web API action to support OData Query.Also need to add configuration in WebApiConfig.cs 

var modelBuilder = new ODataConventionModelBuilder(); 
modelBuilder.EntitySet<Course>("Courses");
var model = modelBuilder.GetEdmModel(); 
config.Routes.MapODataRoute("Courses", "odata", model);

  
it’s for endpoint which expose to be called by client side.
like http://servername/ODataService/odata/Courses

2. Use Datajs to retrieve the data and populate an observableArray for data binding.

//Create an collection for data binding
var Courses = ko.observableArray();

//Get Courses, criteria for which course(s) should be retrieved
//url is OData service url, like http://servername/ODataService/odata/Courses?$filter=xxxxxxxxx
OData.read(url, 
    function (data, response) {
        courses(JSON.parse(data));
    },
    function (err){
        alert(err.message);
    }
);

3. Create view Model for data binding

GetCourses(Courses, "");
var viewModel = {
  Courses: Courses
  ,Criteria :ko.observable("")
}
viewModel.SearchCourse = function () {
    GetCourses(this.Courses, this.Criteria());
}
ko.applyBindings(viewModel);

4. Client side binding

<table>
  <thead>
    <tr>
      <th>Course ID</th>
      <th>Title</th>
      <th>Credits</th>
      <th>Department ID</th>
    </tr>
  </thead>
  <tbody data-bind="foreach: Courses">
    <tr>
      <td data-bind="text:CourseID"></td>
      <td data-bind="text:Title"></td>
      <td data-bind="text:Credits"></td>
      <td data-bind="text:DepartmentID"></td>
    </tr>
  </tbody>
</table>

then you will get something like

Course ID	Title	        Credits	Department ID
1045		Calculus	        4	7
1050		Chemistry	        4	1
1061		Physics		        4	1
2021		Composition	        3	2
2030		Poetry		        2	2
2042		Literature	        4	2
3141		Trigonometry	    4	7
4022		Microeconomics	    3	4
4041		Macroeconomics	    3	4
4061		Quantitative	    2	4

till now,a simple project which call odata service has been done.
In next post, I will show how to do OData Query.

RestSharp Async Call Web API

In last article, how to call Web API via HttpClient has been discussed.
Another way to call Web API, RestSharp will be dicussed in this article.

1. Create RestClient Instance, Url is Url of Web API (http://localhost:49277)

var Client = new RestClient();
Client.BaseUrl = url;

2. Write code to consume Web API.

// Get
var request = new RestRequest("api/Person", Method.GET);
Client.ExecuteAsync<Person>(request, (response) => { 
  if (response.StatusCode == System.Net.HttpStatusCode.OK) {   
    Console.WriteLine("{0}", response.Data.Name);
  } else {
    Console.WriteLine("{0} {1}", response.StatusCode, response.ErrorMessage);
  }
});

//Post
var request = new RestRequest("api/Person", Method.POST);
var person = new Person() { Name = "TestName", Id = "12", Age = 30 };
request.RequestFormat = DataFormat.Json;
request.AddBody(person);
Client.ExecuteAsync<Person>(request, (response) => { 
  if (response.StatusCode == System.Net.HttpStatusCode.OK) {
    Console.WriteLine("{0}", response.Data.Name);
  } else {
    Console.WriteLine("{0} {1}", response.StatusCode, response.ErrorMessage);
  }
});

//Update
var request = new RestRequest("api/Person/12", Method.PUT);
var person = new Person() { Name = "TestName", Id = "12", Age = 30 };
request.RequestFormat = DataFormat.Json;
request.AddBody(person);
Client.ExecuteAsync<Person>(request, (response) => { 
  if (response.StatusCode == System.Net.HttpStatusCode.OK) {
    Console.WriteLine("{0}", response.Data.Name);
  } else {
    Console.WriteLine("{0} {1}", response.StatusCode, response.ErrorMessage);
  }
});

We need to create a RestSharp Request and specify the action type as Method.GET, Method.PUT or Method.POST.
Then call AddBody to set object as Request’s body for passing data to server.
After that call ExecuteAsync, and check response status in callback function.

(response) => { 
  if (response.StatusCode == System.Net.HttpStatusCode.OK) {
    Console.WriteLine("{0}", response.Data.Name);
  } else {
    Console.WriteLine("{0} {1}", response.StatusCode, response.ErrorMessage);
  }
}

if there is object passed back from server, RestSharp Client automatically
convert the Json formatted object to a strong-typed object which can directly used at client side.
like the following,

response.Data.[PropertyName]

HttpClient Call Web API

In last article, a Web API was created, now it’s time to discuss how to call Web API.
There are many ways to call Web API, I will discusse HttpClient call Web API in this article.

1. Create HttpClient Instance, Url is Url of Web API (http://localhost:49277)

var Client = new HttpClient();
Client.BaseAddress = new Uri(url);

2. Write code to consume Web API.

// Get
var response = Client.GetAsync("api/Person/1").Result; 
if (response.IsSuccessStatusCode)
  // Parse the response body.
  var p = response.Content.ReadAsAsync<Person>().Result;
  Console.WriteLine("{0}", p.Name );    
}

//Post    
var person = new Person(){Name = "TestName", Id="Test", Age=30};    
var response = Client.PostAsJsonAsync<Person>("api/Person", person).Result;     
if (response.IsSuccessStatusCode)    {        
  // Parse the response body.
  var p = response.Content.ReadAsAsync<Person>().Result;      
  Console.WriteLine("{0}", p.Name);    
}

//Update    
var person = new Person() { Name = "TestName", Id = "Test", Age = 30 };    
var response = Client.PutAsJsonAsync<Person>("api/Person/12", person).Result;      
if (response.IsSuccessStatusCode)     {       
  // Parse the response body.     
  var p = response.Content.ReadAsAsync<Person>().Result;       
  Console.WriteLine("{0}", p.Name);     
}

  

From above code, GetAsync, PutAsJsonAsync, PostAsJsonAsync and ReadAsAsync are used to retrieve/pass data to Web API via Json format.
For GetAsync, PutAsJsonAsync and PostAsJsonAsync, a url is passed as parameter to indicatewhich Web API action should be called.
For example, the code

Client.PutAsJsonAsync<Person>("api/Person/12", person).Result

will look for Put Action which has an int parament. If there are more than one action match this Route

api/{Controll}/{Action}/{id}

An error happens.

Web API

Since long time ago, MVC pattern has been introduced into software development, and Microsoft published ASP.NET MVC 5 years ago, now latest version is ASP.NET MVC 4. In there, a new data exchange technology between Client side and Server side is introduced, that’s ASP.NET WebAPI.
The WebAPI is running at server side to wait for calling from client side.

I will ignore the part of how to create an ASP.NET Web API project and directly jump into the code itself.

A good reference about how to create an ASP.NET Web API project can be found here on ASP.NET official site.

I created a model called Person first located in Model folder in the WebApi project.

public class Person
    {
        public string Id { get; set; }
        public string Name { get; set; }
        public int Age { get; set; }
    }

It’s a simple class with some properties. Then I created a Controller called PersonController in Control folder.

public class PersonController : ApiController
    {
        public HttpResponseMessage PutPerson(string id, Person p)
        {
            p.Name += " Updated by Server[PutPerson *]";
            return Request.CreateResponse<Person>(HttpStatusCode.OK, p);
        }

        public HttpResponseMessage CreatePerson(Person p)
        {
            p.Name += " Updated by Server[Post]";
            return Request.CreateResponse<Person>(HttpStatusCode.OK, p);
        }

        public HttpResponseMessage GetPerson()
        {
            var p = new Person(){Name ="Get Data From Server[Get]", Id="Test", Age=30};
            return Request.CreateResponse<Person>(HttpStatusCode.OK, p);
        }
    }

Because Web API supports GET, POST, PUT, DELETE actions, so the function name usually start with Get, Create, Put or Delete.

That’s it. First WebApi project is running and can be easily called by HttpClient or RestSharp. They will be discussed in next article.