Sunday, 29 September 2013

Using jQuery Mobile Table Options With ASP.NET GridView

I think many of you are aware of the FriendlyUrls feature added to ASP.NET Web Forms 4.5. It is available by default with Visual Studio 2012 if you have installed Web Tools update 2012.2 or later and it is available by default in Visual Studio 2013 RC as well. FriendlyUrls makes URLs of the web forms application friendly and it enables the option of creating views for mobile devices as well. In the pages specific to mobile devices, we can use the front-end mobile frameworks like jQuery mobile or Sencha Touch.

The default ASP.NET Web Forms template contains an optimized master page for mobile view, Site.Mobile.Master. This will be the default master page for all mobile specific pages.

Using front-end frameworks with server control is a bit tricky, but it is possible to use. In this post, we will see the way to use jQuery mobile’s table options with ASP.NET GridView.

Let’s make the server control ready. In the mobile page, add a GridView and bind data to it. Following is the mark-up of the GridView and the Select method that binds data from Customers table of Northwind database:


<asp:GridView runat="server" ID="gvCustomers" SelectMethod="GetCustomers"></asp:GridView>

public IQueryable GetCustomers()
{
    NorthwindEntities ctx = new NorthwindEntities();
    return ctx.Customers.Take(10).Select(c => new { c.ContactName, c.CompanyName, c.City, c.Phone, c.Region });
}

I chose 5 properties to make the output simpler. The page should contain the view port metadata tag and the scripts and styles needed for jQuery mobile.
<meta name="viewport" content="width=device-width" />
<link href="Content/jquery.mobile.theme-1.3.2.min.css" rel="stylesheet" />
<link href="Content/jquery.mobile.structure-1.3.2.min.css" rel="stylesheet" />
<link href="Content/jquery.mobile-1.3.2.min.css" rel="stylesheet" />
<script src="Scripts/jquery-1.8.2.js"></script>
<script src="Scripts/jquery.mobile-1.3.2.js"></script>

The root div in the Site.Mobile has to be marked with data-role attribute to make jQuery mobile act on the content contained in the page.
<form id="form1" runat="server">
    <div data-role="page" id="home">
        <!-- Rest of the default mark-up -->
    </div>
</form>

Let’s make the GridView appear as the table in the demo on the jQuery Mobile site, so that the user will have an option to see some of the less necessary columns only when they are needed. To enable them, the GridView should be rendered as a table with thead and tbody. This can be done by setting the TableSelection property of the header row after data is bound to the GridView as shown below:
protected void gvCustomers_DataBound(object sender, EventArgs e)
{
    gvCustomers.HeaderRow.TableSection = TableRowSection.TableHeader;
}

To make the rendered table look like table in the demo on jQuery mobile site, following client properties have to be applied on the table:

  • Some CSS classes have to be applied on the table
  • data-role and data-mode attributes on the table
  • data-priority attribute on less important columns

These properties can be set in the DataBound event of the GridView. Add the following statements to the DataBound event of the GridView:

gvCustomers.CssClass = "ui-responsive table-stroke";
gvCustomers.Attributes.Add("data-role", "table");
gvCustomers.Attributes.Add("data-mode", "columntoggle");

var headerCells = gvCustomers.HeaderRow.Cells;
headerCells[3].Attributes.Add("data-priority", "2");
headerCells[4].Attributes.Add("data-priority", "2");

With this, we are done with applying the required settings. Load the page on a mobile emulator; it should look as shown below:




Happy coding!

Wednesday, 11 September 2013

A Better Way of Using ASP.NET SignalR With Angular JS

A few days back, I blogged on using SignalR and Angular JS together and on Implementing SignalR stock ticker sample using Angular JS(Part 1 and Part 2). In those posts, I have used the traditional call-back model to call the functions defined in controller to modify data whenever an update is received from the server.

One of the readers sent me feedback saying that we have a better way to use SignalR and Angular JS together. The way to go is using event methods defined on $rootscope object. This approach is based on publishing and subscribing events. As events can be published from anywhere and subscribed from anywhere, the source and destination will remain completely unaware of each other. Both of them have to depend on just one object, $rootScope.

Official documentation on scope contains details on each method defined on $rootScope. We will be using the following methods for publishing and subscribing the events:

  • $emit(name, args): Publishes an event with specified name with given arguments
  • $on(name, listener): Subscribes to an event with specified name. Listener is a function containing logic to be executed once the event has occurred

To manage SignalR’s client functionality, it is better to create a service, as services are singletons. There will be only one instance of the service in entire application. This behaviour of services makes it possible to have multiple SignalR client pages in the applications and they can be kept in sync without putting any extra amount of effort.

Let’s modify the example discussed in the post titled Hooking up ASP.NET SignalR with Angular JS to use event model. Server hub, references and structure of the HTML page remains the same as past. The only components to be modified are Controller and Service.

Service carries the responsibility to initialize a connection to the hub and call the SignalR’s server methods. Once a response is received from the server, we will broadcast an event from the service with data received.


app.service('signalRSvc', function ($, $rootScope) {
    var proxy = null;
 
    var initialize = function () {
        //Getting the connection object
        connection = $.hubConnection();
 
        //Creating proxy
        this.proxy = connection.createHubProxy('helloWorldHub');
 
        //Starting connection
        connection.start();
 
        //Publishing an event when server pushes a greeting message
        this.proxy.on('acceptGreet', function (message) {
            $rootScope.$emit("acceptGreet",message);
        });
    };
 
    var sendRequest = function () {
        //Invoking greetAll method defined in hub
        this.proxy.invoke('greetAll');
    };
 
    return {
        initialize: initialize,
        sendRequest: sendRequest
    }; 
});


To keep the things simple, I kept names of the server hub event and event rose using $emit the same. The names can be different. Let’s modify the controller to have a listener to the event raised by the service. Following is the implementation of the controller:

function SignalRAngularCtrl($scope, signalRSvc, $rootScope) {
    $scope.text = "";
 
    $scope.greetAll = function () {
        signalRSvc.sendRequest();
    }
 
    updateGreetingMessage = function (text) {
        $scope.text = text;
    }
 
    signalRSvc.initialize();
 
    //Updating greeting message after receiving a message through the event

    $scope.$parent.$on("acceptGreet", function (e,message) {
        $scope.$apply(function () {
            updateGreetingMessage(message)
        });
    });
}


Now open the modified page on multiple browsers and click the Greeting button randomly from all browsers. Messages printed on all browsers should be updated whenever the button is clicked. This behaviour is same as it was earlier. We just adopted a better approach to make it work.

Happy coding!

Sunday, 8 September 2013

Restricting Number of Suggestions in jQuery UI Auto Complete Using Underscore.js

jQuery UI’s autocomplete widget can be used with an array of objects or we can take complete control with by defining a function that emits the list of suggestions to be displayed. Restricting the count of suggestions to a given number is slightly tricky. There are several ways to skin this cat. In this post, we will see one of the ways to achieve the same using Underscore.js.

To make the number of suggestions configurable, a data- attribute can be used.

<input type="text" id="txtName" data-count="5" placeholder="Your name..." />

We need to define a source function to take control over suggestions to be displayed and filter data from the collection using underscore.js and value of the data-count attribute on the element. The source function should perform the following tasks:
  • Select a list of entries from the collection that contain the term entered using _.filter() function
  • Take first n(n being value of data-count attribute) entries from the filtered list using _.take() function
  • Pass the values selected in step 2 to response

var names=["Alex", "Andrew", "Andrea", "Anna", "Abbie", "Abraham", "Aisha", "Albert", "Albina", "Alisha", "Barbie", "Bailey", "Barton", "Bernardo", "Blaise", "Bobbie", "Blossom", "Brianna", "Buddy", "Byron", "Caesar", "Caleb", "Celicia", "Chalmer", "Chandra", "Cindi", "Clarence", "Codie", "Corey", "Cyrus"];
var textBox = $("#txtName");
textBox.autocomplete({
    minLength: 2,
    source: function(request, response){
        var filteredNames = _.take(_.filter(names, function(name){
            return name.toLowerCase().indexOf(request.term.toLowerCase()) != -1;
        }), textBox.data("count"));
        response(filteredNames);
    }
});

You can play with the sample on jsfiddle.


Happy coding!

Thursday, 5 September 2013

Exploring Web API OData Query Options

As I mentioned in the post on CRUD operations using Web API, OData has a lot of query options. The full listing of standard query options can be found on the official OData site. In this post, we will explore the query options supported by Web API and we will also see how to use these query options from .NET clients through LINQ queries.

Query support on Web API Data can be enabled in following two ways:

  • At the method level, by setting Queryable attribute on the Get method

    [Queryable]
    public IQueryable<Customer> Get()
    {
        .....
    }
  • When application starts, by calling EnableQuerySupport method on HttpConfiguration object

    GlobalConfiguration.Configuration.EnableQuerySupport();

To be able to explore more options, we will be using the Northwind database. Create an ADO.NET Entity Data model with following tables:

  • Customers
  • Orders
  • Employee

Let’s make these entities available to the Web API OData endpoint by adding them to an EDM model. Following statements accomplish this:


    var modelBuilder = new ODataConventionModelBuilder();
    modelBuilder.EntitySet<Customer>("Customers");
    modelBuilder.EntitySet<Order>("Orders");
    modelBuilder.EntitySet<Employees>("Employees");
    Microsoft.Data.Edm.IEdmModel model = modelBuilder.GetEdmModel();
    GlobalConfiguration.Configuration.Routes.MapODataRoute("ODataRoute", "odata", model);

Add a Web API controller named CustomersController and modify the code as:


public class CustomersController : ODataController
{
    NorthwindEntities context = new NorthwindEntities();

    public IQueryable<Customer> Get()
    {
        return context.Customers;
    }
}

Now we are all set to test the service. Run the project and change the URL on the browser to:


 localhost:<port-no>/odata

You should be able to see entries for each entity collection we added.



Now that the service is up and running, create a client project and add the service reference of the service just created (You may refer to my post on consuming OData from .NET clients post for setting up the client). Also, create a container object by passing URL of the Web API OData service.

Now that we have service and the client ready, let’s start exploring the different to query the service.

$filter:

All OData query options are query string based. $filter is the most basic and the most powerful of them. As the name suggests, $filter is used to select data out of a collection based on some conditions. The type conditions vary from simple equal to operator to string and date filtering operations.

As we already know, the following URL fetches details of all customers in the Northwind database:

    http://localhost:<port-no>/odata/Customers

Let’s add a condition to fetch details of customers with title Owner. Following URL gets the values for us:

    http://localhost:<port-no>/odata/Customers?$filter=ContactTitle eq 'Owner'

This filter can be applied from .NET client using the LINQ operator Where. Following is the query:


 var filteredCustomers = container.Customers.Where(c => c.ContactTitle == "Owner");

The above query is not fired in-memory. Instead, it generates the above URL by parsing the expressions passed into the LINQ operators. The generated URL can be viewed during debugging. Following screen-shot shows the URL generated by the above query:



As we see, it is same as the URL that we typed manually.

To select all customers with contact Ana at the beginning of their ContactName can be fetched using following URL:

 http://localhost:<port-no>/odata/Customers?$filter=startswith(ContactName,'Ana') eq true
The above query uses the OData function startswith() to compare initial letters of the field value. The corresponding LINQ query is:
    container.Customers.Where(c => c.ContactName.StartsWith("Ana"))

Similarly, endswith() can be used to compare suffix of a string. We can also check if a string is contained in a field using substringof() function.

 http://localhost:<port-no>/odata/Customers?$filter=substringof('ill',CompanyName)%20eq%20true

The corresponding LINQ query is:

    container.Customers.Where(c => c.CompanyName.Contains("ill"))

To get list of all customers with length of their names greater than 10 and less than 20, the URL is:
 http://localhost:<port-no>/odata/Customers?$filter=length(ContactName) gt 10 and length(ContactName) lt 20


You must have already guessed the LINQ query to achieve the same.

    container.Customers.Where(c => c.ContactName.Length > 10 && c.ContactName.Length < 20)

$filter supports querying based on numbers, dates and even checking types. You can get the full listing on the official site for OData.

$orderby:

Result can be ordered based on a field using $orderby operator. Syntax of specifying the operator is same as that of $filter operator. Following URL and the LINQ query fetch details of customers with names of the countries ordered in ascending order:

    http://localhost:<port-no>/odata/Customers?$orderby=Country 
    container.Customers.OrderBy(c => c.Country)

To make the order descending, we just need to specify the keyword desc at the end of the above URL.

$top and $skip

The server collections can be divided into pages from client using the $top and $skip operators. These operators are assigned with numbers that indicate the number of entries to be selected from the top or the number of entries to be skipped from the beginning of the collection.

Following URL and LINQ query select first 10 customers in the Customers table.


    http://localhost:<port-no>/odata/Customers?$top=10
    container.Customer.Take(10)

Syntax of using $skip is similar to that of $top, as $skip also expects a number to be passed in. Both $skip and $top can be used together to fetch data in several chunks. Following URL fetches 10 customers starting with index 40.

    http://localhost:<port-no>/odata/Customers?$skip=40&$top=10
    container.Customers.Skip(40).Take(10)

Paging can be forced from server side as well. If an entity set contains very huge amount of data, the requested client will have to wait for a long time to get the entire response from the server. This can be prevented by sending data in chunks from the server using server side paging. To get next set of values, the client has to send a new request to the server.

Server side paging:

Paging can be enabled on the server using PageSize property of the Queryable attribute. Following snippet applies a page size of 20 while returning a collection of customers:

    [Queryable(PageSize=20)]
    public IQueryable<Customer> Get()
    {
        return context.Customers;
    }
It can also be applied globally across all entity sets by setting the property to configuration object when the application starts, as follows:
    IActionFilter filter = new QueryableAttribute() { PageSize=20 };
    config.EnableQuerySupport(filter);
If you hit the URL to get all customers on your favorite browser after applying above changes, you will be able to see only 20 entries with a link to next set at the end of the result set, as shown in the following screen-shot:



As the URL is passed as a property of the JSON object, it can be easily extracted in any JavaScript client to send request for next set of values. But it is a bit tricky from .NET client. The collection LINQ query written on the client has to be converted to a DataServiceCollection to get the URL of the next request. It is shown below:


    var firstSetOfCustomers = new DataServiceCollection<Customer>(container.Customers);
    var nextSetOfCustomers = new DataServiceCollection<Customer>(container.Execute<Customer>(firstSetOfCustomers.Continuation.NextLinkUri));

Count of records on all pages can be obtained using the query option $inlinecount operator in the above query.
    http://localhost:<port-no>/odata/Customers?$inlinecount=allpages

    var firstSetOfCustomers = new DataServiceCollection<Customer>(container.Customers.IncludeTotalCount());

$expand:

ASP.NET Web API team added support of $expand and $select options in its latest release, which is version 5.0.0-rc1. It is built into Visual Studio 2013 Preview. In Visual Studio 2012, the NuGet package can be upgraded to the pre-release version.

$expand is used to include values of navigation properties of the queried entity set. The interesting part is the results of the navigation properties of the inner entity set can also be included in the result set. Following URL and LINQ query fetch details of Customers, their Orders and the details of the Employee who placed the Order.

    http://localhost:<port-no>/odata/Customers?$expand=Orders/Employee
    container.Customers.Expand("Orders/Employee");

The above query navigates till two levels down the entity set. Depth of the navigation can be controlled using the MaxExpansionDepth property on the Queryable attribute.
    [Queryable(MaxExpansionDepth=1)]
    public IQueryable<Customer> Get()
    {
        return context.Customers;
    }

This configuration can be applied on HttpConfiguration object when the application starts.

    IActionFilter filter = new QueryableAttribute() { MaxExpansionDepth=1 };
    config.EnableQuerySupport(filter);
After applying the above changes, the client cannot navigate to more than one level down the entity set.

$select:

A client can request for projected results based on its need. A list of properties to be fetched can be specified while querying the service to get only those properties. Following are a sample URL and the LINQ query:


    http://localhost:<port-no>/odata/Customers?$select=CustomerID,ContactName
    container.Customers.Select(c => new { ID = c.CustomerID, Name = c.ContactName });

Happy coding!

Tuesday, 27 August 2013

Consuming Web API OData using $resource service of Angular JS

In one of the previous posts, we saw exposing an OData Endpoint from an ASP.NET Web API service and then we consumed it using .NET and JavaScript clients. In this post, we will continue with consuming the service using Angular JS.

$resource is a wrapper around $http service of Angular JS to interact with RESTful data services. If we use $resource, we don’t need to deal with the low level HTTP calls that we used to do with $http.

Since $resource is targeted for REST based services, it has to be configured with the service URL and a few of other optional settings to get it work. Following snippet shows syntax of a sample configuration:


$resource(url, { key:val, .. }, {
    ‘getValues’: {method: ‘GET’, params: { param: val }, … },
    …
    …
});


$resource is not a part of Angular’s core module. To use $resource in an Angular JS application, the module ngResource has to be injected into the module depending on it. To know more about $resource, visit the official documentation page on website of Angular JS.

$resource can be configured to perform all of its operations on a single URL or even the URL can be over-written in the action configuration, if required. To consume a Web API OData service, we need to use the second approach as the URL differs based on the operation we will be performing.

Following factory returns a $resource object to perform CRUD operations on the OData resource:


var app = angular.module('employeeApp', ['ngResource']);
app.factory('employeeSvc', function ($resource) {
    var odataUrl = "/odata/Employees";
    return $resource("", {},
    {
        'getAll': { method: "GET", url: odataUrl },
        'save': { method: "POST", url: odataUrl },
        'update': { method: 'PUT', params: { key: "@key" }, url: odataUrl + "(:key)" },
        'query': { method: 'GET', params: { key: "@key" }, url: odataUrl + "(:key)" },
        'remove': { method: 'DELETE', params: { key: "@key" }, url: odataUrl + "(:key)" }
     });
});


This factory can be injected inside any component and used there. Each action configured above is exposed as a method on the object returned from the factory with a dollar($) symbol prepended to each of them. Since these methods deal with AJAX, they return a $q promise.

Following controller uses the methods defined above to operate on the data service:


app.controller('EmployeeCtrl', function ($scope, employeeSvc) {

    //Getting all employees and assigning to a scope variable           
    function refreshEmployees() {
        (new employeeSvc()).$getAll()
            .then(function (data) {
                $scope.employees = data.value;
            });
    };

    //Add a new employee to the resource
    function createEmployee(emp) {
        return emp.$save();
    };

    //Modify details of an existing employee
    function editEmployee(emp) {
        return (new employeeSvc({
            "Id": emp.Id, "Name": emp.Name, "Salary": emp.Salary
        })).$update({ key: emp.Id });
    };

    //Delete an employee
    function deleteEmployee(id) {
        return (new employeeSvc()).$remove({ key: id });
    };

    //rest of the controller definition.......
});


Take a look at the refreshEmployee function created above. It calls then() on the returned object from the $getAll() method to grab the response as soon as the GET request is completed. As Web API OData sets actual data to the property value, the scope variable is assigned with this property.

Happy coding!

Monday, 26 August 2013

Consuming Web API OData From .NET And JavaScript Client Applications

In last post, I created a Web API OData service that performs CRUD operations on an in-memory collection. In this post, we will consume the service from a .NET client and a web page.

Consuming Web API OData using a .NET client:

A Web API OData service can be consumed using WCF Data Services client. If you gave already worked with WCF Data Services, you already know about consuming Web API OData Service as well.

Right click on a .NET project and choose the option Add Service Reference. In the dialog, enter the OData service URL and click the Go button.



The dialog parses the metadata received from the server and shows the available entities under container as shown in the screenshot. As we created just one entity in the service, we see the entity Employee alone. Name the namespace as you wish and hit OK. Visual Studio generates some classes for the client application based on the metadata.

The generated code contains the following:

  1. A Container class, which is responsible for communicating with the service. It holds DataServiceQuery<TEntity> type properties for each EntitySet on the server
  2. A class for every entity type. This class contains all properties mapped on the server, information about key of the entity

A Container is much like a DbContext in Entity Framework. It handles all the operations. Container is responsible for building OData URLs and sending requests to the service for any operation that client asks for. Let’s start by creating a Container. Constructor of the container accepts a URI, which is base address of the Web API OData service.

Container container = new Container(new Uri("http://localhost:1908/odata"));


To fetch details of all employees, we need to invoke the Corresponding DataServiceQuery property.


var employees = container.Employees;

Although the statement looks like an in-memory operation, it generates the corresponding URL internally and calls the server. Similarly, to get details of an employee with a given Id, we can write a LINQ query as shown:

var employee = container.Employees.Where(e => e.Id == 3).FirstOrDefault();

The above query makes a call to the Get method accepting key in the Web API Controller.

To create a new employee, we need to create an object of the Employee class, add it and ask Container to save it. Following snippet demonstrates this:


Employee emp = new Employee() { Id = 0, Name = "Hari", Salary = 10000 };
container.AddToEmployees(emp);
container.SaveChanges();

Performing update is also much similar. The difference is with calling the SaveChanges method.

emp = container.Employees.Where(e => e.Id == 3).FirstOrDefault();
emp.Name = "Stacy";
container.UpdateObject(emp);
container.SaveChanges(SaveChangesOptions.ReplaceOnUpdate);

If SaveChanges is called with SaveChangesOptions.ReplaceOnUpdate, it performs PUT operation on the resource. If SaveChangesOptions.PatchOnUpdate is passed, it performs PATCH operation on the resource.

To delete an entry, we need to pass an object to DeleteObject method and just like earlier cases; we need to call the SaveChanges method on the Container.


container.DeleteObject(container.Employees.Where(e => e.Id == 3).FirstOrDefault());
container.SaveChanges();


Consuming Web API OData using JavaScript client:

To consume the Web API OData service from a web page, the service has to be called using AJAX. The client can send an AJAX request to the URL of the OData service by specifying an HTTP verb to operate on the resource. To make our life easier, let’s use jQuery for AJAX calls.

To get details of all employees, we need to send a GET request to the OData URL. Values of entries in the collection are stored in a property named value in the object received as response. Fetching details of an employee with a given Id also follows similar approach. Following snippet demonstrates this:


$.getJSON(“/odata/Employees”, function(data){
    $.each(data.value, function(){
        //Modify UI accordingly
    });
});

$.getJSON(“/odata/Employees(3)”, function(data){
        //Modify UI accordingly
});


To add a new employee, we need to send the new object to $.post along with the URL.

var employee = {
    "Id": 0,
    "Name": “Ravi”,
    "Salary": 10000
};

$.post(“/odata/Employees”, employee).done(function(data){
    //Modify UI accordingly
});


Unfortunately, jQuery doesn’t have a shorthand method for PUT. But it is quite easy with $.ajax as well. To perform PUT on the resource, the request should be sent to the specific address with an ID and the modified object should be passed with the request.

var employee = {
    "Id": 3,
    "Name": “Ravi”,
    "Salary": 10000
};

$.ajax({
url: "/odata/Employees(" + employee.Id + ")",
       type: "PUT",
       data: employee
});


Building request for DELETE is similar to put, we just don’t need to pass the object.

$.ajax({
url: "/odata/Employees(" + id + ")",
type: "DELETE"
});


Happy coding!

Saturday, 24 August 2013

Performing CRUD Operations in Web API OData Service using ODataController

OData is a protocol for operating on data over HTTP. OData follows REST architecture. It provides a uniform interface for interacting with data over web and performing CRUD (Create, Read, Update and Delete) operations. It also provides metadata so that the consuming application gets awareness about the types used in the service.

If you are new to OData and want to learn more, checkout the official website for OData and read David Chappel’s whitepaper on OData.

ASP.NET Web API is a solution for creating HTTP services. ASP.NET team added OData support to Web API in the ASP.NET and Web Tools 2012.2 Update. In this post, we will create a simple Web API OData service that performs CRUD operations on an in-memory object collection.

Setting up the project and data:

Fire Visual Studio 2012 or 2013 and create an ASP.NET MVC 4 project with Web API template or, add the following NuGet packages to an empty ASP.NET project:

  • Microsoft.Aspnet.WebApi.OData
  • Microsoft.AspNet.WebApi.WebHost

Let’s create our data components now. Add a new class to the project, name it Employee and add following properties to it:

public class Employee
{
    public int Id { get; set; }
    public string Name { get; set; }
    public double Salary { get; set; }
}
Add another class named EmployeesHolder. This class will hold a static collection of Employee class created above. We will perform CRUD operations on the data created in this class. Add the following code to the EmployeesHolder class:
public class EmployeesHolder
{
    public static List<Employee> Employees;

    static EmployeesHolder()
    {
        Employees = new List<Employee>();

        Employees.Add(new Employee() { Id = 1, Name = "Jack", Salary = 10000 });
        Employees.Add(new Employee() { Id = 2, Name = "Anthony", Salary = 7000 });
        Employees.Add(new Employee() { Id = 3, Name = "Tracey", Salary = 20000 });
        Employees.Add(new Employee() { Id = 4, Name = "Sherry", Salary = 6000 });
        Employees.Add(new Employee() { Id = 5, Name = "Hill", Salary = 16000 });
    }
}

Creating OData Route

We need to add some configurations when application starts to enable OData in the application. Before defining the route map, we need to build an EDM model with all entity sets to be exposed. It is done as shown below:

     var modelBuilder = new ODataConventionModelBuilder();
     modelBuilder.EntitySet<Employee>("Employees");
     Microsoft.Data.Edm.IEdmModel model = modelBuilder.GetEdmModel();

The ODataConventionalModelBuilder is used to map all entity sets that have to be exposed through OData endpoint. Alternatively, ODataModelBuilder can also be used for this purpose. But if we do so, we need to define each property and relationship using fluent configuration model. ODataConventionalModelBuilder does all that work for us. We just need to add the entity sets to be exposed.

We need to define the OData route using the EDM model created above. It is shown below:

config.Routes.MapODataRoute("ODataRoute", "odata", model);


Creating API Controller and performing read operations


Let’s define a Web API controller to perform CRUD operations over the collection created above. Add an API controller to the application named EmployeesController. Modify the parent class of this class as ODataController.
public class EmployeesController : ODataController
{
}

ODataController is the low-level class to work with OData in Web API. We need to directly deal with HTTP verbs and build response by hand using this class. We have higher level classes available that deal with the verbs. While using them we have to just worry about the data, rest of the things are taken care by the framework. But it is important to understand what is going on behind the scenes to get much of the work done. So, in this post we will create the API using ODataController.

Delete all the default code inside the controller. Add the following method to the controller:

public IQueryable<Employee> Get()
{
    return EmployeesHolder.Employees.AsQueryable();
}

Build and run this application now. Change the URL on your browser to:


http://localhost:<port-no>/odata/Employees


You should be able to see the list of all employees created above in your browser.



Notice the metadata URL in the first statement. Metadata information for the entire application is exposed through this URL.

Let’s add another method to the service that gets details of an employee based on ID.


public HttpResponseMessage Get([FromODataUri]int key)
{
    Employee employee = EmployeesHolder.Employees.Where(e => e.Id == key).SingleOrDefault();
    if (employee==null)
    {
        return Request.CreateResponse(HttpStatusCode.NotFound);
    }

    return Request.CreateResponse(HttpStatusCode.OK, employee);
}


The attribute FromODataUri indicates that the value has to be taken from the requested URL. Change the URL on the browser as:


http://localhost:1908/odata/Employees(2)


Now you should be able to see details of the second employee on the browser:



Web API OData supports a number of query options that can be used to query data from client application. We will explore those options in a future post.

Performing Create operation

HTTP Post method is for adding an item to the resource. It usually accepts data from the client in the HTTP request body. Following Post method adds a new employee to the list we created earlier:

public HttpResponseMessage Post([FromBody]Employee entity)
{
    string name = entity.Name;
    HttpResponseMessage response;
    double salary = entity.Salary;

    try
    {
        int employeeId = EmployeesHolder.Employees.Max(e => e.Id) + 1;

        entity.Id = employeeId;
        EmployeesHolder.Employees.Add(entity);

        response = Request.CreateResponse(HttpStatusCode.Created, entity);
        response.Headers.Add("Location", Url.ODataLink(new EntitySetPathSegment("Employees")));
        return response;
    }
    catch (Exception)
    {
        response = Request.CreateResponse(HttpStatusCode.InternalServerError);
        return response;
    }
}

As you see, the POST method returns a HttpResponseMessage object with the newly created entity embedded in the body. Location is explicitly added to the message because according to the HTTP specification, the location header has to be added to the response header once a POST request is succeeded. The API checks it and the consuming client will return an error if the location is not added.

To test this method, open Fiddler and switch to composer tab. Select POST method from the dropdown and enter the new employee object in JSON format in the request body as shown:



We can assign any value to Id. It will be ignored as we are calculating the next Id in the logic. Hit the Execute button to invoke the service method. Once you see the success status in fiddler, refresh the browser to see the updated employees list.



Performing Update Operation

Update can be performed using either patch or put verb. The difference between these verbs is patch performs partial update on the resource, whereas put replaces the entire entry with the new object received from the client. One of these or both can be chosen based on the needs of the application.

Following Put method modifies the entry at the provided Id in the Employees collection:


public HttpResponseMessage Put([FromODataUri]int key, [FromBody]Employee employee)
{
    var employeeToDeleteEdit = EmployeesHolder.Employees.Where(e => e.Id == key).FirstOrDefault();
    HttpResponseMessage response;
    string name = employee.Name;
    var salary = employee.Salary;

    int index = EmployeesHolder.Employees.FindIndex(e => e.Id == key);
    if (index >= 0)
    {
        EmployeesHolder.Employees[index].Name = name;
        EmployeesHolder.Employees[index].Salary = salary;
    }
    else
    {
        response = Request.CreateResponse(HttpStatusCode.NotFound);
        return response;
    }

    response = Request.CreateResponse(HttpStatusCode.OK, employee);
    return response;
}


Compose a PUT request on Fiddler as shown below:


Click on the Execute button to invoke the corresponding service method. Once the response is received from the server, refresh the browser to see the updated result.



Performing Delete Operation

Delete is a straight forward operation. It just accepts a key and deletes the object at that entry from the resource.


public void Delete([FromODataUri]int key)
{
    var employeeToDelete = EmployeesHolder.Employees.Where(e => e.Id == key).FirstOrDefault();
    if (employeeToDelete != null)
    {
        EmployeesHolder.Employees.Remove(employeeToDelete);
    }
    else
    {
        throw new HttpResponseException(HttpStatusCode.NotFound);
    }
}


Just like Post and Put, let’s test this method using Fiddler. Set a delete request as shown below:



Delete doesn’t accept any object in the body. Click the execute button and once the response is received, refresh browser to see the updated values.



As mentioned earlier, ODataController is the low-level class that helps us in building OData service. Web API’s OData assembly includes another controller that handles most of the plumbing like defining API methods and dealing with HttpResponseMessage. It is EntitySetController.We just need to override a set of methods to work with data in the data while using EntitySetController. Most of the tutorials on ASP.NET site use EntitySetController to work with OData.

Happy coding!

Thursday, 25 July 2013

Behaviour of Scope in Angular JS Directives

Directive is the coolest and most crucial feature provided by Angular JS. Use of scope in directives makes the process of writing a directive challenging. Behaviour of scope depends on the way it is assigned in the directive. Following are different scenarios of using scope inside directive:

  • Scope not assigned or set to false
  • Scope set to true
  • Isolated scope

Following is a simple controller with just one value assigned to scope that we will be using in a sample page:
var app = angular.module("myApp", []);

app.controller("SampleCtrl", ['$scope', function ($scope) {
    $scope.val = 0;
}]);


Let’s have a look at each of the above scenarios individually.

Scope not assigned or set to false:
Consider the following directive:
app.directive("dirWithoutScope", function () {
    return{
        scope:false,
        link: function (scope, elem, attrs, ctrl) {
            scope.val=20;
        }
    }
});

As the directive is not making any changes, scope of this directive remains same as the scope of its parent element. The statement in the link function modifies value of the property val, which is set in the controller. Both of the following span elements will display same value, which is 20.
<span>{{val}}</span>

<span dir-without-scope>{{val}}</span>


Scope set to true:
In this case, scope of the directive would be prototypically inherited from scope of its parent element. Let’s consider the following directive:

app.directive("dirWithScopeTrue", function () {
    return{
        scope:true
    }
});

As the scope is prototypically inherited, properties of the parent scope are accessible using this scope. The following span tag will still hold the value assigned to the parent scope:
<span dir-with-scope-true>{{val}}</span>

Let’s complicate the scenario a bit by adding the following link function to the above directive:
link: function (scope, elem, attrs, ctrl) {
    scope.val=25;
}

The value 25 isn’t assigned to the val property in the parent scope. Instead, this statement creates a new property in the child scope and assigns the value to it. The span element created above will hold the value 25 now.

If the value is set through $parent property of the scope, the value gets assigned to the parent scope.

$scope.$parent.val=25;

If statement of link function is replaced with the above statement, values in all span elements will change to 25.

Isolated scope:
If a new scope is created in the directive, the scope doesn’t inherit from the parent scope anymore. Properties of the parent scope are not accessible with the new scope. Following directive contains an isolated scope:

app.directive("dirWithBlankScope", function(){
    return{
        scope:{
        },
        link:function(scope, elem, attrs, ctrl){
            scope.val=30;
        }
    }
});

The assignment statement in the link function creates a property val in the new scope. It doesn’t alter the value of the property assigned in the controller or the previous directive. Following span prints value of the new property:
<span dir-with-new-scope>{{val}}</span>

Properties of the scope of parent element are still accessible through $parent property of the scope.
<span dir-with-new-scope>{{$parent.val}}</span>



Happy coding!