Forms, Reports, Apps

Build and deploy rapidly. Use offline, online, on-premises.

  Blog

Blog
Thursday, July 31, 2014PrintSubscribe
Generating Controller with Business Rules

 Code On Time generator offers the ability to compose controllers from the results of custom SQL scripts.

If a stored procedure is the data source, business rules must be used to compose a result set. This allows the application framework to perform sorting and filtering operations that would otherwise be performed by the database server.

Here is an example of a result set produced by a stored procedure called from an SQL business rule.

Data from the Employee Sales by Country stored procedure can be viewed, sorted, and filtered.

In this example, we will be using the “Employee Sales by Country” stored procedure, available with the Northwind sample database. The procedure combines data from Employees, Orders, and gets the total price (from Order Details) for each order in between the Beginning Date and Ending Date parameters. The CREATE script for the stored procedure can be seen below.

CREATE procedure dbo.[Employee Sales by Country] 
@Beginning_Date DateTime, @Ending_Date DateTime AS
SELECT    Employees.Country, 
        Employees.LastName, 
        Employees.FirstName, 
        Orders.ShippedDate, 
        Orders.OrderID, 
        "Order Subtotals".Subtotal AS SaleAmount
FROM Employees INNER JOIN 
    (Orders INNER JOIN "Order Subtotals" ON Orders.OrderID = "Order Subtotals".OrderID) 
    ON Employees.EmployeeID = Orders.EmployeeID
WHERE Orders.ShippedDate Between @Beginning_Date And @Ending_Date

Example output can be seen in the following picture.

Example output from the EmployeeSalesByCountry stored procedure.

Let’s generate this data controller.

Start the web app generator and activate the Project Designer. In the Project Explorer, switch to the Controllers  tab. Click on the New Controller icon on the toolbar.

Creating a new controller in the Project Explorer.

Give the controller a name:

Property Value
Name EmployeeSalesByCountry

Press OK to save the new controller. In the Project Explorer, right-click on the new controller and press “Generate From SQL…”.

Defining the new controller.

The Define Data Controller window will open. Paste in the following script:

EXEC dbo.[Employee Sales by Country] 
    @Beginning_Date = '1970-01-01', 
    @Ending_Date = '2000-01-01'

Press Verify and the result will be seen in the data grid, as in the picture below:

The script has been verified and the results can be seen in the data grid on the "Define Data Controller" window.

The Define Data Controller window also offers the option to define a Business Rule or the Command Text for the controller.

When “Command Text” is selected, the controller will have a command defined from the SQL script and will take advantage of the application framework’s ability to compose SQL statements on the fly. SQL formulas will be defined for each field. If specified, the “Base Table Name” property will be used in any dynamically created Insert and Update statements.

The “Business Rule” option will not generate a command for the controller. Instead, two SQL business rules will be created that prevent the default Select action from occurring and define a custom result set. In addition, three more business rules will be created to override the insert, update, and delete actions from occurring.

Keep default settings and press OK to define the data controller. The window will close and the Project Explorer will refresh with added fields, views, data fields, actions, as well as the command or business rules.

The EmployeeSalesByCountry controller has been defined.

Next, we will need to create a page and bind the controller to the page with a data view. Right-click on the controller and press Copy.

Copying the EmployeeSalesByCountry controller.

Switch to the Pages tab in the Project Explorer. Click on the New Page icon.

Creating a new page.

Assign a name.

Property Value
Name EmployeeSalesByCountry

Press OK to save the page. Drag the new page in the Project Explorer to the right of Home page node to place it second in the site menu.

Dropping the new page to the right of Home page node.     The Employee Sales By Country page has been placed after Home page node.

Right-click on the new page and press Paste to bind the controller to the page.

Using Paste command to bind the controller to the page.     A data view has been created for EmployeeSalesByCountry.

On the toolbar, press Browse to generate the app and open it in the default browser.

The result set will be visible on the page. The user can sort, filter, and view data. Note that additional programming will be required to allow the user to update, insert, or delete records.

Thursday, July 31, 2014PrintSubscribe
Creating Data Controller From Web Service

Code On Time web app generator automatically creates controllers for any specified tables and views from your database. In addition, you can define new controllers from any SQL query. One can also choose to display data from any data source using C# or Visual Basic business rules – you are only limited by your imagination.

In this example, let’s request a list of articles recently published on /blog. A sample application showing the blog posts can be seen below.

The list of posts retrieved from the web service is displayed in a list.

The URL that will be used to compose a REST request is the following:

http://www.blogger.com/feeds/2297698770491701674/posts/default/

You can see an example of the response with the essential items highlighted below.

<?xml version='1.0' encoding='UTF-8'?>
<?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?>
<feed xmlns='http://www.w3.org/2005/Atom' ...>
  ...
  <entry>
    ...
    <published>2014-07-13T22:25:00.000-07:00</published>
    <updated>2014-07-15T00:03:46.566-07:00</updated>
    ...
    <title type='text'>
      Map View, Master-Detail Pages, 
      Custom Result Sets, Client-Side APIs
    </title>
    <content type='html'>
      &lt;p&gt;&lt;a title="Code On Time generator creates line-of-business Web Apps ...
    </content>
    ...
  </entry>
  <entry>
    ...
    <published>2014-07-13T10:00:00.000-07:00</published>
    <updated>2014-07-13T17:11:25.294-07:00</updated>
    ...
    <title type='text'>Assigning a Theme to a Page</title>
    <content type='html'>
      &lt;p&gt;&lt;a title="Code On Time Generator is a premier web application ...
    </content>
    ...
  </entry>
  ...
</feed>

The code business rule will need to accept this XML, create a data table and convert each “entry” element into a data row. The data rows will have four columns – Published, Updated, Title, and Content.

Defining the Controller

The first step is to define a controller that will handle the data table. One possible way of defining the controller would be to simply create it in the Project Designer. However, let’s take advantage of the automatic field, view, data field, and action generation provided by the Define Data Controller tool.

Start the Project Designer. In the Project Explorer, switch to the Controllers tab and press the New Controller icon.

Creating a new controller in the Project Explorer.

Give the controller a name:

Property Value
Name Posts

Press OK to save the new controller. Expand the new controller in the Project Explorer, and right-click on the Fields node. Select New Field option.

Creating a new field in the Posts controller.

Define the following properties:

Property Value
Name Title
Type String
Length 256

Press OK to save. Create another field with these properties:

Property Value
Name Content
Type String
Html Encoding False

Save the field, and add another:

Property Value
Name Published
Type DateTime

Save, and add the Updated field:

Property Value
Name Updated
Type DateTime

Save the last field. Right-click on the controller, and press Generate From Fields.

Generating the controller from the field definitions.

This will proceed to generate views, data fields, actions, and several code business rules to override CRUD operations. No command will be created.

The controller has been generated from the fields.

The first code business rule will provide an outline for defining the result set. The next three rules simply override the Insert, Update, and Delete actions and call PreventDefault() method. The developer must implement these rules in order for the respective actions to work.

On the toolbar, press Browse to regenerate the app and create the code files. When complete, right-click on Posts / Business Rules / Select (Code / Before) – GetData business rule, and press Edit Rule In Visual Studio.

Editing the rule in visual studio.

The file will open in Visual Studio. The business rule will create a DataTable object by calling to CreatePostsDataTable() method. The default implementation of this method will simply return a data table with no data.

[Rule("GetData")]
public void GetDataImplementation(
    string title, 
    string content, 
    DateTime? published, 
    DateTime? updated)
{
    ResultSet = CreatePostsDataTable();
}
        
private DataTable CreatePostsDataTable()
{
    DataTable dt = new DataTable();
    dt.Columns.Add("Title", typeof(String));
    dt.Columns.Add("Content", typeof(String));
    dt.Columns.Add("Published", typeof(DateTime));
    dt.Columns.Add("Updated", typeof(DateTime));
    // 
    // Populate rows of table "dt" with data from any source 
    // (web service, file system, database, etc.)
    //
    return dt;
}

Let’s complete the implementation by providing the data for the data table. At the top of the file, add the following using/import directive:

C#:

using System.Xml;

Visual Basic:

Imports System.Xml

Then, replace the “Populate rows of table” comment after the data table is declared with the following code. The code will make a request to Blogger, read in each “entry” element and create a new data row in the table using the values of that element.

C#:

// get data into table
XmlReader reader = XmlReader.Create(
    "http://www.blogger.com/feeds/2297698770491701674/posts/default/");
reader.ReadToDescendant("entry");
while (reader.LocalName == "entry")
{
    DataRow r = dt.NewRow();
    XmlReader subtree = reader.ReadSubtree();

    if (subtree.ReadToDescendant("published"))
    {
        r["Published"] = subtree.ReadElementContentAsDateTime("published",
            "http://www.w3.org/2005/Atom");
        r["Updated"] = subtree.ReadElementContentAsDateTime("updated",
            "http://www.w3.org/2005/Atom");
        while (subtree.LocalName != "title")
            subtree.Read();
        r["Title"] = subtree.ReadElementContentAsString("title",
            "http://www.w3.org/2005/Atom");
        r["Content"] = subtree.ReadElementContentAsString("content",
            "http://www.w3.org/2005/Atom");

        dt.Rows.Add(r);
    }

    if (!reader.ReadToFollowing("entry") || reader.EOF)
        break;
}

Visual Basic:

Dim reader As XmlReader = XmlReader.Create(
                "http://www.blogger.com/feeds/2297698770491701674/posts/default/")
reader.ReadToDescendant("entry")
While reader.LocalName = "entry"
    Dim r As DataRow = dt.NewRow()
    Dim subtree As XmlReader = reader.ReadSubtree()

    If subtree.ReadToDescendant("published") Then
        r("Published") = subtree.ReadElementContentAsDateTime("published",
                                                              "http://www.w3.org/2005/Atom")
        r("Updated") = subtree.ReadElementContentAsDateTime("updated",
                                                            "http://www.w3.org/2005/Atom")
        While subtree.LocalName <> "title"
            subtree.Read()
        End While
        r("Title") = subtree.ReadElementContentAsString("title",
                                                        "http://www.w3.org/2005/Atom")
        r("Content") = subtree.ReadElementContentAsString("content",
                                                          "http://www.w3.org/2005/Atom")

        dt.Rows.Add(r)
    End If

    If Not reader.ReadToFollowing("entry") OrElse reader.EOF Then
        Exit While
    End If
End While

Make sure to save the file.

Adding the Page and Viewing the Results

Switch back to the Project Designer. Right-click on the Posts controller node, and press Copy.

Copying the 'Posts' controller.

Switch to the Pages tab in the Project Explorer. Click on the New Page icon.

Creating a new page from the Project Explorer.

Assign a name.

Property Value
Name Posts

Press OK to save the page. Drag the new page in the Project Explorer to the right of Home page node to place it second in the site menu.

Dropping the page on the left side of the Home page node.     The 'Posts' page has been placed second in the site menu.

Right-click on the new page and press Paste to bind the controller to the page.

Pasting onto the 'Posts' page.     The data controller has been bound with a data view.

On the toolbar, press Browse to generate and open the web app in the default browser. The list of posts retrieved from the web service is displayed on the page. Note that you must define a primary key before any of the items can be selected.

Thursday, July 24, 2014PrintSubscribe
Touch UI for Any Data, Anywhere (Stored Procedures, Web Services, etc.)

Code On Time release 8.0.7.0 introduces ability to generate custom data controllers directly from Project Designer. The source of data is up to you – the app generator will handle any data anywhere! Create amazing Touch and Desktop UI for data returned from stored procedures, web services, file system, etc.  The release also introduces a collection of important bug fixes and performance improvements. Continue reading for the full list.

Generating Controllers from Project Explorer

Create a new data controller, right-click the corresponding node in Project Explorer and choose Generate from SQL option to create a data controller based on a free-form SELECT statement , stored procedure, or any other SQL script .

'Generate from SQL' and 'Generate from Fields' options in Code On Time app generator.

“Command Text”  Controller

If the script is an arbitrary SELECT statement, then indicate that the script defines a command text. This option will configure a custom command for the data controller and ensure the maximum efficiency at runtime. You can also specify an optional “base” table name if you want the controller to support Update, Insert, and Delete.

Configuring a data controller based on arbitrary SELECT statement in Code On Time app generator.

Verify the script and click OK. Copy and paste the new controller on any page.

An app with Touch UI created with Code On Time.

“Business Rule” Controller

If you want to configure a data controller based on a stored procedure, then you will need to indicate that the script defines a business rule.

Configuring a data controller based on a stored procedure in Code On Time.

The controller will be enhanced with a collection of business rules. There will be no command.

Rule enableResultSet will instruct application framework to use the custom result set.

set @BusinessRules_EnableResultSet = 1
-- Enable caching of the result set. Duration is specified in seconds.
-- set @BusinessRules_ResultSetCacheDuration = 30 

Rule getData will produce the result set.

EXEC    [dbo].[Employee Sales by Country]
        @Beginning_Date = N'1/1/1980',
        @Ending_Date = N'1/1/2014'

Note that Update, Insert, and Delete are prevented by default.

set @BusinessRules_PreventDefault = 1
-- implement insert here

Implement your own business logic in the corresponding SQL or “Code” business rules. The output of the stored procedure will be stored in an instance of DataTable class. Developers can specify optional cache duration to improve performance of controllers based on “slow” stored procedures.

Business rules of a data controller based on a stored procedure displayed in Project Explorer of Code On Time app generator for desktop and mobile devices.

Drop the controller on a page to see it in action.

A data controller based on a stored procedure displayed in Touch UI application created with Code On Time.

“Thin Air” Controller

If you data is not coming from the database, then use another approach. Define a collection of fields for the new data controller. Right-click the data controller and choose Generate from Fields option. This will create a collection of “Code” business rules that produce an empty DataTable class instance with the columns matching the data controller fields.

A custom data controller produces data from 'thin' air in an app created with Code On Time.

Implement the code to populate the DataTable instance in the file that contains GetData business rule.

Imports MyCompany.Data
Imports System
Imports System.Collections.Generic
Imports System.Data
Imports System.Linq
Imports System.Text.RegularExpressions
Imports System.Web
Imports System.Web.Security

Namespace MyCompany.Rules

    Partial Public Class CustomDataSource3BusinessRules
        Inherits MyCompany.Data.BusinessRules

        ''' <summary>
        ''' This method will execute in any view before an action
        ''' with a command name that matches "Select".
        ''' </summary>
        <Rule("GetData")> _
        Public Sub GetDataImplementation()
            ResultSet = CreateCustomDataSource3DataTable()
        End Sub

        Private Function CreateCustomDataSource3DataTable() As DataTable
            Dim dt As DataTable = New DataTable()
            dt.Columns.Add("Title", GetType([String]))
            dt.Columns.Add("Published", GetType(DateTime))
            dt.Columns.Add("Reviewed", GetType(DateTime))
            '
            ' Populate rows of table "dt" with data from any 
' source (web service, file system, database, etc.) '
Dim r As DataRow = dt.NewRow() r("Title") = "Building modern applications with Code On Time" r("Published") = New DateTime(2014, 12, 15) dt.Rows.Add(r) Return dt End Function End Class End Namespace

Note that Update, Insert, and Delete commands are prevented by default. You can implement your own routines when needed. Also make sure that you have specified the primary key fields to allow selection of data .

Here is the data controller in a live application.

A data from 'thin' air displayed in an app with Touch UI created with Code On Time app generator.

This feature is available in all product editions. Detailed tutorials with step-by-step instructions will be published later this week.

Bug Fixes and Enhancements

The release includes an important fix for Unlimited edition users. Generated applications were failing previously if the browser was not supplying Accept Encoding header in HTTP requests, which resulted in a non-function page displayed to the end users in both Desktop and Touch UI. The web server was reporting HTTP error 400 (Bad request).

Application framework will also not execute custom business rules twice. The bug was introduced in the previous release.

Business rules are not executed for the selected and unchecked row when multiple selection is enabled in Desktop UI.

This is the list of other enhancements and bug fixes included in the release:

  • Non-IE desktop browsers will not report “Invalid date” message in Touch UI.
  • Touch UI updates all visible summary views in Touch UI when a page is resized.
  • Filter information and "Clear" option are displayed correctly in master and detail context menus in Touch UI.
  • Summary views in Touch UI do not wrap "See All" option on the next line.
  • Touch UI displays "Showing N items." message in the view description.
  • Item styles RadioButtonList, ListBox and CheckBoxList are now supported in Touch UI. The latter enables many-to-many fields.
  • Method $app.mobile.activeLink will not strip "focus" from the active tab on touch-enabled devices.
  • Touch UI now uses action header text, command name, and command argument to eliminate duplicate actions from the context menu. Previous implementation has relied on command name and argument only, which have resulted in “lost” context menu options.
  • Fixed the bug in Quick Find that was causing incorrect search results when fields "shorter" than the search sample are present in a grid/list view.
  • Navigating to a "hashed" url of a protected page will not cause a duplicate history event in webkit browsers.
  • Page title is displayed inline when sidebar is visible to allow more space for toolbar buttons.
  • Taphold on field value in a grid column will display a popup with a complete text of the field value if the value is partially hidden.
  • Touch UI allows static text selection with a mouse in desktop browsers.
  • Fixed page height decrease caused by a refresh of a summary view in Touch UI.
  • Removed "keyup" and "keydown" events causing appscrolling  event in wrappers in Touch UI applications.
  • Taphold can be done with Ctrl+Click when using a mouse in Touch UI applications. The other option is to press the mouse button down and holding it at least 750 milliseconds before release.
  • Fixed ResetSkipCount method to ensure that a correct page is loaded from Result Set under all conditions.
  • User and Role manager have been improved for a consistent behavior in Desktop and Touch UI apps.
  • Sync of selected key value is performed by application framework if the number of submitted key values matches the number of primary key fields.
  • Focus on an input field in Touch UI will also select the field value.
  • Blob key field is converted to a string when a check for "null" BLOB field is performed in Touch UI.
  • Removed icons-png folder from the ~/touch/images folder of generated apps. The complete set of SVG icons available in Touch UI are now listed in ~/touch/icons.html file includes in every project.
  • Fixed Export exception when server rules are null.
  • Ensured EnableMinifiedCss is generated for all users.

The next release will be out in early August of 2014. We expect to include further enhancements to the Touch UI and a new server-side Reporting API that will produce binary reports on the server. The feature will also be extended to Email Business Rules to enable reports as attachments.