Designer

Labels
AJAX(112) App Studio(9) 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(178) 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(9) OAuth Scopes(1) OAuth2(13) Offline(20) Offline Apps(4) Offline Sync(5) Oracle(11) PKCE(2) Postgre SQL(1) PostgreSQL(2) PWA(2) QR codes(2) Rapid Application Development(5) Reading Pane(2) Release Notes(184) Reports(48) REST(29) RESTful(29) RESTful Workshop(15) RFID tags(1) SaaS(7) Security(81) SharePoint(12) SPA(6) SQL Anywhere(3) SQL Server(26) SSO(1) Stored Procedure(4) Teamwork(15) Tips and Tricks(87) Tools for Excel(3) 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
Designer
Thursday, July 31, 2014PrintSubscribe
Generating Controller from SQL Query

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

The script can range in complexity from performing a simple “select *” from a table to any complicated SQL expression to combine fields from multiple tables.

Here is an example of a result set produced by an arbitrary SQL query.

The result of the SQL query can be viewed in the browser.

In this example, we use a script that displays fields from tables Customers, Orders, Order Details, and Products by using joins on the foreign keys CustomerID, OrderID, and ProductID. The query can be seen below.

SELECT CompanyName, OrderDate, ProductName, Quantity 
    FROM Customers 
        JOIN Orders 
            JOIN [Order Details] 
                JOIN Products 
                ON [Order Details].ProductID = Products.ProductID 
            ON Orders.OrderID = [Order Details].OrderID 
        ON Customers.CustomerID = Orders.CustomerID 

Example output can be seen in the following picture.

Results of the query.

Let’s generate a data controller for this query.

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 ItemsOrderedByCustomer

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 ItemsOrderedByCustomer controller

The Define Data Controller window will open. Paste in the script at the beginning of this article. Press Verify and the result will be seen in the data grid, as in the picture below:

Verifying the results of the query in the "Define Data Controller" window.

Select “Command Text” radio button. This will use the SQL script as a command 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.

The “Base Table Name” property will be used in any dynamically created Insert and Update statements. Leave this property blank for now.

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 data controller has been defined and now has a command.

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 'ItemsOrderedByCustomer' data controller.

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

Creating a new page in the web app.

Assign a name.

Property Value
Name ItemsOrderedByCustomer

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 'Items Ordered By Customer' page to right side of Home page node.     The 'Items Ordered by Customer' page is now second in the app menu.

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

Pasting into the 'Items Ordered by Customer' page.     The controller has been bound to the page with a data view.

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

The result of the query will be visible on the page. The user can sort, filter, and view data.

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.

Tuesday, March 4, 2014PrintSubscribe
Changing Application Baseline in Text Editor

Code On Time web application generator automatically creates a baseline application straight from your database. For example, if you follow instructions explaining creation of the Northwind sample then a complete web application will be displayed in your web browser without much effort on your part.

'Products' page of the automatically geneated Web Site Factory project

Application generator enumerates all database tables and views specified by the developer to compose the pages and data controllers.

One page is created for each database table or view. The generator will use foreign key relationships that exist in the database to create the baseline navigation menu.

One data controller is composed for each database table. A typical data controller describes available fields, user interface presentation views, and an action state machine in XML format. The framework of the generated application knows how to interpret the contents of the data controller files.

A typical baseline application page defines the data views linked to data controllers.

All pages are stored in the single file Application.Baseline.xml.

All data controllers are stored in the single file Controllers.Baseline.xml.

Both files can be found in the root folder of your project.

This is the snippet from the application baseline that defines the Products page.

<page name="Products" title="Products" description="View Products" index="1080" 
      path="Categories | Products" generate="always" style="Generic">
  <containers>
    <container id="container1" flow="NewRow" />
    <container id="container2" flow="NewRow" style="padding-top:8px" />
  </containers>
  <dataViews>
    <dataView id="view1" controller="Products" view="grid1" showInSummary="true" 
              container="container1" activator="None" text="" />
    <dataView id="view2" controller="OrderDetails" view="grid1" text="Order Details" 
              filterSource="view1" container="container2" filterFields="ProductID" 
              activator="Tab" autoHide="Container" pageSize="5" showModalForms="true" />
  </dataViews>
  <controls />
  <about>This page allows products management.</about>
</page>

Next snippet shows abbreviated definition of the Products data controller. This data controller is referenced by the page definition above.

<dataController name="Products" conflictDetection="overwriteChanges" label="Products" 
                nativeSchema="dbo" nativeTableName="Products">
  <commands>
    <command id="command1" type="Text">
      <text> select
        "Products"."ProductID" "ProductID"
        ,"Products"."ProductName" "ProductName"
        ,"Products"."SupplierID" "SupplierID"
        ,"Supplier"."CompanyName" "SupplierCompanyName"
        ,"Products"."CategoryID" "CategoryID"
        ,"Category"."CategoryName" "CategoryCategoryName"
        ,"Products"."QuantityPerUnit" "QuantityPerUnit"
        ,"Products"."UnitPrice" "UnitPrice"
        ,"Products"."UnitsInStock" "UnitsInStock"
        ,"Products"."UnitsOnOrder" "UnitsOnOrder"
        ,"Products"."ReorderLevel" "ReorderLevel"
        ,"Products"."Discontinued" "Discontinued"
        from "dbo"."Products" "Products"
        left join "dbo"."Suppliers" "Supplier" on "Products"."SupplierID" = "Supplier"."SupplierID"
        left join "dbo"."Categories" "Category" on "Products"."CategoryID" = "Category"."CategoryID"
    </text>
    </command>
    <command id="ProductIDIdentityCommand" type="Text" event="Inserted">
      <text>select @@identity</text>
      <output>
        <fieldOutput fieldName="ProductID" />
      </output>
    </command>
  </commands>
  <fields>
    <field name="ProductID" type="Int32" allowNulls="false" isPrimaryKey="true" 
           label="Product#" readOnly="true" />
    <field name="ProductName" type="String" allowNulls="false" 
           label="Product Name" showInSummary="true" />
    <field name="SupplierID" type="Int32" label="Supplier#" showInSummary="true">
      <items style="Lookup" dataController="Suppliers" newDataView="createForm1" />
    </field>
    <field name="SupplierCompanyName" type="String" readOnly="true" 
           label="Supplier Company Name" />
    <field name="CategoryID" type="Int32" label="Category#" showInSummary="true">
      <items style="Lookup" dataController="Categories" newDataView="createForm1" />
    </field>
    <field name="CategoryCategoryName" type="String" readOnly="true" label="Category Name" />
    <field name="QuantityPerUnit" type="String" 
           label="Quantity Per Unit" showInSummary="true" />
    <field name="UnitPrice" type="Decimal" default="((0))" label="
           Unit Price" showInSummary="true" />
    <field name="UnitsInStock" type="Int16" default="((0))" label="Units In Stock" />
    <field name="UnitsOnOrder" type="Int16" default="((0))" label="Units On Order" />
    <field name="ReorderLevel" type="Int16" default="((0))" label="Reorder Level" />
    <field name="Discontinued" type="Boolean" allowNulls="false" 
           default="((0))" label="Discontinued" />
  </fields>
  <views>
    <view id="grid1" type="Grid" commandId="command1" label="Products">
      <headerText>$DefaultGridViewDescription</headerText>
      <dataFields>
        <dataField fieldName="ProductName" columns="40" />
        <dataField fieldName="SupplierID" aliasFieldName="SupplierCompanyName" />
        <dataField fieldName="CategoryID" aliasFieldName="CategoryCategoryName" />
        <dataField fieldName="QuantityPerUnit" columns="20" />
        <dataField fieldName="UnitPrice" dataFormatString="c" columns="15" />
        <dataField fieldName="UnitsInStock" columns="15" />
        <dataField fieldName="UnitsOnOrder" columns="15" />
        <dataField fieldName="ReorderLevel" columns="15" />
        <dataField fieldName="Discontinued" />
        </dataField </view>
    <view id="editForm1" type="Form" commandId="command1" label="Review Products"> . . . . .
    </view>
    <view id="createForm1" type="Form" commandId="command1" label="New Products"> . . . . .
    </view>
  </views>
  <actions>
    <actionGroup id="ag1" scope="Grid">
      <action id="a1" commandName="Select" commandArgument="editForm1" />
      <action id="a2" commandName="Edit" />
      <action id="a3" commandName="Delete" />
      <action id="a6" />
      <action id="a7" commandName="Duplicate" commandArgument="createForm1" />
      <action id="a8" commandName="New" commandArgument="grid1" />
    </actionGroup> . . . . .
  </actions>
</dataController>

Notice that the page Products is also referencing the OrderDetails data controller, which is not shown.

The Products data controller is referencing Categories and Suppliers data controllers in the definitions of CategoryID and SupplierID fields.

Multiple pages can reference the same data controller, which significantly simplifies application maintenance. Change one data controller and the changes will propagate to all application pages that make use of it.

The application generator creates Application.Baseline.xml and Controllers.Baseline.xml files the first time the application is generated.

Web application generator also creates Application.Cache.xml and Controllers.Cache.xml files that initially represent the exact copies of the baseline files.

'Baseline' and 'Cache' versions of applications and data controllers are stored in the root folder of the generated web application.

The project generation scripts will read the Application.Cache.xml file and create physical ASP.NET Web Forms for each page. The web forms make use of the standard ASP.NET components and some custom components that come with the application framework.  The complete source code of the entire application framework is included in the generated code base.
The project generation scripts will also split the Controllers.Cache.xml file into multiple data controller files. Web Site Factory projects have all data controllers stored in the ~/Controllers folder. Other types of projects have the data controllers stored in the Controllers folder of the application class library. The definitions of data controllers found in the application folders are shorter and do not have some elements and attributes required by the code generator and Project Designer.

Developers can use the Project Designer to modify the application pages and data controllers.

Properties of 'Products'.'SupplierID' field displayed in Project Designer

The log of changes is automatically recorded in Application.Log.xml and Controllers.Log.xml files. The Project Designer simultaneously updates the contents of Application.Cache.xml and Controllers.Cache.xml files.
The basic relationship of the files is as follows:

Application.Baseline.xml + Application.Log.xml = Application.Cache.xml
Controllers.Baseline.xml + Controllers.Log.xml = Controllers.Cache.xml

If the contents of the database have changed then the data controller baseline of the project can be refreshed. The application generator will delete the “cache” versions of the files and re-apply the contents of the logs to the baselines to produce the new “cache” versions.

Refreshed data controllers of the project will be replaced in the baseline or removed from it.

New data controllers will be added to the baseline for the new database tables and views included in the project. The application generator will also compose a new host page for each new data controller and include it under New Pages navigation option of the site menu.

The Project Designer offers a logical view of the objects. Developers can browse the generated applications and visually inspect and change the properties of various application elements.

Experienced developers may find that the data controller XML files are fairly easy to understand. Data controller files are physical components of your project required at runtime. If you change the data controllers then the changes will be reflected in the application instantly.

You have to remember that the data controller files are the “byproduct” of the application generation process. Direct changes to the data controller will be lost if the project is regenerated.

The same applies to the application pages.

Avoid changing the data controllers and pages in the text editor and either use  the Project Designer or modify the data controller and application baseline instead.

Notice that you can define custom controls that are placed on the application pages. The custom controls are generated as ASP.NET User Controls and can be configured to be produced the “first time only”. Such controls can in fact be modified in the text editor without loosing the changes.

We recommend using Visual Studio or Visual Web Developer when working with the baseline files. Code completion available in these tools will speed up the development process and will highlight the markup errors if any.

Code completion is available in Visual Studio when editing the Application and Controllers baselines.

If you make changes to the baseline files then the changes will not take effect until your refresh the project.

Start the application generator, click on the project name and choose the Refresh action.

Do not select any data controllers in the list. Simply click the Refresh button at the bottom of the dialog to initiate the refresh process. Proceed to generate the application to see the changes in action.

Project 'Refresh' Dialog

Select the data controllers only if you want them to be replaced by the application generator. The application generator will compose a brand new temporary baseline and replace any selected data controllers with their new versions from the temporary file.

You can also create copies of data controllers directly in the baseline.

For example, open the Controllers.Baseline.xml file in the editor and copy the Products controller to the clipboard. Paste the controller right next to the original and remove “nativeSchema” and “nativeTableName” attributes from “dataController” element of the copy.

<dataController name="MyProducts" conflictDetection="overwriteChanges" label="My Products" >
  . . . . .
</dataController>
<dataController name="Products" conflictDetection="overwriteChanges" label="Products" 
                nativeSchema="dbo" nativeTableName="Products" 
                xmlns="urn:schemas-codeontime-com:data-aquarium">
  . . . . .
</dataController>

The application generator will treat MyProducts data controller as a custom data controller. Custom data controller is the controller that cannot be matched to any of the tables or views included in your application. The matching is done by comparing nativeSchema and nativeTableName attributes of controllers. Removal of these attributes turns the copy into a custom data controller.

Once again select the project Refresh action. The new controller will be in the list. It has a green icon indicating its special status.

'Refresh' dialog with the custom data controller 'MyProducts'

Do not select the custom controller, click the Refresh button to complete the refresh. If you select the data controller then the refresh process will simply remove it from the baseline.

Activate the Project Designer to see the properties of the custom data controller.  The next screen shot shows the custom data controller MyProducts structure in the Project Explorer. The original data controller Products is highlighted in the hierarchy.

Structure of the custom data controller 'MyProducts' displayed in the Project Explorer. The original controller 'Products' is highlighted in the hierarchy.

Use the custom data controller as you would use any other data controller of your application.

The application and data controller baselines will coexist with the changes done in the Project Designer. Keep in mind that your baseline definitions are combined with the logged modifications produced in the Designer. The final combined result is stored in the “cache” files. The “cache” files are the foundation of the actual application generated by Code On Time.

Individual Baseline Controllers

An alternative way of defining baseline controllers is to create a separate controller file. The name of this file must end with “.baseline.xml”. When refreshing the project, the app generator will scan for files matching the name and inject controllers defined in this file into the baseline. If the name of the controller matches one in the baseline, then the baseline controller will be replaced.