Tuesday, 29 October 2013

Querying ASP.NET Web API OData using Breeze JS

A few days back I blogged about the query options supported by ASP.NET Web API OData. Though we get a number of options to query data from clients through REST-based URLs, building the URLs at runtime is not an easy task. One of the very popular ways to call services from rich JavaScript applications is through jQuery AJAX. While jQuery AJAX abstracts the pain of dealing with browser and configuring parameters, it expects an absolute URL. Writing a set of fixed URLs can be easy, but in larger applications we will have a number of scenarios where we need to build most part of an OData URL based on decisions. We can’t inspect any of the URLs unless a request is sent to them. It would be good to have an abstraction that generates the queries for us.

Breeze JS is the right library in such case. Breeze is built with OData query standards. But it is not limited to querying OData. Breeze can manage complex object graphs, cache data, query cached local objects, save complex objects to server, and perform validations and more. Breeze solves all the problems that one might face while working with data in rich JavaScript applications. In this post, we will see how Breeze simplifies querying OData services. We will explore some other essential features Breeze in future posts. To learn more about Breeze, make sure to check their official documentation and interactive tutorials on Breeze website.

Breeze uses jQuery for AJAX and Q for promises. Breeze needs data.js to talk to OData sources. Getting these scripts in Visual Studio is easy through the following NuGet packages:


Now add references to these libraries on the page.

<script src="~/Scripts/jquery-1.9.1.min.js"></script>
<script src="~/Scripts/datajs-1.1.1.min.js"></script>
<script src="~/Scripts/q.min.js"></script>
<script src="~/Scripts/breeze.min.js"></script>


Breeze heavily uses metadata of the data structure on which it has to work. ASP.NET Web API OData service exposes the metadata through its endpoint. But we need to set an important property to the OData configuration, it is Namespace. Adding the following statement to the Web API OData endpoint configuration:
modelBuilder.Namespace = "WebAPI_EF_OData.Models";

Make sure to check Brian Noyes’ step-by-step tutorial on Consuming ASP.NET Web API OData using Breeze. Brian does a nice job by explaining each step in detail.

Let’s set up Breeze on the client side. Add the following code to the page in which you want to perform breeze operations:

$(function () {
    var baseAddress = "/odata";
    breeze.config.initializeAdapterInstances({ dataService: "OData" });
    var manager = new breeze.EntityManager(baseAddress);
});

Now we can start using Breeze’s querying capabilities against the OData endpoint. Breeze uses LINQ-like operators to specify conditions on the data source. Following snippet shows a basic Breeze request to the EntitySet Customers and captures the response once it gets from the server:
var query = breeze.EntityQuery.from("Customers");
manager.executeQuery(query, function (data) {
    //Manipulate UI
}, function (err) {
    //Show Error Message
});

The above query sends a request to the URL http://localhost:/odata/Customers. Following query applies a simple condition on the above query:
var queryWithCondition = breeze.EntityQuery.from("Customers")
                                           .where("ContactTitle", "equals", "Owner");

This query corresponds to the URL http://localhost:/odata/Customers?$filter=ContactTitle eq 'Owner'. As stated earlier, Breeze is capable of expressing any OData URL. It has operators defined for orderby, checking length of strings, substrings, date operators, querying data as pages, expanding navigation properties and many others. Following listing shows a set of OData URLs and their corresponding Breeze queries.
// http://localhost:<port-no>/odata/Customers?$filter=startswith(ContactName,'Ana') eq true
var queryStartsWith = breeze.EntityQuery.from("Customers")
                                        .where("ContactName", "startsWith", "Ana");

// http://localhost:<port-no>/odata/Customers?$filter= not startswith(ContactName,'Ana') eq true
var Predicate = breeze.Predicate;
var predicate = new Predicate("ContactName", "startsWith", "Ana").not();
var queryNotStartsWith = breeze.EntityQuery.from("Customers")
                                           .where(predicate);

// http://localhost:<port-no>/odata/Customers?$filter=substringof('ill',CompanyName) eq true
var queryContainsSubstring = breeze.EntityQuery.from("Customers")
                                               .where("CompanyName", "contains", "ill");

// http://localhost:<port-no>/odata/Customers?$filter=length(ContactName) gt 10 and length(ContactName) lt 20
var queryCheckingLength = breeze.EntityQuery.from("Customers")
                                                           .where("length(ContactName)", "greaterThan", "10")
                                                            .where("length(ContactName)", "lessThan", "20");

// http://localhost:<port-no>/odata/Customers?$orderby=Country
var queryOrderBy = breeze.EntityQuery.from("Customers")
                                     .orderBy("Country");

// http://localhost:<port-no>/odata/Customers?$top=10
var queryTop10 = breeze.EntityQuery.from("Customers")
                                   .top(10);

// http://localhost:<port-no>/odata/Customers?$skip=40&$top=10
var queryTopAndSkip = breeze.EntityQuery.from("Customers")
                                        .top(10).skip(40);

// http://localhost:<port-no>/odata/Customers?$inlinecount=allpages
var queryInlineCount = breeze.EntityQuery.from("Customers")
                                         .inlineCount(true);

// http://localhost:<port-no>/odata/Customers?$expand=Orders/Employee
var queryExpand = breeze.EntityQuery.from("Customers")
                                    .expand("Orders/Employee");

// http://localhost:<port-no>/odata/Customers?$select=CustomerID,ContactName
var querySelect = breeze.EntityQuery.from("Customers")
                                    .select("CustomerID, ContactName");

This is not the end. I created this list as it will serve as a one stop reference for me and hopefully for you as well! Most of the operators look and behave like LINQ operators. Check API documentation on the official site to get details on each of the operators used above.

Happy coding!

Thursday, 24 October 2013

Making Bootstrap UI Accordion work with Bootstrap 3

The latest templates of Angular UI Bootstrap don’t play well with Bootstrap 3. A few days back, I tried using the accordion directive of Bootstrap UI and was disappointed with the outcome. It happened so because of the CSS classes. There are significant differences between the CSS classes in version 2.x and 3.0.

In the templates file, there are two templates defined for accordion, accordion.html and accordion-group.html. To make the accordion work with Bootstrap 3, we need to modify the CSS classes used in the directive. Following are the modified templates:

angular.module("template/accordion/accordion-group.html", []).run(["$templateCache", function ($templateCache) {
    $templateCache.put("template/accordion/accordion-group.html",
      "<div class=\"panel panel-default\">\n" +
      "  <div class=\"panel-heading\" ><a class=\"accordion-toggle\" ng-click=\"isOpen = !isOpen\" accordion-transclude=\"heading\">{{heading}}</a></div>\n" +
      "  <div class=\"panel-collapse collapse in\" collapse=\"!isOpen\">\n" +
      "    <div class=\"panel-body\" ng-transclude></div>  </div>\n" +
      "</div>");
}]);

angular.module("template/accordion/accordion.html", []).run(["$templateCache", function ($templateCache) {
    $templateCache.put("template/accordion/accordion.html",
      "<div class=\"panel-group\" ng-transclude></div>");
}]);


Make these changes and use the accordion directive just as in Bootstrap 2.
<div data-accordion="" data-close-others="true">
        <div data-accordion-group="" data-heading="Heading 1">
            Contents in first group
        </div>
        <div data-accordion-group="" data-heading="Heading 2">
            Contents in second group
        </div>
</div>


Out of other directives, some of them work well with Bootstrap 3 classes, but some of them don’t. Tweaking other directives may not be this easy. But there are ways to make them work.

Update (Jan 2014): Bootstrap UI for Bootstrap 3 is officially released. Refer to the project's source for the template.

Happy coding!

Thursday, 17 October 2013

Basics: Reasons to move from DataTables to Generic Collections

I think, these days no community member writes or speaks about using DataTables and DataSets for data operations. But, there are a number of real projects built using them and many developers still feel happy when they use them in their projects. Sometimes it is not easy to completely replace DataTables with typed generic lists, particularly in bulky projects. But now is the right time to move as future developers may not even learn about DataTables :).

Generic collections have a number of advantages over DataTables. One cannot imagine a day without generic collections once he/she gets to know how beneficial they are. Following is a list of reasons to move from DataTables to collections that I could think now:
  1. DataTable stores boxed objects, one needs to unbox value when needed. This adds overhead on the runtime environment. Whereas, values in generic collections are strongly typed, so no boxing involved.
  2. Unboxing happens at runtime, so is the type checking. If there is a mismatch between types of source and target, it leads to a runtime exception. This may lead to a number of issues while using DataTables. In case of collections, as the types are checked at the compile time, such type mismatches are caught during compilation.
  3. .NET languages got a very nice support for creating collections, like object initializer and collection initializer. We don’t have such features for DataTables.
  4. LINQ queries can be used on both DataTables as well as collections. But experience of writing the queries on generic collections is better because of intellisense support provided by Visual Studio.
  5. DataTables are framework specific; we often see issues with serializing and de-serializing them in web services. Generic collections are easier to serialize and de-serialize, so they can be easily used in any service and consumed from a client written in any language.
  6. ORMs are becoming increasingly popular and they use generic collections for all data operations.
  7. Mocking DataTables in unit tests is a pain, as it involves creating the structure of the table wherever needed. But a generic collection needs a class defined just once.

These are my opinions on preferring collections over DataTables. Any feedback is welcome.

Happy coding!