July 2006 Entries
Display Record's Description Through AJAX

 Sign up for Articles and Forums on my other websites: http://m.aatechsources.com

Description:

This customization utilizes the power of AJAX to make asynchronous calls to server-side methods. The server-side methods then call back a JavaScript function to display data in a popup window. The code customization for .NET Framework 2.0 uses the Microsoft Atlas library. For .NET Framework 1.1, the AJAXPro (available free) third-party DLL is used.

Procedure:

Step 1: Call JavaScript function on MouseOver

Define an area that the user can mouse over to see the popup data.  When the user mouses over, the MyCustomFunction JavaScript function is called.  This function takes two arguments.  The first argument is the Id of the record being retrieved.  The second argument is the reserved word 'event' that specifies the location of the mouse.

You can use a code generation tag to specify a field value within the table row.  Make sure to specify the database field corresponding to the Field Value code generation tags on the Page Properties dialog box. 

 <a OnMouseOver='MyCustomFunction(<GEN:FieldValue NAME="MyRecordID"/>, event);'>
    <GEN:FieldValue NAME="MyRecordName"/>
</a>

Step 2: Define two JavaScript functions

Define two JavaScript functions within the script tags in the HTML page. The first function is called by the MouseOver event.  It will save the current mouse position and then call the server-side method declared in your page class.  The second function is the call-back function called by the server-side method.

There are slight differences between .NET Framework 1.1 (using AjaxPro.dll) and .NET Framework 2.0 (using Microsoft Atlas) as shown below.

For .NET Framework 1.1

<script type ="text/javascript">
function MyCustomFunction(MyRecordID, event)
{
    // Save the mouse position for later use by detailRolloverPopup
    SaveMousePosition(event);

    // Invoke the AJAX method defined in the code-behind of the page
    // Replace MYAPP with your application's name and MYPAGE with the corresponding Page class's name.
    // Also, specify the callback function - MyCallBack (defined below)
    MYAPP.UI.MYPAGE.GetRecordDescription(MyRecordID, MyCallBack);
}

function MyCallBack(result)
{
    // The detailRollOverPopup() displays the content returned from the AJAX call in a popup window
    // It accepts three parameters:
    // - aTitle, string to be displayed in the title bar of the popup window.
    // - aContent, string containing HTML to be displayed in the body of the popup.
    // - aPersist, boolean indicating whether the popup should remain visible even on mouseout.
    detailRolloverPopup('Window Title', result.value, false);
}
</script>

For .NET Framework 2.0

<script type ="text/javascript">
function MyCustomFunction(MyRecordID, event)
{
    // Save the mouse position for later use by detailRolloverPopup
    SaveMousePosition(event);

    // Invoke the WebMethod defined in the code-behind of the page through the PageMethods command
    // Also, specify the callback function - MyCallBack (defined below)
    PageMethods.GetRecordDescription(MyRecordID, MyCallBack);
}

function MyCallBack(result)
{
    // The detailRollOverPopup() displays the content returned from the AJAX call in a popup window
    // It accepts three parameters:
    // - aTitle, string to be displayed in the title bar of the popup window.
    // - aContent, string containing HTML to be displayed in the body of the popup.
    // - aPersist, boolean indicating whether the popup should remain visible even on mouseout.
    detailRolloverPopup('Window Title', result, false);
}
</script>

Step 3: Add ScriptManager reference to page (only for .NET Framework 2.0)

In the HTML page, include the <atlas:ScriptManager> element.  The tag must be within the <form> tag to enable the page for Microsoft Atlas.  This tag enables Atlas client scripts to be downloaded when the web page is requested.

<atlas:ScriptManager ID="scriptManager1" runat="server"/>

Step 4: Use this wizard to add customized code.

Step 5: Build and run the application

Applies To:

    This customization applies to pages with table controls.

Note:

    Please note that this code customization example for .NET Framework 2.0 makes use of the April Community Technology Preview (CTP) version of Microsoft Atlas DLL. 

Disclaimer:

Customizations included in this wizard are provided as a sample to demonstrate a feature, and may work only in specific situations. Geeketee Mai cannot assist in the resolution of problems which may occur as a result of customizing your application or modifying a customization to fit a particular purpose.

 

Application Security
Built-in security features critical for today's enterprise applications
Although most corporations take security precautions at the network level, the majority of application security must be built into the application itself. Several important application security features including role-based access control, automatic sign-out, and database-resident password storage.

 

Role-based access control
You can automatically add end-user authentication (sign-in) and role-based access control as a standard feature to your applications. This authentication feature is based on your own user and role data in your database, making it easy to set up and administer.

An unlimited number of user roles, and individual users can possess multiple roles. For example, the customer service supervisor has one role as a "rep" with access to customer account information, and a second role as "manager" with authorization to issue refunds or credits. These roles are accessible simultaneously without requiring the user to log in under a second role.

Automatic sign-out
Users are automatically logged-out after a designated period of time to guard against identity theft when a user leaves their Web browser open to the application.This is especially important for applications that connect between enterprises.

Password Storage
Highly sensitive user name and password data is stored directly in the application's existing database tables and not in any separate file that could be compromised.

Data Transmission Encryption
All application data transmitted to and from the client browser is encrypted using the web server's built-in SSL (secure socket layer) encryption. This standard security ensures that no one can see your data as it passes over the public Internet or over your private intranet and local area networks.

Single sign-on using Active Directory
Users of multiple applications will want a single sign-on feature, saving them from having to sign in to each individual application. Iron Speed Designer applications are easily extended to add single sign-on using Active Directory and Lightweight Directory Access Protocol (LDAP).

Application Customization and Integration

 


Extensible C# and Visual Basic .NET classes

Code generated by Iron Speed Designer is designed to be customized and then regenerated repeatedly without reapplying your code customizations. This is accomplished by a class hierarchy designed for code customization that is not affected when rebuilding your application.

 

Easy to Customize Code
Simply subclass the appropriate page, control or database class. Your code extensions are preserved when code files are regenerated, allowing you a high degree of flexibility in extending your application program code.

Visible, customizable code. Page and control classes in the Presentation Layer are easy to understand and modify. Quickly see how your application builds SQL queries, loads data, and initializes UI controls – right in the code. To customize, simply override the appropriate method right in the same code file!



Customize data retrieval. Calling custom stored procedures and loading your own data is a snap.



Customize data validation and storage. Quickly add custom data validation and data storage code.



Customize dropdown lists. Customizing the query and sort order for dropdown lists is straightforward, even for the most complex applications.



Customize filters. Customize the query and sort order for filters with ease.



Native ASPX controls. Generated applications use native ASP.NET controls. There's nothing new or proprietary to learn.



Separate UI, Business and Data name spaces. Page classes are generated in the UI name space, the Business name space contains all Record and Table classes, and the Data name space contains classes that connect to your database.

Straightforward Class Hierarchy
Generates a complete, robust class hierarchy for your application. Your application is fully documented and browsable using Code Telescope. Learn more...

Several of the major class types are:

 

Page. A code-behind class is generated for each page in your application. The Web page and user control classes provide advanced functionality, including browser independence, event handling methods for both client and application layer commands, unified object model methods, state management and scalability.
Record. A class corresponding to a record is generated for each database table used in your application to perform record-based access (e.g., insert, update, delete). “Virtual record” classes are generated for each database table and database view that are joined together.
Table. A class is generated for each table and database view in your application to provide the methods necessary to retrieve a group of records based on your filtering criteria and end-user filtering criteria.
Referencing Data Access Functions in Code

 

Creates two classes for each table in your database.

The Record classes represent a record from the database.  Some of the record classes specify an actual physical record in the database while others correspond to a virtual record – the result of a join between tables.  A “Record” suffix is added to the name of the table to get the name of the class.  For example, if you have a Customers table in your database, the class will be called CustomersRecord.  The record class is different from the record control class described elsewhere.  A record class corresponds to a database record, while a record control class corresponds to a user interface control that contains other fields that display or edit data.

The Table class is one of the most important classes used in applications.  This class is generated for each table in your application to provide the methods necessary to retrieve a group of records based on a query.  A “Table” suffix is added to the name of the table to get the name of the class.  For example, if you have a Customers table in your database, the class will be called CustomersTable.  A “View” or a “Query” suffix is added to the name if the class is generated for a view or query respectively.

To read data from the database you can use the GetRecords function on the Table class.  There are a number of variations of the GetRecords functions that either take a string based where clause or an object that specifies the clause.  Each of the GetRecords functions can take optional arguments that specify the order by clause, the number of records to retrieve, and the starting page number.

GetRecords with a where clause string

The following examples show how to use the GetRecords functions with a string based where clause.  This case is typically used to make a call to GetRecords when there is only one where clause that is not combined with another clause using an AND or OR operator.  While the clauses can be combined in a string, it is better to use a WhereClause object defined later in this section.

C#:

CustomersRecord[] myRecords;

 

myRecords = CustomersTable.GetRecords("Country = USA");

if (myRecords != null)

{

     foreach (CustomersRecord rec in myRecords)

     {

          // To access a field in the record, simply specify

          //   rec.

          String s = "Company: " + rec.CompanyName;

     }

}

Visual Basic .NET:

Dim myRecords As CustomersRecord()

myRecords = CustomersTable.GetRecords("Country = USA")

 

If Not (IsNothing(myRecords)) Then

     For Each rec In myRecords

           ' To access a field in the record, simply specify

          '    rec.

          Dim s As String = "Company: " & rec.CompanyName

     Next

End If

The GetRecords function takes a WHERE clause and retrieves all records that meet that criteria.  Please note that the number of records returned is dependent on the number of records in the database.  If you want to limit the number of records, you can pass additional parameters to the GetRecords function.  The following code will return the third set of 50 records.

C#:

CustomersRecord[] myRecords;

myRecords = CustomersTable.GetRecords("Country = USA", null, 3, 50);

 

if (myRecords != null)

{

     foreach (CustomersRecord rec in myRecords)

     {

          // To access a field in the record, simply specify

          //   rec.

          String s = "Company: " + rec.CompanyName;

     }

}

Visual Basic .NET:

Dim myRecords As CustomersRecord()

myRecords = CustomersTable.GetRecords("Country = USA", Nothing, 3, 50)

 

If Not (IsNothing(myRecords)) Then

     For Each rec In myRecords

          ' To access a field in the record, simply specify

          ' rec.

          Dim s As String = "Company: " & rec.CompanyName

     Next

End If

The above examples demonstrate how you can read a set of records from the database.  If you want to access the records that are being displayed on a page, you would need to call the GetRecords() function on the Table Control class within the page.

In addition to the above example, you can also use the GetRecord function to read a single record from the database.  GetRecord takes a WHERE clause similar to GetRecords and will return the first record that matches the query.

GetRecords with a WhereClause object

The following examples show how to use the GetRecords functions with a WhereClause object.  This case is typically used to make a call to GetRecords when there are more than one where clauses that must be combined with AND or OR operators.  The CreateWhereClause method generated by Iron Speed Designer uses this method to retrieve data from the database.

You can defined a WhereClause object and then call the iAND and iOR methods to define clauses.  The iAND and iOR methods take a field name, an operator and a value.  The field name may contain spaces or other characters, so it is safer to use the name as provided by the database schema.  The database schema field name can be specified using the Table class followed by the column name such as CustomersTable.CompanyName.

C#:

public virtual void LoadData()

{

     try

     {

          DbUtils.StartTransaction();

 

          // The WHERE clause will be empty when displaying all records in table.

          WhereClause wc = CreateWhereClause();

          this.DataSource = CustomersTable.GetRecords(wc);

     }

     catch (Exception ex)

     {

          throw ex;

     }

     finally

     {

          DbUtils.EndTransaction();

     }

}

 

protected virtual WhereClause CreateWhereClause()

{

     // Start with a blank WhereClause

     WhereClause wc = new WhereClause();

 

     // Create a WhereClause that is as follows:

     // Country = "USA" AND State = "California" AND (Name Contains "Jones" OR CompanyName Contains "Jones")

 

     // Add the value selected in the Country filter dropdown

     if (this.CountryFilter.SelectedValue != "")

     {

          wc.iAND(CustomersTable.Country, EqualsTo, this.CountryFilter.SelectedValue);

     }

 

     if (this.StateFilter.SelectedValue != "")

     {

          wc.iAND(CustomersTable.State, EqualsTo, this.StateFilter.SelectedValue);

     }

 

     // Now we need to create a separate WhereClause that OR's the search string and then

     // this separate clause is ANDed with the rest of the clauses)

 

     if (this.CustomersSearchArea != "")

     {

          WhereClause search = new WhereClause();

 

          search.iOR(CustomersTable.Name, Contains, this.CustomersSearchArea.Text);

          search.iOR(CustomersTable.CompanyName, Contains, this.CustomersSearchArea.Text);

 

          // Now AND this with the WhereClause wc defined earlier.

          wc.iAND(search);

     }

 

     return wc;

}

Visual Basic .NET:

Public Overridable Sub LoadData()

     Try

          DbUtils.StartTransaction()

 

          ' The WHERE clause will be empty when displaying all records in table.

          Dim wc As WhereClause = CreateWhereClause()

          Me.DataSource = CustomersTable.GetRecords(wc)

 

     Catch ex As Exception

          Throw ex

     Finally

          DbUtils.EndTransaction()

     End Try

End Sub

 

Protected Overridable Function CreateWhereClause() As WhereClause

 

     ' Start with a blank WhereClause

     Dim wc As WhereClause = New WhereClause

 

     ' Create a WhereClause that is as follows:

      ' Country = "USA" AND State = "California" AND (Name Contains "Jones" OR CompanyName Contains "Jones")

 

     ' Add the value selected in the Country filter dropdown

     If Me.CountryFilter.SelectedValue <> "" Then

           wc.iAND(CustomersTable.Country, EqualsTo, Me.CountryFilter.SelectedValue)

     End If

 

      ' Add the value selected in the State filter dropdown

     If Me.StateFilter.SelectedValue <> "" Then

          wc.iAND(CustomersTable.State, EqualsTo, Me.StateFilter.SelectedValue)

     End If

 

     ' Now we need to create a separate WhereClause that OR's the search string and then

     ' this separate clause is ANDed with the rest of the clauses)

 

     If Me.CustomersSearchArea.Text <> "" Then

          Dim search As WhereClause = New WhereClause

          search.iOR(CustomersTable.Name, Contains, Me.CustomersSearchArea.Text)

          search.iOR(CustomersTable.CompanyName, Contains, Me.CustomersSearchArea.Text)

 

          ' Now AND this with the WhereClause wc defined earlier.

          wc.iAND(search)

     End If

 

     Return wc

End Function

The GetRecords function takes a WHERE clause and retrieves all records that meet that criteria.  Please note that the number of records returned is dependent on the number of records in the database.  If you want to limit the number of records, you can pass additional parameters to the GetRecords function.  The following code will return the third set of 50 records.

C#:

// By default we want to expand foreign keys and to sort in a case sensitive order

OrderBy orderBy = new OrderBy(true, true);

 

// Order by Name in Ascending order

orderBy.Add(CustomersTable.Name, Asc);

 

this.DataSource = CustomersTable.GetRecords(wc, orderBy, 3, 50);

Visual Basic .NET:

' By default we want to expand foreign keys and to sort in a case sensitive order

Dim orderBy As orderBy = New orderBy(True, True)

 

' Order by Name in Ascending order

orderBy.Add(CustomersTable.Name, Asc)

 

Me.DataSource = CustomersTable.GetRecords(wc, orderBy, 3, 50)

The above examples demonstrate how you can read a set of records from the database.  If you want to access the records that are being displayed on a page, you would need to call the GetRecords() function on the Table Control class within the page.

In addition to the above example, you can also use the GetRecord function to read a single record from the database.  GetRecord takes a WHERE clause similar to GetRecords and will return the first record that matches the query.

Saving Data to the Database

 

In the above sections we have discussed the lifecycle of retrieving and displaying data on a web page.  There is an analogous life cycle the page goes through to retrieve the data from the user interface controls into memory and subsequently save this data in the database.

The data is retrieved into memory from each of the user interface controls and validated.  The retrieved data is stored in an instance of the data access layer’s Record class.

The data from the page is retrieved within the record control class, but the transaction is committed at the page level.  This is because data from all records must be saved within a transaction and any foreign key relationships must be taken into account when the data is saved.  For example, master records are saved first followed by child records since the child records need the Id of their parent record.

You can override the SaveData method at the record control or table control to add functionality before or after saving the data. If the Id’s of the records are assigned by the database, they will be available after the data is written to the database and the transaction is committed.  This can be accomplished by customizing the SaveButton_Click method and calling the underlying methods yourself.  Please note that the SaveButton_Click_Base method at the page level contains a call to Redirect after the data is saved, so none of the code after a call to the base method will be executied.

If the button action specifies redirection to another page, the Redirect method is called within the Save button’s click handler.  The Redirect method of the base class will automatically change the URL parameters if they have been specified in the Properties dialog box.

 

Calling Hierarchy of a Page with a Record Control when Saving Data

The calling hierarchy of a page with a record control when saving data shows the various methods that are called at the Page and Record Control class levels.  When saving data, most of the work is performed by handling the Click event of the button at the page class level.  The Click event is handled by ButtonClick and ButtonClick_Base methods at the page level.  The ButtonClick_Base method then calls the SaveData method for each of the Record Control classes on the page.  Since you may be only editing a subset of fields on the page, LoadData is called to load the complete record and perform concurrency comparison.  This is followed by a call to Validate the data entered by the user and GetUIData to retrieve the data from the user interface controls into the database record.  The record is then saved in the database.  The CommitTransaction is performed at the ButtonClick_Base to ensure that all of the data is saved within one transaction.

Table Control and Record Control Lifecycle

 

The Table Control and Record Control are user interface controls and have a lifecycle of their own, just like the lifecycle of each of the controls on a page.  It is important to understand the lifecycle of the table and record control classes since the page delegates the responsibility of reading the data from the database and retrieving and validating the data from the user interface prior to saving it in the database.

The query used to read data from the database is a composite query that is formed based on the static WHERE clause specified by the developer and the dynamic settings specified by the end user.  The static query might be:

SELECT  *

FROM Customers

WHERE Customers.State = California

When the end user views the information, he or she might search for some information within the table, further filter by another field, sort by a column and display the third page of information.   In this case, the pseudo-query might look something like:

SELECT    rows 31 to 40

FROM Customers

WHERE Customers.State = California AND

     Customers.LastName LIKE ‘%Smith%’

ORDER BY Customers.ZipCode DESC

During the lifecycle of a table or record control, you have an opportunity to further modify the query before it is executed by overriding the CreateWhereClause method.  You can also review the data retrieved and make any changes before presentation to the user, or calculate values that are dependent on the rows retrieved by overriding the DataBind method.   Please note that the query only returns the rows that are being displayed on the web page, not all of the rows that would be returned by the query.  For example, if each page displays 10 records, and page 4 is being currently displayed, the query will return only records 31 through 40.

 

Calling Hierarchy of a Page with a Table Control when Displaying Data

The calling hierarchy of a page with a table control when displaying data shows the various methods that are called at the Page, Table Control and Record Control class levels.  When displaying data, most of the work is performed by handling the Load event at the page class level.  The Load event is handled by Page_Load, LoadData and LoadData_Base methods at the page level.  The LoadData_Base method then calls the LoadData and DataBind methods for each of the Table Control classes on the page.  LoadData then calls CreateWhereClause to create the clause that is used to read the data from the database.  The DataBind binds the data to the user interface controls and also binds the pagination controls.  Any dropdown filter lists are populated by calling the PopulateFilter methods.

 

Calling Hierarchy of a Page with a Table Control when Filtering, Sorting or Searching Data

The calling hierarchy of a page with a table control when filtering, sorting or searching data shows the various methods that are called at the Page, Table Control and Record Control class levels.  When filtering, sorting or searching data, most of the work is performed by the PreRender method at the Table Control class level.  The PreRender method takes the settings set earlier by one of the Click or SelectedIndexChanged events at the Table Control class level.  PreRender then checks to see if the data needs to be reloaded and calls the LoadData and DataBind methods for the Table Control class.  LoadData then calls CreateWhereClause to create the clause that is used to read the data from the database.  The DataBind binds the data to the user interface controls and also binds the pagination controls.  Any dropdown filter lists are re-populated by calling the PopulateFilter methods.

 

Calling Hierarchy of a Page with a Record Control when Displaying Data

The calling hierarchy of a page with a record control when displaying data shows the various methods that are called at the Page and Record Control class levels.  When displaying data, most of the work is performed by handling the Load event at the page class level.  The Load event is handled by Page_Load, LoadData and LoadData_Base methods at the page level.  The LoadData_Base method then calls the LoadData and DataBind methods for each of the Record Control classes on the page.  LoadData then calls CreateWhereClause to create the clause that is used to read the data from the database.  The DataBind binds the data to the user interface controls.  Any dropdown lists used on the record page is also populated by calling the PopulateFieldDropDownList method from DataBind.

Page Code Customization Model

 

There are four types of classes that are generated.

Page code-behind class

The page’s code-behind class is derived from the Microsoft .NET Framework’s page class.  This class contains event handlers and methods that load the data from the database, display the data in user interface controls and save the updated data back into the database.  The page class event handlers and methods call on some of the other classes to actually perform the specific task.  Most of the code customization should be performed in these other classes.

 

Sample Add Customers page showing the page code-behind class and a record control class (described below).

Microsoft .NET Framework does not provide the flexibility of sub-classing of page classes where the controls are defined at both the base class and the sub-class.  To provide the ability to customize the generated code, Iron Speed Designer creates a Base method for each of the methods.  For example, Iron Speed Designer generates LoadData and LoadData_Base.  LoadData calls LoadData_Base to perform the actual work.  LoadData can be customized, while LoadData_Base should not be modified.  LoadData can call perform additional work before or after the call to LoadData_Base, or the entire call to LoadData_Base can be replaced with custom code in LoadData.

 

Some of the key methods generated in the page class are:

  • Page_Load: Calls Authorize to verify if user has access to the page, and then calls LoadData to load the data. 

  • LoadData and LoadData_Base: LoadData calls the LoadData_Base method which in turn calls each of the record and table controls to actually load the data for the respective controls.  The Base method (LoadData_Base) should not be modified, LoadData can be modified to perform additional tasks before or after the call to LoadData_Base or to simply replace the call.

  • Button_Click and Button_Click_Base: These methods handle the click event of a button and are named based on the name of the button.  For example, a button called SaveButton will have a SaveButton_Click and a SaveButton_Click_Base method generated as part of the page class.  The SaveButton_Click calls the SaveButton_Button_Click method which in turn calls each of the record and table controls to actually save the data for the respective controls.  The Button_Click_Base method starts, commits and ends a transaction and all updating of data occurs within this one transaction.  Any errors including validation errors are reported by the lower level methods by throwing an exception. The exception is caught in Button_Click_Base and a Javascript alert is registered for display during the subsequent page load.

Record control class

If a page contains a record control such as an Add or Edit record page, a record control class provides the methods necessary to load the data for the specific record and bind its data to the user interface control.  There are two record control classes created for each record on the page.  A Base record control class contains all the generated code and is named by prefixing “Base” to the name of the record control (e.g., BaseCustomersRecordControl).  An initially empty “safe” class is also generated and is named the same as the name of the record control (e.g., CustomersRecordControl).  Any methods defined in the base class can be overridden in the safe class to customize the functionality of the record control.

Some of the key methods generated in the record control class are:

  • LoadData: Load the data from the database based on the query specified on the record panel wizard.  This method calls the CreateWhereClause to compose the where clause that will be used to read the data from the database.

  • CreateWhereClause:  For Edit Record and Show Record pages, the CreateWhereClause retrieves the URL parameter and constructs a Where Clause to read the record from the database.

  • DataBind: Binds the record read from the database to the user interface controls.  Any formatting of the data such as the conversion of the stored date into a local culture specific date format is performed in this method.

  • SaveData: This method calls Validate to perform additional validation of the data, retrieves the data from the user interface controls, and then saves the data in the database.  The transaction must be started prior to a call to this function, and must be committed by the caller.  This method calls the Parse method to parse the value from the user interface control into the database record.  The Parse method first performs validation to ensure the value can be recognized based on the type of the field (e.g., date), and then, if necessary, converts the text value to the data type of the field (e.g., integer).  The Parse method may throw an exception if the value is not recognized.  The exception must be handled by the caller of the SaveData method.

  • Validate: An initially empty Validate method is generated in the Base class.  You can override this method in the safe class to perform additional validation.  In case of an error, an exception must be throw with an appropriate message that can be reported to the end user.

Table control class

If a page contains a table control such as a Show Table page, the table control class provides the methods necessary to load, display, filter, search, sort, and paginate the table data.  There are two table control classes created for each table on the page. A Base table control class contains all the generated code and is named by prefixing “Base” to the name of the table control (e.g., BaseCustomersTableControl).  An initially empty “safe” class is also generated and is named the same as the name of the table control (e.g., CustomersTableControl).  Any methods defined in the base class can be overridden in the safe class to customize the functionality of the table control.

In addition to the two classes for each table control, there are two additional classes created that correspond to a row in the table.

 

Sample page showing a page class, a table control class and a row class (described below).

Some of the key methods generated in the table control class are:

  • LoadData: Load the data from the database based on the query specified on the table panel wizard.  This method calls the CreateWhereClause to compose the where clause that will be used to read the data from the database.  CreateOrderBy is called to create the ORDER BY portion of the SELECT where clause.  Both CreateWhereClause and CreateOrderBy methods can be overridden in the safe class to add, modify or replace the generated code.  The LoadData method sets the DataSource of the Table Control class.  The DataSource is used later by the DataBind method to bind each of the rows in the table.

  • CreateWhereClause: The CreateWhereClause composes and returns a Where Clause.  The Where Clause is composed of the static where clause defined at page creation time combined with any filtering and searching criteria specified by the end user.  You can add additional clauses by overriding the CreateWhereClause method.

  • DataBind: Binds the record read from the database to the user interface controls.  This method loops through each row in the table, sets the DataSource of the row record control to the specific row from the DataSource of the table control, and then calls the DataBind method of the row record control.  Any formatting of the data such as the conversion of the stored date into a local culture specific date format is performed in this method.  Pagination controls are bound by calling BindPaginationControls method.  The data for any drop-down filter controls is loaded and bound in this method by calling Populate methods for each filter.

  • SaveData: This method is applicable to editable tables and calls the SaveData method for each of the row record controls in the table.  This method also deletes and rows if the user deleted the row.  The row is deleted from the database when the Save button is clicked, not when the delete button is clicked. The transaction must be started prior to a call to this function, and must be committed by the caller.  See the SaveData method for the Record Control described above.

  • BindPaginationControls:  All of the pagination controls are bound in this method.  Some controls are disabled if they are not applicable, such as the first page button if the user is already on the first page of the table.

  • PopulateFieldFilter:  For every dropdown filter, there is a PopulateFilter method generated.  The name of the method is of the form PopulateFILTERNAMEFilter.  For example, if there is a Country filter, the method generated will be called PopulateCountryFilter.  This method first calls the CreateWhereClause method for the specific filter (e.g., CreateWhereClause_CountryFilter), and then reads the data from the database, initializes the dropdown list with the values returned, and sets the selected value based on the current value specified in the database.  By default, a maximum of 500 items are retrieved from the database.  This can be changed by modifying the MaxDisplayedValues attribute on the Page Properties dialog box for the specific filter control. 

The CreateWhereClause_FILTERFilter method can be overridden to add, modify or replace the generated method. This is the best way to display a subset of items in the filters. Please note that the filter is a Display Foreign Key As field, the query may be run on the foreign key table, and not on the table from where the data is being displayed.  This is based on the setting on the Page Properties dialog box that determines whether All Values or Only Result Set is selected for the filter settings.  For example, if you are displayed the Order Details table containing a Product Id filter that is a foreign key to the Products table, then the Populate method will retrieve data from the Products table if the All Values option is selected.  If the Only Result Set option is selected, then the Populate method will retrieve data from the Order Details table.  Please take this into consideration when modifying the CreateWhereClause_FILTER methods so you can add the right WHERE clause for the applicable table.

  • Sort_Click:  For every column sort hyperlink in a table control, there is a Click handler generated.  The name of the click handler is of the form COLUMNNAME_Click.  For example, if there is a Country1 column header, the method generated will be called Country1_Click.  This method calls the underlying ColumnSort method to set the CurrentSortOrder variable that will be used later by the CreateOrderBy method to set the sorting column and direction.

Row class

If a page contains a table control, then in addition to the table control classes, two additional classes are created.  These classes correspond to a row in the table.  The row classes are exactly the same as the Record Control classes defined above with one difference. 

It is important to note that the row classes do not load the data from the database individually, but instead rely on their DataSource variable being set by the table control’s DataBind method.

Page Control Hierarchy

 

All web pages in Microsoft .NET Framework contain a number of user interface controls that are initialized at the server side and are called server controls.  Since server controls can have children, and each of their children may have children, and so on, a control and its descendents form a tree of controls.  This tree of controls is called the control hierarchy. The root of the control hierarchy for a .NET web page is the Page-derived class.  Iron Speed Designer generates a hierarchy of controls for each of the pages. 

The loading of the data from the database is delegated by the page to the Table Control or the Record Control classes.  Since you can have a number of tables and records displayed on a page, there can be multiple Table Control and Record Control classes within a page.  Each of the classes is responsible for loading its data from the database based on the query you specified and any search, filter and pagination settings selected by the end user.  The Row record control class does not load data directly from the database, but receives its data from the Table Control class.

The dropdown filter controls load the data from the database directly in methods that are named PopulateFILTERNAME.

The field value controls do not load data from the database directly.  Instead they rely on the Table Control and Record Control classes to load the data and are bound in the DataBind methods for each of the table or record control classes.

The Page Lifecycle

 

Creates standard web pages that are derived from the ASP.NET Page class.  When an ASP.NET web page is requested from the web server, the code-behind class for the page goes through a sequence of steps to initialize and load the user interface controls, read the data from the database and display the page.

This sequence of steps is called the page lifecycle as shown below:

  • Initialization:  During this stage the page and all of the controls within the page (control hierarchy) are instantiated.  This includes any tables, textboxes and buttons.  Any event handlers to handle click events for buttons, sorting hyperlinks, and text changed events for filters are initialized at this stage.

  • Loading: The data being displayed or edited on this page is loaded from the data-source and “bound” to each of the user interface controls.  The binding process involves formatting the information as well as loading any additional information needed such as the contents of drop-down lists.  Most of the work is performed during this step.

  • Event Handling: Post-back events caused by server controls will be handled. These event handlers include events such as button clicks, SelectedIndexChanged of a dropdown list, TextChanged of a textbox and sorting hyperlink events, Note that when button clicks happen, the Init and Load event handlers will be executed as well.  Iron Speed Designer generates code for the Init and Load handlers that checks for the IsPostBack property before deciding whether to execute any code.  As generated, the Init and Load handlers do not execute any code during event handling since the code is surrounded by If Not(Me.IsPostBack), so the event handler must perform all actions including loading data from the database if necessary.

  • Rendering: The HTML of the page and all controls are sent to the browser for rendering.  Iron Speed Designer generates code for the PreRender method that checks to see if this is the first time a page is being displayed or whether this is a postback caused by an event such as a button click.  During the initial page lifecycle when the page is first being displayed, the PreRender method does not perform any actions.  During event handling postbacks, PreRender checks to see whether any data is required to be reloaded because of button clicks or other events.  If the data needs to be loaded again based on the new settings, PreRender calls LoadData to retrieve data from the database.

All pages generated derive from the Microsoft .NET Framework’s Page class, so they follow the same page lifecycle described above.  The classes generated extend the Page class to support loading data from the database and to provide more enhanced user interface controls that support data type formatting and validation.

Overrides and Events

At each state of the page lifecycle, the Microsoft .NET Framework sends an event notification to the page.  You can handle an event to customize any aspect of the page before it is displayed to the user.  By handling an event, you can add functionality to your page, but cannot replace the existing functionality that is already provided by the underlying classes.

You can define any number of event handlers for a single event.  For example, the Init event can be handled by multiple event handlers.  In general, if you want to add functionality, it is better to define your own event handler, rather than modifying an existing event handler.  Note that the order of calling of event handlers for an event is not guaranteed.  The event handlers may be called in any order, so care must be taken to ensure that there are no dependencies betweem event handlers for the same event.

Note that event notifications are sent after the completion of each phase.  For example, the Init event is sent when the initialization of all the controls is complete and the Load is sent after the loading of the data and the controls of the page is completed.

Iron Speed Designer generates code to handle these standard events such as Init and Load.  The generated code then calls other methods to perform the specific tasks such as loading of the data or binding data to the user interface controls. 

You can customize or change the behavior of any control by either:

  • Adding your own event handler:  If the goal is to add to the functionality, you can simply add your own event handler.

  • Changing the generated event handler or method:  Generates code in two sections.  Section 1 is generated once, and never overwritten.  Section 2 will be overwritten whenever controls are added, modified or deleted.  All generated event handlers are in Section 2 and should not be modified.  To customize the behavior, Iron Speed recommends modifying the methods that are called by the event handlers.  These methods are defined in Section 1 and can be modified easily.

  • Overriding the generated method:  Any of the generated methods can be overridden in the sub-classes.  The sub-classes generated in Section 1 will not be overwritten, so the behavior can be easily customized by overriding the method in one of the subclasses.  Unlike event handling, overriding a method for a class allows you to replace the underlying functionality being performed.  For example, you can override the LoadData method of a record control class to read the data from the database and bind it to each of the controls.  If you override a method, you have a choice of calling the base method or simply replacing all of the functionality provided by the base class.

Each of the generated files contains two regions.  The first region is generated once and never overwritten.  This is called Section 1 and may also be referred to as the “safe” region of a file.  The second region may be regenerated during a rebuild and should not be modified.  This is called Section 2 and may also be referred to as the “gen” region of a file.

C#:

#region "Section 1: Place your customizations here."

 

     // Contains derived classes - you can override any method defined in inheritted classes.

     // Contains methods that can be modified.

 

#endregion

 

#region "Section 2: Do not modify this section."

 

     // Contains classes and methods that should not be modified.

     // Everything in this section may be overwritten during a rebuild.

 

#endregion

Visual Basic .NET:

#Region "Section 1: Place your customizations here."

 

     ' Contains derived classes - you can override any method defined in inheritted classes.

     ' Contains methods that can be modified.

 

#End Region

 

#Region "Section 2: Do not modify this section."

 

     ' Contains classes and methods that should not be modified.

     ' Everything in this section may be overwritten during a rebuild.

 

#End Region

What is Atlas?

 

What is Atlas?

The Atlas features of ASP.NET are not just another AJAX script library for writing client-centric Web applications. Atlas builds on the .NET Framework 2.0 and adds support for better utilizing the capabilities of client-side JavaScript and the XMLHttpRequest object. It includes server-based features that make it easy to enrich existing ASP.NET applications, as well as a client script library that is used by the Atlas controls and services. The architecture diagram in Figure 1 shows that the Atlas architecture extends across client and server and should be viewed as a broad set of development technologies for creating richer, more responsive cross-browser Web applications.

Figure 1 ASP.NET Atlas Architecture
Figure 1 ASP.NET Atlas Architecture

Scenarios enabled by Atlas are not limited to updating regions of the page with an asynchronous JavaScript call. You also get richer client experiences that would otherwise be impractical. For example, consider a Web application built around movie data. The application might want to allow users to search for a specific actor. Obviously it wouldn’t be practical to provide a comprehensive dropdown list of all actor names to choose from, so the application would probably break the problem down. Users might be asked to select the first letter of the actor’s name. A request to the server could then provide a list that would be somewhat more manageable, but the user experience is not great. The application could present the user with a textbox to enter in part of the actor’s name. The server would then at least have some data to use in narrowing the search. This is better, but still leaves room for improvement. With Atlas you could provide a textbox that reacts dynamically as the user types to help narrow the search without waiting for the browser to refresh the whole page. Figure 2 shows how you could use Atlas to add autocomplete behavior that provides feedback as the user types.

Figure 2 Filtering Combobox
Figure 2 Filtering Combobox

The Atlas CTP is available as a download from atlas.asp.net. When installed, it adds an additional Web Site template for C# and Visual Basic® .NET to Microsoft Visual Web Developer™. When you create a new Web site project in Visual Web Developer (click File, then New, then Web Site), you will see a dialog like the one shown in Figure 3. The Atlas Web site includes Microsoft.Web.Atlas.dll and an updated web.config file that configures the Web application to be able to use Atlas-based ASP.NET features. In the current release, Microsoft.Web.Atlas.dll is placed in the bin directory of the application as a local assembly available throughout the application.

Figure 3 Creating an Atlas Web Site
Figure 3 Creating an Atlas Web Site

Atlas-based applications can be easily deployed by copying the files from a development machine to a server with ASP.NET 2.0 without worrying about separately installing Atlas. The installation is at the application level instead of machine level. As subsequent CTP releases become available, they can be used on a machine with older versions of Atlas even as the features evolve and change. This provides more flexibility in migrating to newer versions than if the installation were systemwide.


The Atlas Architecture

The first thing to notice about the Atlas architecture diagram shown in Figure 1 is that it spans both client and server. ASP.NET 2.0 added some additional client features but not to the extent that Atlas does. On the right side of the architecture diagram, notice that Atlas server features are built on top of ASP.NET 2.0 and extend its capabilities. Atlas includes a new set of server controls as well as new features aimed at accessing server-based data and services from the browser.

On the left you’ll see a comprehensive client script library, which can be used independently of the server features in writing client-centric JavaScript. It is the foundation on the client t