Blog: Posts from February, 2019

AJAX(112) App Studio(2) Apple(1) Application Builder(244) 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(100) Firebird(1) Form Builder(14) Globalization and Localization(6) How To(1) Hypermedia(2) Inline Editing(1) Installation(4) 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(17) OAuth(8) OAuth Scopes(1) OAuth2(10) Offline(19) 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(171) 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) Stored Procedure(4) Teamwork(15) Tips and Tricks(85) Tools for Excel(2) Touch UI(93) Transactions(5) Tutorials(183) Universal Windows Platform(3) User Interface(335) Video Tutorial(37) Web 2.0(100) Web App Generator(101) Web Application Generator(607) Web Form Builder(40) Web.Config(9) Workflow(28)
Posts from February, 2019
Tuesday, February 12, 2019PrintSubscribe
Sort Order of Item in Data Lookups
This is the view createForm1 of Products controller. Lookup field CategoryID is configured as a radio button list. Each list item represents a row from Categories lookup table. Items are sorted in an alphabetical order.

The data model of Products controller is based on the table with the same name. A foreign key consisting of CategoryID column is referencing Categories table. Field CategoryName is borrowed from Categories table to be displayed as an alias of Products.CategoryID.

If a dedicated model for Categories table is created, then the app builder will produce a corresponding controller and configure Products.CategoryID field as a lookup.

App builder will set Items Data Controller property of CategoryID field to "Categories", Data Value Field to "CategoryID", and Data Text Field to "CategoryName". Both fields are referencing the fields of the controller specified as a source of items.

Field Items Data View property is left blank by default.

Categories will be ordered by CategoryName when selected from Categories table if Items Data View is not specified.
Set Products / Fields / CategoryID / Items Data View to "grid1". This will force your app to take into account the sort expression of Categories/views/grid1 view. If the sort expression is specified, then the items will be ordered accordingly.

You can set up sort order and sort type directly in the Categories model. For example, you can configure the model to sort categories in descending order.

Alternatively, select Categories/views/grid1 view and enter "CategoryName desc" without quotes in Sort Expression property.

Generate the app and observe the new sort order of categories in the lookup.

Note that the custom sort order will also apply to any other style of lookup.

Consider adding a numeric column to Categories table to have a a data-driven custom sort order.
Monday, February 11, 2019PrintSubscribe
Adding Assembly References and Keeping Them
Apps created with Code On Time are based on Microsoft.NET. You can take advantage of system and 3rd party libraries to extend your application.

Let's say you want to access some of the Microsoft Active Directory features available through System.DirectoryServices assembly. Select your app on the start page of the app generator and choose Visual Studio. Right-click the app node and choose Add|References option in the context menu. Choose required assemblies and press OK.

Adding an assembly reference to the app.

If your project was created with the framework packaged in a class library, then make sure to save the solution to preserve the reference. The reference will be stored in the project file of the app.

If the framework is included directly into the app and you have ~/App_Code folder, then the reference will be stored in ~/web.config file. App generator recreates this configuration file from scratch when the app is rebuild.

First, open web.config in Visual Studio and locate the new assembly references.

Custom assembly references in the app with a self-contained application framework.

Copy the definition of assembly reference to the clipboard and switch to the app generator.

Select the project name, choose Settings and proceed to Client & Server.  Locate Web.config modification instructions  in the Server section and enter the following:

AppendChild: /configuration/system.web/compilation/assemblies

Press Enter twice and paste the contents of the clipboard. You will end up having something like this:

Press Finish  and from now on the custom assembly references will be reproduced every time the project is generated.

Friday, February 8, 2019PrintSubscribe
Global Error Logging
The framework in the foundation of apps created with Code On Time provides a unified error reporting mechanism that can be utilized to perform a global exception logging.

Error Logging

Create the following table in your database to keep track of runtime errors.

create table Errors(
    ErrorID uniqueidentifier not null primary key,
    ErrorDate datetime default getdate(),
    UserName nvarchar(128),
    Details ntext

Select your project on the start page of the app builder and choose Visual Studio. Create a code file in the ~/App_Code/cust0m folder and enter the following code:

namespace MyCompany.Services
    public partial class ApplicationServices
        protected override void HandleError(HttpContext context, Exception er)
            // log all uncaught exceptions reported by application
            LogError(new JObject(), er);

        public static Guid LogError(JObject errorDetails, Exception ex)
            // add exception to the details
            var error = new JObject();
            error["message"] = ex.Message;
            error["type"] = ex.GetType().FullName;
            error["source"] = ex.Source;
            error["stack"] = ex.StackTrace;
            errorDetails["exception"] = error;
            // configure error details
            var errorID = Guid.NewGuid();
            var details = errorDetails.ToString();
            var userName = BusinessRulesBase.UserName;
            // log error in the database 
            using (var q = new SqlText(
                "insert into Errors(ErrorID, Details, UserName) " +
                "values(@ErrorID, @Details, @UserName) "))
                q.ExecuteNonQuery(new { errorID, details, userName });
            return errorID;

Error details inherited from the exception will be transcribed in JSON format.
Note that the partial class ApplicationServices is not available in the Trial Edition. You will need a commercial version of the app generator to override the methods of the partial framework classes.
Method ApplicationServices.HandleError is invoked by application framework when the incoming requests have resulted in the application exception that was not handled. The code above will automatically capture all uncaught exceptions. Create a data model for the Errors table and design your own GUI to allow administrative review of error messages.

Custom Error Reporting

Some exceptions are handled by the framework and reported to the end user to avoid rendering the application inoperable. For example, the error is reported to the user as-is if there was an exception when saving data. The user may cancel the data input form and continue working with the app.
Database engine error may be cryptic and impossible to decipher. Developer can choose to “translate” such errors to the user and/or log them in the database for review by administrator.
Create another “code” file in the ~/App_Code/custom folder of your app.
Enter the following code to replace the default error reporting by data controllers. We are using ApplicationServices.LogError method created above to log errors.

using MyCompany.Data;
using Newtonsoft.Json.Linq;
using System;
using System.Web;
using MyCompany.Services;

namespace MyCompany.Data
    public partial class Controller
        protected override void HandleException(Exception ex, ActionArgs args, ActionResult result)
            // by default the exception is reported to the user in result.Errors property
            base.HandleException(ex, args, result);
            // log error in the database
            var errorDetails = new JObject();
            errorDetails["args"] = JObject.FromObject(args);
            var errorID = ApplicationServices.LogError(errorDetails, ex);
            // replace the error message reported to the user with a custom error
            if (result.Errors.Count > 0)
                result.Errors.Add(string.Format("Error {0}. Please contact the Help Desk.", errorID));

Error details will include the JSON definition of arguments including field values that caused the exception.

From now on any errors reported to the user will appear like this:

An example of custom error reported to the user when saving data in the app created with Code On Time.