REST

Labels
AJAX(112) App Studio(7) Apple(1) Application Builder(245) Application Factory(207) ASP.NET(95) ASP.NET 3.5(45) ASP.NET Code Generator(72) ASP.NET Membership(28) Azure(18) Barcode(2) Barcodes(3) BLOB(18) Business Rules(1) Business Rules/Logic(140) BYOD(13) Caching(2) Calendar(5) Charts(29) Cloud(14) Cloud On Time(2) Cloud On Time for Windows 7(2) Code Generator(54) Collaboration(11) command line(1) Conflict Detection(1) Content Management System(12) COT Tools for Excel(26) CRUD(1) Custom Actions(1) Data Aquarium Framework(122) Data Sheet(9) Data Sources(22) Database Lookups(50) Deployment(22) Designer(177) Device(1) DotNetNuke(12) EASE(20) Email(6) Features(101) Firebird(1) Form Builder(14) Globalization and Localization(6) How To(1) Hypermedia(2) Inline Editing(1) Installation(5) JavaScript(20) Kiosk(1) Low Code(3) Mac(1) Many-To-Many(4) Maps(6) Master/Detail(36) Microservices(4) Mobile(63) Mode Builder(3) Model Builder(3) MySQL(10) Native Apps(5) News(18) OAuth(8) OAuth Scopes(1) OAuth2(11) Offline(20) Offline Apps(4) Offline Sync(5) Oracle(10) PKCE(2) PostgreSQL(2) PWA(2) QR codes(2) Rapid Application Development(5) Reading Pane(2) Release Notes(180) Reports(48) REST(29) RESTful(29) RESTful Workshop(15) RFID tags(1) SaaS(7) Security(80) SharePoint(12) SPA(6) SQL Anywhere(3) SQL Server(26) SSO(1) Stored Procedure(4) Teamwork(15) Tips and Tricks(87) Tools for Excel(2) Touch UI(93) Transactions(5) Tutorials(183) Universal Windows Platform(3) User Interface(338) Video Tutorial(37) Web 2.0(100) Web App Generator(101) Web Application Generator(607) Web Form Builder(40) Web.Config(9) Workflow(28)
Archive
Blog
REST
Monday, September 24, 2012PrintSubscribe
jQuery Cross-Domain Static Client of a Web App

Integration with other service providers is a key to success of many SaaS business applications. The mail order company Northwind Traders has decided to expose their product catalog to third parties to increase sales. A back office web app has been created with Code On Time and configured to expose the product catalog.

An integration partner can put together a simple HTML page to display a list of products from http://demo.codeontime.com/northwind with a very few lines of code.

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <title>jQuery Cross-Domain Client</title>
    <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.8.1/jquery.min.js"></script>
    <script src="http://demo.codeontime.com/northwind/appservices/Products?_instance=ProductCatalog">
    </script>
    <script type="text/javascript">
        $(document).ready(function () {
            $.each(MyCompany.ProductCatalog.Products, function (index, product) {
                $('<option>')
                    .text(
                        product.ProductName + ' / ' +
                        product.CategoryCategoryName + ' / ' +
                        product.SupplierCompanyName + ' / ' +
                        product.UnitPrice)
                    .attr('value', product.ProductID)
                    .appendTo($('#ProductList'));
            });
        });
    </script>
</head>
<body>
    <select id="ProductList" size="20">
    </select>
</body>
</html>

The first script tag links jQuery library to the page straight from the Google’s CDN.

The second script references http://demo.codeontime.com/northwind/appservices/Products. This URL points to the demo web app. The highlighted component /appservices/Products references the REST URI of the Products data controller. The _instance parameter instructs the application to construct a JavaScript property with the name of ProductCatalog. The property will be assigned to MyCompany global variable that matches the namespace of the application.

The script executes as soon as the page has been loaded in the browser and iterates through MyCompany.ProductCatalog.Products array to populate the select element ProductList defined in the page body.

This is how the page will look if you have it opened in your default web browser.

A jQuery cross-domain static client of a web app in action

If you open the page straight from the hard drive in Internet Explorer, then you many need to allow running scripts for the list of products to get displayed.

Internet Explorer will prompt to Allow Blocked Content if the jQuery cross-domain static client file is opened directly from the file system

The product catalog is dynamically constructed by the web app every time it is requested.

This is how the array of products look in debug mode if global variable MyCompany is inspected in Visual Studio.

Global variable 'MyCompany' of a jQuery cross-domain static client of the demo web app is inspected in Visual Studio at runtime

If more than one resource pointing to the demo app controller is linked to the page then data will be available as properties of MyCompany global variable.

The Product Catalog data is downloaded by a web browser from the demo web app regardless of the domain of the HTML page or web platform that has served the page. This opens tremendous opportunities of integrating data in the third-party solutions.

Monday, September 24, 2012PrintSubscribe
Your Own Personal Application Server

Code On Time release 7.0.2.0 introduces a built-in application sever in web apps created with Unlimited edition. Developers are creating modern user interface forms based on the data controllers using drag & drop and cut/copy/paste. Customized data controllers provide powerful REST APIs that allow extending web apps created with Code On Time to any platform supporting REST, JSON, JSONP, and XML.

See an example of HTML form that allows submitting data to the web app database without a single line of code. Learn how to create a native Windows Client for your web app. More examples covering development of cross-domain and embedded jQuery scripts are coming soon. It is now possible to create custom user controls that take a full advantage of data controllers with the help of jQuery.

The following features, enhancements, and bug fixes are included in this release:

  • REST APIs allow extending web apps with no-code html forms, native clients, and jQuery scripts.
     
  • Parameters can be referenced in the SQL Formula definition of a field.
     
  • Web Site Factory projects include the app generator version number in JavaScript and CSS references.
     
  • Many-to-many business rules work correctly when removing data rows from tables with surrogate primary keys.
     
  • Method BusinessRules.Result.RefreshChildren will correctly refresh the child views.
     
  • The category of annotations remains invisible until activatied by the end user.
     
  • Data sheet view will correctly size the columns in "new" mode when annotations are enabled.
     
  • Adaptive filter dialog window will correctly handle Enter key to prevent re-submission of the page.
     
  • The selected row is correctly "forgotten" by a data view when it is not in the filtered set of data rows.
     
  • Inline lookup record creation will correctly reference the Data Value Field and Data Text Field of the lookup field when figuring the value and text that must be selected in the lookup.
     
  • The controller configuration caching is now performed to improve performance. Only once instance of a data controller configuration is customized when processing  a server request.
     
  • Designer maintains "collapsed" state of nodes in Project Explorer during drag & drop operations.
     
  • Designer correctly saves changed to the "Group" property of views.
     
  • DataViewExtender class is now declared as a partial class derived from DataViewExtenderBase, which makes it possible to override CSS and JavaScript registration.
     
  • Many-to-many field values (without aliases are displayed on reports. We are still working on making possible display of of alias values.
     
  • Blob handler sets HTTP status code to 404 if the blob stream length is zero.
Friday, September 21, 2012PrintSubscribe
Windows Client of a Web App

A web app created with Code On Time may function as an application server for a client on any platform.

Let’s create a native Windows Forms application that will allow browsing and searching products available at http://demo.codeontime.com/Northwind/Pages/Products.aspx.

This is how a Quick Find search is performed by the web app. The native Windows client will provide a similar presentation and search facility.

The 'Quick Find' feature in action in a web app created with Code On Time

Click on the following link and you will see a response in XML format from the REST service of the web application:
http://demo.codeontime.com/northwind/appservices/Products?_q=40%20biscuit

The response will look similar to this sample.

<?xml version="1.0" encoding="utf-8"?>
<Products totalRowCount="2" pageSize="100" pageIndex="0" rowCount="2">
  <items>
    <item ProductName="Sir Rodney's Marmalade" SupplierID="8" CategoryID="3" 
          QuantityPerUnit="30 gift boxes" UnitPrice="$81.00" UnitsInStock="40" 
          UnitsOnOrder="0" ReorderLevel="0" Discontinued="False" ProductID="20" 
          SupplierCompanyName="Specialty Biscuits, Ltd." 
          CategoryCategoryName="Confections" />
    <item ProductName="Sir Rodney's Scones" SupplierID="8" CategoryID="3" 
          QuantityPerUnit="24 pkgs. x 4 pieces" UnitPrice="$10.00" UnitsInStock="3" 
          UnitsOnOrder="40" ReorderLevel="5" Discontinued="False" ProductID="21" 
          SupplierCompanyName="Specialty Biscuits, Ltd." 
          CategoryCategoryName="Confections" />
  </items>
</Products>

The “_q” parameter represents the Quick Find argument of the web resource. If the parameter is not specified, then the first 100 items are returned. Other parameters for sorting, paging, and filtering are also supported.

The native Windows client of the Northwind application server will construct a similar URL to retrieve data for presentation.

Start Visual Studio and select File | New Project option. Choose Windows Forms Application under Visual C# or Visual Basic template group, enter “ProductBrowser” in the name, and click OK to create project files.

The empty 'Northwind Product Browser' project contains a single Windows Form

Drop TextBox, Button, and ListView components from toolbox on the design surface of Form1 and have them arranged as shown next.

Form 'Form1' enhanced with a TextBox, Button, and ListView components

Use Properties Window to modify the Columns collection of listView1. Create five columns Product Name, Supplier Company Name, Category Name, Quantity per Unit, and Unit Price to capture a few properties of products.

Five columns in the list view 'listView1' represent properties of products stored in the Northwind database

Also set the following properties of listView1 component:

Property Value
FullRowSelect True
GridLines True
View Details
VirtualMode True

The list view is configured to behave as a virtual view.

If the property VirtualListSize is set to a value other than zero then the virtual list view will request items from the application as needed.

The list view will continuously request items representing a visible subset of data rows as a user scrolls the list.

Right-click Form1 node in the Solution Explorer and select View Code option in the context menu.

Add the highlighted namespaces to the top of code file:

C#:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Net;
using System.Xml.XPath;
using System.IO;

namespace ProductBrowser
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }
    }
}

Visual Basic:

Imports System.Net
Imports System.Xml.XPath
Imports System.IO

Public Class Form1

End Class

The namespaces will link required .NET library components used by Windows native client to communicate with the web app.

Add fields _dataPage, _query, _cache, and method GetDataPage to the definition of class Form1.

C#:

protected XPathNavigator _dataPage;
protected string _query;

private SortedDictionary<int, XPathNavigator> _cache = new SortedDictionary<int, XPathNavigator>();

protected XPathNavigator GetDataPage(int pageIndex)
{
    XPathNavigator result = null;
    if (!_cache.TryGetValue(pageIndex, out result))
    {
        Cursor = Cursors.WaitCursor;
        try
        {
            WebRequest request = WebRequest.Create(String.Format(
                "http://demo.codeontime.com/northwind" +
                "/appservices/Products?_pageIndex={0}&_pageSize=10&_q={1}",
                pageIndex, _query));
            request.Method = "GET";
            using (WebResponse response = request.GetResponse())
            {
                using (Stream stream = response.GetResponseStream())
                    result = new XPathDocument(stream)
                        .CreateNavigator().SelectSingleNode("/Products");
            }
            _cache.Add(pageIndex, result);
        }
        finally
        {
            Cursor = Cursors.Default;
        }
    }
    return result;
}

Visual Basic:

Protected _dataPage As XPathNavigator
Protected _query As String

Private _cache As SortedDictionary(Of Integer, XPathNavigator) =
    New SortedDictionary(Of Integer, XPathNavigator)

Protected Function GetDataPage(pageIndex As Integer) As XPathNavigator
    Dim result As XPathNavigator = Nothing
    If Not (_cache.TryGetValue(pageIndex, result)) Then
        Cursor = Cursors.WaitCursor
        Try
            Dim request As WebRequest = WebRequest.Create(String.Format(
                "http://demo.codeontime.com/northwind" +
                "/appservices/Products?_pageIndex={0}&_pageSize=10&_q={1}",
                pageIndex, _query))
            request.Method = "GET"
            Using response As WebResponse = request.GetResponse()
                Using stream As Stream = response.GetResponseStream()
                    result = New XPathDocument(stream).
                        CreateNavigator().SelectSingleNode("/Products")
                    _cache.Add(pageIndex, result)
                End Using
            End Using
        Finally
            Cursor = Cursors.Default
        End Try
    End If
    Return result
End Function

The implementation of method GetDataPage creates a web request and retrieves the page of data from the web app if the page has not been found in the dictionary of cached data pages. The method parses the XML response received from the web app and stores an instance of XPathNavigator class initialized with a page data in the _cache field. The web request URI incorporates the requested page index and search criteria in _pageIndex and _q parameters accordingly.

Select listView1 in form designer and activate Properties Window, choose Events button, and double click RetrieveVirtualItem event.

Creating 'RetrieveVirtualItem' event handler for listView1 list view

Enter the following definition of the method listView1_RetrieveVirtualItem as shown next.

C#:

private void listView1_RetrieveVirtualItem(object sender, RetrieveVirtualItemEventArgs e)
{
    // analyze the current page item range
int pageIndex = Convert.ToInt32(_dataPage.GetAttribute("pageIndex", String.Empty)); int pageSize = Convert.ToInt32(_dataPage.GetAttribute("pageSize", String.Empty)); int rowCount = Convert.ToInt32(_dataPage.GetAttribute("rowCount", String.Empty)); int firstAvailableRowIndex = pageIndex * pageSize; int lastAvailableRowIndex = firstAvailableRowIndex + rowCount - 1; // if the current page does not contain the item then retrieve the page from the app if (!(firstAvailableRowIndex <= e.ItemIndex && e.ItemIndex <= lastAvailableRowIndex)) { pageIndex = e.ItemIndex / pageSize; firstAvailableRowIndex = pageIndex * pageSize; _dataPage = GetDataPage(pageIndex); } // create a virtual list item XPathNavigator dataRow = _dataPage.SelectSingleNode( String.Format("items/item[{0}]", e.ItemIndex - firstAvailableRowIndex + 1)); e.Item = new ListViewItem(dataRow.GetAttribute("ProductName", String.Empty)); e.Item.SubItems.Add(dataRow.GetAttribute("SupplierCompanyName", String.Empty)); e.Item.SubItems.Add(dataRow.GetAttribute("CategoryCategoryName", String.Empty)); e.Item.SubItems.Add(dataRow.GetAttribute("QuantityPerUnit", String.Empty)); e.Item.SubItems.Add(dataRow.GetAttribute("UnitPrice", String.Empty)); }

Visual Basic:

Private Sub listView1_RetrieveVirtualItem(sender As System.Object,
        e As System.Windows.Forms.RetrieveVirtualItemEventArgs) Handles listView1.RetrieveVirtualItem
    ' analyze the current page item range
    Dim pageIndex As Integer = Convert.ToInt32(_dataPage.GetAttribute("pageIndex", String.Empty))
    Dim pageSize As Integer = Convert.ToInt32(_dataPage.GetAttribute("pageSize", String.Empty))
    Dim rowCount As Integer = Convert.ToInt32(_dataPage.GetAttribute("rowCount", String.Empty))
    Dim firstAvailableRowIndex As Integer = pageIndex * pageSize
    Dim lastAvailableRowIndex As Integer = firstAvailableRowIndex + rowCount - 1
    ' if the current page does not contain the item then retrieve the page from the app
    If Not (firstAvailableRowIndex <= e.ItemIndex And e.ItemIndex <= lastAvailableRowIndex) Then
        pageIndex = e.ItemIndex \ pageSize
        firstAvailableRowIndex = pageIndex * pageSize
       _dataPage = GetDataPage(pageIndex)
    End If
    ' create a virtual list item
    Dim dataRow As XPathNavigator = _dataPage.SelectSingleNode(
        String.Format("items/item[{0}]", e.ItemIndex - firstAvailableRowIndex + 1))
    e.Item = New ListViewItem(dataRow.GetAttribute("ProductName", String.Empty))
    e.Item.SubItems.Add(dataRow.GetAttribute("SupplierCompanyName", String.Empty))
    e.Item.SubItems.Add(dataRow.GetAttribute("CategoryCategoryName", String.Empty))
    e.Item.SubItems.Add(dataRow.GetAttribute("QuantityPerUnit", String.Empty))
    e.Item.SubItems.Add(dataRow.GetAttribute("UnitPrice", String.Empty))
End Sub

Consult the sample of XML response at the top of article to understand the method implementation.

The implementation makes an assumption that a page of XML data is stored in the _dataPage instance of XPathNavigator. The property e.ItemIndex specifies the index of the item that the virtual list view needs. The code tries to determine if the current data page contains the item. If the item is not in current page _dataPage, then the application will retrieve a page of data from the web app by invoking GetDataPage method. The method will either find the page in the cache or reach out to the web app with a web request for data.

Next, the event handler will create an instance of a ListViewItem. Its sub-items represent the values displayed in the columns of the list view. The instance of the ListViewItem is assigned to e.Item property.

At this point the entire mechanism of populating the list view with data has been implemented.

The only remaining step is to collect user input for the search criteria and to assign a value to the VirtualListSize property of listView1.

Activate the design surface of Form1 and double-click the Find button. This will create an event handler that shall be defines as explained below.

C#:

private void button1_Click(object sender, EventArgs e)
{
    // assign the search criteria
    _query = textBox1.Text;
    // remove any previously cached data pages
    _cache.Clear();
    // get the first page of data with index "zero"
    _dataPage = GetDataPage(0);
    // figure the total number of rows in the virtual listview
    int totalRowCount = Convert.ToInt32(_dataPage.GetAttribute("totalRowCount", String.Empty));
    listView1.VirtualListSize = totalRowCount;
}

Visual Basic:

Private Sub button1_Click(sender As System.Object, e As System.EventArgs) Handles button1.Click
    ' assign the search criteria
    _query = textBox1.Text
    ' remove any previously cached data pages
    _cache.Clear()
    ' get the first page of data with index "zero"
    _dataPage = GetDataPage(0)
    ' figure the total number of rows in the virtual listview
    Dim totalRowCount As Integer = Convert.ToInt32(_dataPage.GetAttribute("totalRowCount", String.Empty))
    listView1.VirtualListSize = totalRowCount
End Sub

The implementation of button1_Click method copies the search criteria from the text box in the field _query.  Then it clears the previously cached data pages and obtains the first page of data. Last, the method will figure the size of the virtual list.

In less than a hundred lines of code a remarkable functionality has been brought to life.

Press F5 to start the Northwind Product Browser for Windows. Click the Find button.

Product Browser retreives pages of data from the web app as user scrolls the list view

Try scrolling the list of products. The Windows client will make at the most 8 requests to retrieve the 77 products from the Northwind database sample. The page size in this implementation is deliberately set to 10 items to ensure that a client-server interaction does occur upon scrolling.  If the page size is not specified then the default page size of 100 will be used.

Enter “40 biscuit” in the text box textBox1 and hit the button one more time. The two products matching the search criteria will be retrieved. Compare the result to the web app screenshot at the top.

Product Browser perform 'Quick Find' function with the help of the application server emdeded in the web app created with Code On Time

The same technique of data paging can be used in any application that supports XML or JSON data formats. That includes Java applications and mobile native Android and iPhone/iPad apps.