Blog: Posts from September, 2008

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(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(183) 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(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
Posts from September, 2008
Monday, September 15, 2008PrintSubscribe
Server-Side Data Filters

Data Aquarium Framework and Aquarium Express applications are featuring user-defined adaptive filtering. Users can select any combination of field values in dynamic menus of grid view columns to find the data they need.

Take a look at a live example of Northwind database web application available at http://dev.codeontime.com/demo/northwind. The screen shot displays a list of orders filtered down to employee with last name Fuller. User is about to apply an additional filter to the column Ship Via Company Name.

image

If you want your users to see only a subset of data then define alternative data views based on queries that are limiting data in the SQL query in the foundation of each views.  The advantage of this approach is an ability to quickly define a data subset limited by a known criteria. Dynamic parameter values are not allowed in the query.

What if you want to limit the list of orders to those placed by currently signed-in employee only?

New feature available in Data Aquarium Framework allows to define a reusable data filter class used by linked data controllers automatically whenever a corresponding data retrieval operation requires a  filter. Let's see how it works.

Generate a web site code with Data Aquarium Framework project  and Northwind database.  Open this web site in Visual Studio 2008 or free Visual Web Developer 2008 Express Edition. Add Class1 to App_Code folder and enter the following code.

Data filter written in C#:

using System;
using System.Collections.Generic;
using MyCompany.Data;

public class Class1 : IDataFilter
{
    void IDataFilter.Filter(SortedDictionary<string, object> filter)
    {
        filter.Add("EmployeeID", new int[] { 2, 1 });
        filter.Add("ShipVia", 1);
    }
}

Here is VB.NET version of this class:

Imports System.Collections.Generic
Imports MyCompany.Data

Public Class Class1
    Implements IDataFilter

    Public Sub Filter(ByVal filter As SortedDictionary(Of String, Object)) _
        Implements MyCompany.Data.IDataFilter.Filter
        filter.Add("EmployeeID", New Object() {2, 1})
        filter.Add("ShipVia", 1)
    End Sub
End Class

Open data controller descriptor ~/Controllers/Orders.xml and  add an attribute dataFilterType as shown below:

<dataController 
  name="Orders" conflictDetection="overwriteChanges" 
  label="Orders" xmlns="urn:schemas-codeontime-com:data-aquarium" 
  dataFilterType="Class1">

If you run the web site and select Orders in the drop down of the default page then a view like the one below is displayed.

image

Only eight pages of orders are available. All of them are limited to those placed by employees Fuller and Davolio. All of these orders were shipped via Speedy Express.  If you look at the sample code then you will notice that we are supplying filter values for EmployeeID field as an array with two values, while the ShipVia field is filtered by a single value only.

A quick and easy enhancement will make your view less busy. In our example only one shipper is displayed. You can hide this column from user interface by adding an additional hidden attribute to dataField element in the data controller descriptor ~/Controllers/Orders.xml.

<dataField fieldName="ShipVia" aliasFieldName="ShipViaCompanyName"  hidden="true"/>

In a real-world scenario you will likely use HttpContext.Current.User.Identity property or HttpContext.Current.User.IsInRole method to determine the scope of data that you want to include in the result set displayed to a currently signed in user. Make sure to add System.Web namespace to the list of namespaces in your data filter to get access to HttpContext.Current property.

What do you do if the number of filter values is greater than just a few? In this case you might want to consider creating a database table that holds sets of filter values matched with user identities or roles and then join this table into SQL queries defined in corresponding data controller descriptors. Implement a server-side data filter to provide an ID or a role of current user.

If the name of the data filter field is not matched with any of the fields in the result set then the value is ignored. You can link the same filter to multiple data controllers to take advantage of centralized processing architecture of Data Aquarium Framework.

Sunday, September 14, 2008PrintSubscribe
Microsoft SQL Server 2008 Support

Several users have reported the following error when trying to generate a project with Microsoft SQL Server 2008.

System.InvalidOperationException
The Writer is closed or in error state.

The exception has been raised by ADO.NET when trying to extract user-defined types from the database. File [My Documents]\Code OnTime\Library\CodeOnTime.ModelMap.xml defines a collection of queries that are extracting database information and storing it in the PROJECTTYPE.Metadata.xml file in the root of your project. We have changed SQL Server data discovery entry to exclude UserDefinedTypes as shown in this snippet.

<modelMap>
  <provider providerName="System.Data.SqlClient">
    <collection name="*" exclude="Users,Databases,UserDefinedTypes"/>
    <collection name="$TableSchemas"/>
    <query name="Tables">select * from information_schema.tables</query>
    <query name="Columns">select * from information_schema.columns</query>
    .......

This has eliminated the problem. The fix has been deployed and will be automatically downloaded when you start Code OnTime Generator. None of the current projects is supporting user-defined types and this does not affect any of the available features.

If you are creating a brand new project with Microsoft SQL Server 2008 then metadata discovery should work fine if you have installed the update or downloaded the code generator after the publication of this post.

If you did experience this problem then please click on open link next to the name of your project on the main page of code generator. Delete Error.PROJECTTYPE.Metadata.xml and PROJECTTYPE.Metadata.xml files and generate the project again. If you project type is Aquarium Express then the metadata file is DataAquarium.Metadata.xml.

Alternatively you can open your project and navigate to Database Connection page where the error message is displayed. Click on the link 'Click here if your database has changed and you would like to refresh the cached metadata'. This will delete the file with meta data and will guarantee that your project has been generated with the latest database changes.

Please report any errors or suggestions at http://codeontime.com/contactus.aspx. You can download Code OnTime Generator at http://codeontime.com/download.aspx.

Thursday, September 11, 2008PrintSubscribe
Default Field Values in Custom Action Handlers

A common requirement in many data management applications is to compliment data manually entered by users with some calculated values. You may be required to perform some complicated financial computations, lookup additional field values in the database according to some custom logic, or automatically supply audit trail by recording the time stamps and user ID in the database records. Some of these tasks can be encapsulated in database table triggers. If this is not an option then it is time to create a custom action handler.

We will illustrate this with the unit price lookup by improving on the custom action handler example presented in Aquarium Express Primer.

The primer is demonstrating a lookup of unit price for inserted order details records of Northwind database. Basically it is suggesting to allow insertion of the order details record without a price and executing a follow-up update of the new record. This is resulting in two database operations - SQL insert will be followed by update statement.

We will improve on that by supplying a unit price prior to the insertion of order details record.

Open ~/Controllers/OrderDetails.aspx and change the definition of createForm1 as follows:

<view id="createForm1" type="Form" commandId="command1" label="New Order Details">
  <headerText>Please fill this form and click OK button to create a new order details record. Click Cancel to return to the previous screen.</headerText>
  <categories>
    <category headerText="New Order Details">
      <description>Complete the form. Make sure to enter all required fields.</description>
      <dataFields>
        <dataField fieldName="OrderID" aliasFieldName="OrderCustomerID" />
        <dataField fieldName="ProductID" aliasFieldName="ProductProductName" />
        <dataField fieldName="UnitPrice" dataFormatString="c" columns="15" hidden="true"/>
        <dataField fieldName="Quantity" columns="15" />
        <dataField fieldName="Discount" columns="15" />
      </dataFields>
    </category>
  </categories>
</view>

The primer suggests removing the UnitPrice data field from view createForm1. We are restoring the data field and instead marking it up as "hidden". Hidden data fields are not rendered in the standard user interface when displayed in a web browser, which meets our objective as outline in the primer. On the other hand, hidden fields are available for manipulation in custom action handlers. Note that you can still display any hidden fields if you are using custom form templates.

Now you can remove the price lookup code from method AfterSqlActon in Class1.

Create a new method BeforeSqlAction as shown in example.

Here is C# implementation of BeforeSqlAction.

protected override void BeforeSqlAction(ActionArgs args, ActionResult result)
{
    if (args.CommandName == "Insert" && args["UnitPrice"].Value == null)
    {
        double price = 0;
        using (SqlText findPrice = new SqlText(
            "select UnitPrice from Products where ProductId = @ProductID"))
        {
            findPrice.AddParameter("@ProductId", args["ProductID"].Value);
            price = Convert.ToDouble(findPrice.ExecuteScalar());
        }
        args["UnitPrice"].NewValue = price;
        args["UnitPrice"].Modified = true;
    }
}

VB.NET implementation looks very much the same.

Protected Overrides Sub BeforeSqlAction(ByVal args As MyCompany.Data.ActionArgs, _
                                            ByVal result As MyCompany.Data.ActionResult)
        If args.CommandName = "Insert" And args("UnitPrice").Value Is Nothing Then
            Dim price As Double = 0
            Using findPrice As SqlText = New SqlText( _
                "select UnitPrice from Products where ProductId = @ProductID")
                findPrice.AddParameter("@ProductID", args("ProductID").Value)
                price = Convert.ToDouble(findPrice.ExecuteScalar())
            End Using
            args("UnitPrice").NewValue = price
            args("UnitPrice").Modified = True
        End If
    End Sub

As you can see we are finding the price of the ordered product and then assigning it to the new value of UnitPrice in the argument. It is important to mark the field value as modified. Otherwise the field will not be included in the SQL statement generated by data controller.

Custom action handlers allow complex calculations to be implemented in a high level language such as C# or VB.NET, which may be the only option if calculations involve resources outside of the database server. The same custom action handler is uniformly used in all pages of your application that are displaying the data with the help of the controllers that are referring to your custom action handler via actionHandlerType attribute. Custom action handlers become centralized stateless business logic layer rule repositories of your Web 2.0 applications written with ASP.NET and AJAX.