Web Application Server Overview

Web Application Development

What is a Web Application?

In very simple terms, a Web Application is a web database application; using new or pre-existing database tables. With the help of the wizards, you can generate a web application in a matter of minutes; complete with background, appropriate buttons and access to your database tables.

Web Applications are thin client applications. Processing takes place on the server side, and only the web page is sent, or resulting XML in case of a Web Service call, resulting in faster performance, and increased security. This state of the art technology is accomplished by using a combination of files that are easily created during development and work together. The Web Browser Object or Web Service Object (WBO); Active Server Pages (ASP); and DataDictionary (DD) files are the main files.

The Visual DataFlex Studio is the Integrated Development Environment (IDE) for creating Web Applications. The wizards in the Studio will allow you to create Web Application pages and reports. This generates many files including the WBO and ASP files mentioned above. From the Studio, you can jump to the Database Builder utility that will allow you to create your database tables and DD files. These will contain all your business rules for the database tables (i.e., caplock the state field, auto assign an order number, maintain running totals).

Visual DataFlex Web Applications supports HTML, WAP, and XML Web Services.

  • Overview of the Development Cycle

  • Writing Web Applications

  • Creating Active Server Pages

  • Creating Web Browser Objects

  • Debugging Web Applications

  • Troubleshooting Web Applications

Web Applications and Connectivity Kits

Visual DataFlex Web Applications can be used with any Microsoft SQL Server, Pervasive.SQL, IBM DB2, ODBC-supported database or DataFlex database table.

The Visual DataFlex database drivers can be used both for Windows and Web Applications.

Expanding your Knowledge about Web Applications

The following is a list of topics that will help supplement your understanding of the needed concepts underlying Web Applications. Many of these you can find on the Internet or at your local bookstore.

  • Online Technical Knowledge Base: www.dataaccess.com/kbase

  • Technical Support Email: support@dataaccess.com

  • Data Access Newsgroups are at news.dataaccess.com

  • A Basic Understanding of Microsoft’s Internet Information Server (IIS)

  • An Understanding of Standard HTMLCommands

How to Create Controls

How Data is Moved within the Controls (Get/Post Process)

  • An Understanding of Active Server Pages (ASP)

Built-in objects: Response; Request; Server; Session; Application

How to create controls

How Data is moved with Get/Post Process)

How ASP generates HTML

What <%…%> and <%=…%> do

How to use Server Side Scripting

  • Some popular links are:

Builder.com: Web Development - Builder.com contains a lot of useful information, so be sure to search the site for additional topics.

MSDN Online Web Workshop ASP from A to Z

World Wide Web Consortium (W3C)


Overview of the Development Cycle

The following processes are described from a logical point of view rather than how they are implemented in the Studio. The purpose of this is to identify a correct process and all its steps to understand what needs to be done rather than exactly how it will be done. Other sections describe the various processes and process steps from the perspective of the Studio.

  • Overview of Processes

  • Creating a Web Application

  • Creating a Web Application from a Visual DataFlex Windows Application

  • Modifying a Web Application

  • The Actual Processes


Overview of Processes

There are four basic processes that the Studio is designed to perform:

  1. Create a web application

  2. Create a web application around an existing Visual DataFlex Windows Application

  3. Modify a web application

  4. Delete a web application

In the charts that follow the following color key is used:

See Also

Overview of the Development Cycle


Creating a Web Application

The steps for creating a new web application are outlined in the following process diagram:

See Also

Overview of the Development Cycle


Creating a Web Application From a DataFlex Application

Creating a Web Application From a Visual DataFlex Windows Application

The steps for creating a web application from an existing Visual DataFlex Windows application are outlined in the following process diagram. The existing Visual DataFlex Windows application is assumed to be an Object-Oriented application that uses standard data-dictionary objects.

See Also

Overview of the Development Cycle


Modifying a Web Application

Modifying a web application can be represented by the following discrete sub-processes:

Modifying the Application Components

Modifying Tables and Data-Dictionaries

Modifying Web Browser Objects

Modifying Active Server Pages (ASP)

See Also

Overview of the Development Cycle


The Actual Processes

Before you begin any project in the Studio, you should have a solid system specification that will consist of:

  • The relational database design

  • The data-storage rules

  • The data-flow rules

  • The visual design

  • Report design and other output needs

Once this information is ready, you can use the various tools of the Studio to implement your design. You will:

  • Use the Database Builder to implement the relational database, the data-storage rules and the data-flow rules.

  • Use a tool such as FrontPage to implement the visual design.

  • Use the Studio to assemble the completed application.

  • Use the compiler to build your completed program.

Using the Studio

These are the basic steps in creating an application with the Studio.

  • Create a workspace and program to "house the WBOs"

  • Define and Connect the tables

  • Create the Data-Dictionaries for the tables

  • Use Wizards and Templates to design and build the WBOs

  • Compile and run the Application

Establish a Workspace

You can open an existing workspace or create a new workspace from the Studio. See New Workspace Wizard and Workspaces and Libraries.

Define and Connect the Tables

After your workspace is established, you will need to create your table definitions. You use the Database Builder tool for this. Database Builder will allow you to quickly create table definitions including column names, types, lengths, indexes, and relationships.

Create the Data Dictionaries for the Tables

After you have your tables defined, continue with the Database Builder to create your Data Dictionaries.

Design and Build the Components

With your tables and Data Dictionaries in place, you are now ready to begin creating the WBOs of your application with the Studio.

The program components are categorized by function. The Studio supports the creation of the Web Application itself, WBOs (Web Browser Objects) for data entry and reports, HTML/ASP files, Web Services and other Packages and text files.

To create data entry or report objects, you can use the Wizards. They will ask you a series of questions regarding the title, description, style, the Data-Dictionaries to use and so on. When finished, the wizard will create the object. You can also start with an already-existing template and modify it.

Compile and Run the Application

With an Application outline and some or all of its WBOs in place, you can now compile and debug/run it.

See Also

Overview of the Development Cycle


Learning from the Web Application Examples

Visual DataFlex comes with 2 Web Application examples; an ASP Test Page and a Data Entry and Report Example (in the Order Entry workspace).

You can view the Web Application examples in your Web Browser immediately after installing the product.

ASPTest12_0

ASPTest12_0 is the abbreviation for Web Application ASP Test Page. This sample is simply a single ASP page with no database functionality at all. This virtual directory and page are provided simply to test if Active Server Pages are properly executing on the PC where the Web Application Server is installed.

After installing the product, you can access this ASP Test page from a Web Browser by typing in the following URL:

http://localhost/ASPTest12_0

This should bring up an HTML page that displays the text "Web Application Server is Cool!" 5 times in increasing fonts and changing colors.

If you see the text 5 times as described above, Active Server Pages are executing on your PC.

If you do NOT see the text displayed as described above, Active Server Pages are not executing properly. If this happens, please check your Microsoft installation and documentation make sure Microsoft NT Option Pack is installed properly.

Data Entry and Report Example

After installing the product, you can access this sample application from a Web Browser by typing in the following URL:

http://localhost/Order_Entry_12

Once you bring up this sample application, you can click on the "More" link on the left side of the frames page to see a detailed description of the sample application's functionality.

What this Sample Demonstrates

This application is an example of Web-based data entry and reporting. You will see data entry pages for Customers, Sales People, Vendors and Inventory Items. You can also see reports for Customers and Orders, and there are a few example web services.

One of the functionalities shown in this example is a login page where you can log into the system. This functionality is taken a step further by dynamically allowing access to different functions on the same web pages based on your login rights. If you successfully log into the system, the Save and Delete buttons appear on the data entry pages so that you now have edit rights.

When testing the data entry functionality, pay attention to the data validations. For example, bring up the Customers page and enter some data, but leave the Customer Name field blank, then click on the Save button (provided you have logged in first). You will see that the page brings up an error message that tells you the customer name is a required field. Notice also that the other information you have entered is still on this page and you do not have to "go back" to another page to edit it. Last, notice that the actual form label for the form field causing the error is now red.

Some other functionality of the data entry pages is a combobox from which you can select the index by which records are found. This combobox can be created at design time or runtime and applies to both the 'find' buttons with which you can find records in each page and the 'List' button with which you can call up an instant report of the database.

The 'List Orders' report page is an example of drill-down reporting. It lists all existing orders with a hyperlink on the order number. Clicking on the link brings up another page, which shows all details regarding that order.

The "More" hyperlink gives you more information about this example, including some alternate data entry and reporting pages, which are not linked to by the hyperlinks on the left side of the frames page.


Creating a New Web Application

When you create a new Web Application, Visual DataFlex actually does a lot of work for you behind the scenes. The Studio makes it as easy as possible for you to create the pieces you need for a web application by providing several wizards. Of course you may take the output of these wizards and customize them as much as you want. This is just part of the power and flexibility of Visual DataFlex.

To start select New, then Project from the File pull-down menu. You then select Web Project from the Project tab page.

Click OK and the Web Application is created, ready for you to add WBOs.

If you have not yet created your first Web Application, see the Creating Your First Web Application section in Quick Start.


Overview_writingWeb Applications

Writing Web Applications - Overview

This section of the provides an introduction to the concepts and processes involved in writing Web Applications using the Visual DataFlex Studio.

These are the basic steps of building a Web Application.

  1. Analysis: Determine and balance the needs of the target user and customer.

  2. Design: Design a suitable database model, and user interface that can achieve the Web Application’s goals.

  3. Tables and Data-Dictionaries: Implement the database model by building a relational hierarchy of database tables and applying data dictionaries to each table to implement the data-processing rules.

  4. WBOs: Each user-interface element of your Web Application, such as an entry form or a report, will interact with a subset of your database model. Each unique subset of tables from your database is called a view. These views are implemented as Web Browser Objects (WBOs).

  5. User-Interface: Web Application user-interface components are implemented using ASP (Active Server Pages). ASP allows you to design Web Pages that are executed on the Web Server and output HTML to the client device (Browser Application). The ASP files interface with the WBOs to perform all of the database operations and queries.

See Also

The Visual DataFlex Studio

Layers of a Web Application

Web Application Requirements


The Visual DataFlex Studio

The Visual DataFlex Studio is the Integrated Development Environment (IDE) that you will use for creating your Web Applications. It builds a test environment so that you can make sure your Web Application and all its components will perform as you want when they are published onto the actual Web Server. It manages its projects inside Workspaces, and coordinates all of the other tools you may need, so they can be cohesively applied to a project.

Wizards are provided to lead you through the most often used steps of creating Web Applications, together with their Web Browser Objects and Reports. Templates are provided as starting points for many components, and you can create your own templates from a component (or set of components) at any point in the creation process to avoid the need for repetition later.

Using the Studio, you can define a complete data-aware Web Application. You can define your database tables, establish the rules governing the entry and display of data, as well as create the interface through which the application is used. In addition, you can easily integrate hand-written source code into that generated by the Studio. You can do this while still allowing the Studio to maintain and extend the portions of the code that it generates.

The Studio provides context-sensitive help at many levels and, if you find yourself asking "What source files are going to be affected?" or "Why is this option unavailable here?" look down at the status bar and the answer is probably there. Tool-tips, menu options and the status bar, are all context-sensitive to provide you with as much current and specific information as possible.

See Also

Writing Web Applications


Layers of a Web Application

Web Applications use Active Server Pages (ASP) to provide dynamic HTML content to the browser. Each ASP can interface with a Web Browser Object (WBO) that is also running on the Visual DataFlex Web Application Server. The WBOs define a structure of Data-Dictionary objects and a series of interface routines that are called by the ASP. The Data-Dictionary objects provide controlled access to the Web Application’s database via a defined set of rules (business rules).

See Also

Writing Web Applications


Web Application Requirements

The following is a description of the major requirements to run a Web Application on a Web Server and access it from a client device (Browser).

  • Web Browser: Users will interact with your Web Application using a Web Browser such as Netscape or Internet Explorer. Web Application Server Applications support Ultra-Thin Clients thus allowing client access to your Web Applications using virtually any kind of Web Browser. It should preferably support HTML 3.2 or above, and cookies. A Web Browser without support for cookies will also work, but the Server will create a new session for every user request. Both Netscape and Internet Explorer have support for cookies.

  • Web Server is the WWW server. The Visual DataFlex Web Application Server supports MS IIS (Internet Information Server).

  • Active Server Page (ASP) support: The HTML that is sent to the Client's Web Browser by your application is generated using server-side scripting. ASP is the Microsoft Internet Information Server (MS IIS) server-side scripting module. It is installed together with MS IIS 3 or higher.

  • DBMS: Your Web Application can utilize any DBMS that can be controlled by Web Application Server Data Dictionary objects. Supported DBMS’ include the Visual DataFlex embedded database, Pervasive.SQL, Microsoft SQL Server, IBM DB2 Universal Database and ODBC-supported databases.

See Also

Writing Web Applications


Definition of Terms

The use of terms can be very confusing if you do not fully understand how they are used. Therefore, a brief overview is in order.

  • Active Server Page (ASP)

  • Data-Dictionary

  • Web Application

  • Web Browser Object (WBO)

See Also

Writing Web Applications


ASP

Active Server Pages (ASP)

Active Server Pages (ASP) is a method for creating programs that run on a Microsoft Web server. It was first available on the Microsoft Internet Information Server 3.0 (IIS). By using Active Server Pages you can design HTML files that run VBScript or JavaScript code on the server. This script is typically used to dynamically output the HTML that is to be sent to the browser.

ASP is used in Web Applications by writing VBScript or JavaScript to communicate with Web Browser Objects (WBOs) on the Web Server. WBOs are designed to perform all of the database chores that are required by your Active Server Pages.

Related Topics

Creating ASPs

See Also

Definition of Terms


Data Dictionary

Data-dictionaries are the repositories for your Web Application’s business rules. They centralize database rules, business rules and application logic in one place.

This enables the system designer to quantify the presentation and flow of data through the database and ensures that all application pieces that access data do so according to these pre-defined rules.

Related Topics

DataDictionary Class

See Also

Definition of Terms


Web Application

In its most simple form a Web Application is a set of static HTML files that exist on a Web server (ISP) and can be accessed and displayed in a browser application such as MS Explorer or Netscape.

Today’s World Wide Web users require more sophistication and flexibility. Web Applications need to have access to vast databases allowing data entry and data mining. Web pages need to be able to dynamically modify their content (dynamic content) based on user needs and the constantly changing information being presented.

Web Applications created in the Visual DataFlex Studio can do all of this and are designed to provide n-tier access from a web browser to your Web server databases. The HTML that is sent to the browser requires no plug-ins, Active-X controls or Java beans, thus supporting very-thin clients.

Related Topics

Layers of a Web Application

cWebApp Class

See Also

Definition of Terms


WBO

Web Browser Object (WBO)

Web Browser Objects (WBOs) are the components of your Web Application that create an interface between the database and the Active Server Pages.

Each WBO contains a structure of data-dictionary objects that define a specific view of the Web Application’s database. Different WBOs are built according to the data-management requirements of the Web Application.

Related Topics

cWebBusinessProcess Class

See Also

Definition of Terms


Building Data Dictionaries

The key to successful database applications is good data modeling. After designing the structure, attributes and business rules of your database, you can use the Database Builder to implement your data model.

Related Topics

Data Dictionary Guide

DataDictionary Class

See Also

Writing Web Applications


Building Database Views

Each user-interface element of your Web Application, such as an entry form or a report, will interact with a subset of your database model. Each unique subset of tables from your database is called a view. These views are implemented as Web Browser Objects (WBOs).

Each WBO contains a structure of Data Dictionary Objects that model the database view. It also defines a series of interface methods (procedures and functions) that allow it to communicate with your Web Application’s user-interface components (ASP).

This process is discussed more fully in the following sections…

  • The Web Browser Object

  • Sample WBO File

Further information on writing WBOs can be found in the following sections of the help system…

  • Creating Web Browser Objects

  • The cWebBusinessProcess Class

See Also

Writing Web Applications


The Web Browser Object (WBO)

Each Web Browser Object (WBO) contains a structure of Data Dictionary Objects (DDO) and one or more methods (procedures and functions) that use the DDO structure to access and alter data.

Each DDO in the structure contains all of the data-processing rules for a single table. When connected to other DD objects, the structure comprises a set of rules for a database. These DDOs are accessed by methods in the WBO.

A WBO contains built-in methods for handling remote data entry requirements (save, delete, find and clear). It has the ability to output HTML text (for reporting), and can communicate with an ASP/HTML file via the COMWBO object. The most basic WBO must contain a DDO structure. This basic WBO can be used by any ASP file to find, clear, delete and save records for any table in the DDO structure. If reporting is required, a report method (procedure) must be created within the WBO. This report method will use the DDOs to find records and then output the data in HTML format to the ASP file.

The interface between an ASP/HTML file and a WBO is actually quite simple. Typically, a user will make some kind of request action on a browser (e.g., they will enter data into forms and press a button, or, they will click on a URL link). This action will request that an ASP file be loaded and processed.

The ASP file then accesses the WBO by sending it the following messages:

DDValue: Asks the WBO to return the current Data Dictionary value for the passed table and column. An optional extra parameter may be passed to determine the type of Data Dictionary value to be returned (long label, status help, etc.). By default, the DD’s current field value is returned. The ASP file will use this information to create an HTML output that displays this data.

RequestSave: Asks the WBO to perform a save for the passed table. Posted data from the HTML form will be used to update the Data Dictionaries.

RequestDelete: Asks the WBO to delete the current record (row) for the passed table. The current record is determined by the posted HTML data.

RequestFind: Asks the WBO to find a record in the database, according to the passed mode (e.g., Next, Previous) and index. Posted data from the HTML form will be used to seed the Data Dictionaries prior to the find.

RequestClear: Clears the current row of the passed table.

RequestDDUpdate: Updates all of your DDOs so you can reliably use the DDValue function to obtain information about your DDOs within the ASP page, and it lets you know if your current DDO is valid.

RequestFindbyRowId: Performs a find by RowId for the passed table name and rowId.

No special coding is required to execute any of the above procedures. As long as your DDO structure is properly created, the WBO contains all the knowledge required to perform these remote data entry tasks.

Call: Allows you to pass messages and parameters from ASP to the WBO, where they are executed. This allows you, from within ASP, to retrieve and set WBO properties, and call custom WBO processes (functions and procedures). When developers create custom WBO methods and properties they will use this call function to access them. This opens up the full power of WBOs and allows developers to "do whatever they want." All call methods must be published within a WBO before they can be used by the call function.

To give you an idea of how this all works, we will step through a save process. As you read this, keep in mind that this entire process is automatic.

  1. An HTML form has been created and is displayed on the user’s Web Browser. This display will consist of input forms that contain the data.

  2. The user makes the needed changes to the HTML data and presses the Save button. This causes the request type (save, delete, clear, etc.) and the form data to be posted to an ASP file on the Web Server. The ASP file will process the posted data, recognize that a save request has been submitted and call the RequestSave function in the COMWBO, passing the name of the main table to which to apply the save.

  3. The COMWBO redirects this message to the WBO, passing the name of the WBO and the name of the main table. Web Application Server identifies the WBO and sends the RequestSave message to this object, passing the name of the main table. The WBO locates the DDO for the passed table name and starts the save process.

  4. The WBO must first re-find the current record structure. It:

  • First clears the DDO structure.

  • Sends a message to the COMWBO asking the COMWBO to return all record identifiers (RowIds) in the posted HTML form.

  • For each record identifier, a DDO find and relate occurs. These finds and relates occur in a bottom up fashion. First the main DDO is re-found and all relational parent records are found.

At the end of this step, all records have been re-found.

  5. The WBO sends a message to the COMWBO asking it for all data from the HTML forms. The COMWBO sends this information to the DDOs via messages to the WBO. As data is moved into the Data Dictionary objects, formatting requirements of the business rules encoded in the DD objects are enforced. For instance, if the field is designated to be CapsLocked, the DDO uppercases the data.

    At the end of this step, all changed data has been moved from the HTML form to the DDO and all formatting required by the business rules have been applied.

  6. The WBO now sends a message to the DDO corresponding to the main table requesting field validations required by the business rules. Field validation is applied to fields in the main DDO and all connected DDOs. If a validation error occurs, the error is recorded and the validation continues. This allows us to send a list of all validation errors back to the Web browser.

    At the end of this step all records have been re-found, all fields updated and all fields validated.

  7. If there were no field validation errors and there is changed data, a Request_Save message is now sent to the main DDO. The DDO will now perform a standard DDO save (lock, reread, backout, update, validate, save).

  8. If errors occurred in steps 6 or 7, the errors will be displayed in the HTML page sent to the Web Browser.

  9. The HTML page will now be dynamically generated. As the ASP file generates the page, it will require field value data from Web Application Server. The COMWBO will send a message to the WBO requesting data from the Data Dictionary. The data returned will be the current data in the DDO. If the DDO was cleared as a result of a successful save, the new HTML page will show cleared data. If data was not cleared, the HTML page will show the current data.

One feature to note about the COMWBO-to-WBO interface is that all requests for file and field data are passed as names and not numbers. The WBO will parse the passed name and, at runtime, determine the appropriate File (table) and Field (row) identifiers. As long as file and field names are not changed, this allows you to maintain your ASP files and your WBOs independently. If you change an ASP file, you will not need to change or recompile your Web Application program. If you change your Web Application program, you will not need to change your ASP file.

Similar processes exist for RequestDelete, RequestClear and RequestFind.

See Also

Building Database Views (WBOs)


Sample WBO File

Following is a sample WBO file. Its corresponding ASP component can be seen by clicking here. The Web Application Studio Entry Wizard generates both of these files. They are included here only to provide the reader with an introductory sense of these components. Note how simple and small both of these files are. The cWebBusinessProcess Class and the DataDictionary classes are doing almost all of the work for you. It is interesting to compare this ASP file with other, non-Web Application Server ASP file examples that demonstrate data access techniques. The Web Application Server model is much simpler and much more powerful.

This sample is capable of saving, clearing, and finding records to a table of customers..

Use cWebBusinessProcess.pkg

Use Customer.dd

Object oCustomerEntry Is A cWebBusinessProcess

Set psDescription To "Customer Entry"

Set pbClearAfterSave To False

Object oCustomer_DD Is A Customer_DataDictionary

Send DefineAllExtendedFields

End_Object // oCustomer_DD

Set Main_DD To oCustomer_DD

Send RegisterStandardInterface

// Send RegisterDebugInterface

// Send RegisterFullErrorInterface

// Send RegisterAutoEntryInterface

Set pbAllowSaveNew To True

Set pbAllowSaveEdit To True

Set pbAllowDelete To True

Set pbAllowClear To True

Set pbAllowFind To True

Set pbAllowDDUpdate To True

End_Object // oCustomerEntry

See Also

Building Database Views (WBOs)


Building the User Interface

The User Interface is the part of your Web Application that interacts with the Browser Application. This requires designing a Web of HTML pages. You can use any Web Authoring tool, such as Microsoft’s FrontPage.

To write HTML that can interact with Web Browser Objects (WBOs) you must use ASP and Server-Side Scripting (VBScript or JavaScript). This process is discussed more fully in the following sections…

  • Web Server Requirements

  • Dynamically Creating HTML Output

  • Communicating with WBOs

  • Sample ASP File

For further information about creating and maintaining ASP files refer to the Creating Active Server Pages section of the Help system.

See Also

Writing Web Applications


Web Server Requirements

Web Applications require certain capabilities from your Web Server. The Web Server must be able to:

  • Dynamically create HTML output

  • Support a server-side scripting language

  • Create objects that can communicate with the WBOs

To accomplish this the Web Applications use Active Server Pages (ASP), which runs on the Microsoft IIS server, and WBO and uses ASP files to generate HTML output and to communicate with the COM object.

See Also

Building the User Interface


Dynamically Creating HTML Output

Active Server Page (ASP), is a server-side scripting environment that lets you create and run dynamic Web Server applications. The Web Server runs these scripts rather than the client (the web browser). The Web Server does all the work involved in generating the HTML pages that you send to browsers.

An ASP script begins to run when a browser requests a .asp file from your Web Server. Your Web server then calls ASP, which reads through the requested file from top to bottom, executes any commands, and sends an HTML page to the browser. Your browser has no knowledge of the .asp file; it just receives standard HTML output.

An ASP file consists of:

  • Text

  • HTML tags

  • Script commands. A script command instructs your computer to do something, such as assign a value to a variable. ASP directly supports VBScript and JavaScript.

ASP files can be viewed and edited with any standard text editor and with many HTML editors (e.g., Microsoft FrontPage). An ASP file looks like an HTML file with special embedded tags. These special tags are server-side extensions. As the name implies, server side extensions are processed at the server. The result of this processing, if any, is sent to the client browser as standard HTML output.

See Also

Building the User Interface


Communicating with WBOs

The Active Server Page engine provides access to five predefined objects:

  • Request

  • Response

  • Application

  • Session

  • Server

These objects provide the ASP HTML/Script developer access to the entire HTTP/HTML Web environment. In addition, ASP can communicate with custom COM objects. These objects can be used to communicate with other parts of your network environment (e.g., a database) and to move processing logic to external objects when your .asp file cannot or should not do the processing.

The custom object used in your ASP environment is Web Application Server's COM Web Browser Object (COMWBO. The COMWBO communicates with Web Application's Web Browser Object (WBO). This represents the link between the WBO and ASP.

As you will see, the interface between the ASP and the WBO is quite simple. We allow each domain to do what it does best. The server-side ASP files generates your user interface (i.e., they generate the HTML output that the browser uses). The WBO handles all data processing according to the business rules that you set. The ASP file interacts with your database data at a very high level; it can request data and/or a process (e.g., save/find/delete a record, or generate a process/report). A typical ASP file will contain no data processing scripting code. A typical WBO will contain no user interface code.

The following diagram shows how the Web Application Server interface might be represented to the developer.

  1. There are two active programmable components – the ASP file and the WBO object. The COMWBO is a passive object that serves as a conduit between the two active components. Both the WBO program and the ASP file can access this object, each with its own predefined interface.

  2. The Visual DataFlex Studio's Wizards get you started by creating both the ASP and the WBO components. Once created, you can alter either component manually. Normally, you will alter the ASP file to create more sophisticated displays and user interfaces. You will alter the WBO to model more advanced business processes.

  3. The Data Dictionary structure used in the WBO is programmed automatically from the pre-defined structures in each Data Dictionary. These Data Dictionaries represent the business rules that apply to your database tables. The Data Dictionary Objects provide the WBO with the actual data processing services, such as finding, deleting and saving.

  4. The basic business processes provided by the WBO are actually quite sophisticated. The WBO handles the database; finding, clearing, deleting and saving operations. All data is validated before any save or delete, all input errors are reported, and all transactions employ an automatic multi-user model in which integrity is maintained down to the field (column) level. For example, if two users on two different browsers edit two different columns of the same row and press "Save" at the same time, both columns will be properly updated. No additional programming is required to enable this multi-user capability.

  5. The ASP file does not have direct access to your data. ASP requests are sent to the WBO, which directs the request to its process interface. This process interface then interacts with the Data Dictionaries, which in turn interacts with your database. This has two important benefits:

  • Your data is very secure. If your Data Dictionaries are properly defined, there is virtually no way you or anyone else could create an ASP script that could damage your data. With the proper safeguards placed in your WBO, you can also ensure that sensitive data is not accidentally exposed over the Web. This cannot be said for other current Web data access methods, such as ADO or JDBC, which use some variant of ODBC and SQL to directly access and alter data. The main problem with this method is represented in the name "ODBC" – your data is "open."

  • It is very easy to access data within your ASP files: You access data within your ASP files at a very high level. ASP scripting languages are not well suited for database queries and manipulation; Web Application Server is. While working within the ASP file, you will concentrate primarily on the user interface and you will be able to use the latest industry tools, such as FrontPage, when creating these user interfaces. Again, comparison with other web data access methods, is appropriate. ASP files that directly use ODBC/SQL methods to access data result in extremely complicated and hard to maintain files.

  6. The client web browser is an extremely thin client. Any browser that supports HTML 3.2 or above can access your data. Because Web Application Server handles all of the complicated display and validation logic, the HTML data actually sent to the browser client is quite small and therefore quite fast. On today’s overloaded Internet, a thin client is a happy client. While the HTML data sent to the browser is by default quite small, there are virtually no restrictions as to what actually can be sent to the client. You can choose to send HTML files that contain client side scripts, bitmap files, audio-visual files, Java applets, dynamic HTML (DHTML) or whatever the next "hot" technology happens to be.

While these features may appear to be very centric to a single Web Server technology (MS IIS and ASP), in reality they are not. They are centric to modern Web Server technology. They consist of:

  • Dynamic creation of HTML

  • Embedded server-side scripting

  • Server-side objects (COM, Java Servlets, etc.)

All modern web servers either currently provide or will shortly provide these capabilities. IIS and ASP just happen to be Web Application Server's first port.

See Also

Building the User Interface


Sample ASP File

Following is a sample ASP file. Its corresponding WBO component can be seen by clicking here. The Web Application Studio Entry Wizard generates both of these files. They are included here only to provide the reader with an introductory sense of these components. Note how simple and small both of these files are. The cWebBusinessProcess Class and the DataDictionary classes are doing almost all of the work for you. It is interesting to compare this ASP file with other, non-Web Application Server ASP file examples that demonstrate data access techniques. The Web Application Server model is much simpler and much more powerful.

This sample is capable of saving, clearing, and finding records to a table of customers..

Sample ASP File

<% '

' Customer Entry

'

Option Explicit ' Force explicit variable declaration.

' Declare variables

Dim Index, RunReport

Dim RowId

Dim CheckFieldChange, DebugMode, FieldError

' Initialize Standard Information

Index = Request("Index") ' The last selected Index number

RowId = Request ("RowId") ' If a record Id was passed

RunReport = (Request ("RunReport")<>"") ' If run report was selected

%>

<html>

<head>

<meta http-equiv="content-type" content="text/html;charset=iso-8859-1" />

<meta name="generator" content="Visual DataFlex Studio" />

<title>CustomerEntry</title>

<link rel="STYLESHEET" href="css/WebApp.css" type="text/css" />

</head>

<body topmargin="5" leftmargin="5">

<% CheckFieldChange=oCustomerEntry.Call("Get_peFieldMultiUser") %>

<!-- #INCLUDE FILE="inc/SetChangedStates-script.inc" -->

<!-- #INCLUDE FILE="inc/ddValue_Constants.inc" -->

<% ' DebugMode = 1 ' uncomment this for page get/post debug help %>

<!-- #INCLUDE FILE="inc/DebugHelp.inc" -->

<h3>Customer Entry</h3>

<%

oCustomerEntry.Call "Set_pbReportErrors", 1 'Normally show any errors that occur

'We either find a record, or clear the WBO

If RowId <> "" Then

Err = oCustomerEntry.RequestFindbyRowId( "Customer", RowId)

Else

Err = oCustomerEntry.RequestClear("Customer",1)

End If

' process various buttons that might have been pressed.

' only support Post submissions

If Request ("Request_Method") = "POST" Then

If Request ("Clear") <> "" Then

Err = oCustomerEntry.RequestClear("Customer",1)

End If

If Request ("Save") <> "" then

oCustomerEntry.Call "Set_pbReportErrors", 0

Err = oCustomerEntry.RequestSave("Customer")

If Err = 0 Then

Response.Write("<center><h4>Customer Record Saved</h4> </center>")

Else

Response.Write("<font color=""red"">")

Response.Write("<center><h4>Could not save changes. Errors Occurred</h4> </center>")

oCustomerEntry.Call "Msg_ReportAllErrors"

Response.Write("</font>")

End If

End If

If Request("Delete") <> "" Then

oCustomerEntry.Call "Set_pbReportErrors", 0

Err = oCustomerEntry.RequestDelete("Customer")

If Err = 0 Then

Response.Write("<center><h4>The record has been deleted.</h4></center>")

Else

Response.Write("<font color=""red"">")

Response.Write("<center><h4>The record could not be deleted.</h4></center>")

oCustomerEntry.Call "Msg_ReportAllErrors"

Response.Write("</font>")

End If

End If

' note we use the Index variable we created above

If Request("FindPrev") <> "" Then Err = oCustomerEntry.RequestFind("Customer", Index, LT)

If Request("Find") <> "" Then Err = oCustomerEntry.RequestFind("Customer", Index, GE)

If Request("FindNext") <> "" Then Err = oCustomerEntry.RequestFind("Customer", Index, GT)

If Request("FindFirst") <> "" Then Err = oCustomerEntry.RequestFind("Customer", Index, FIRST_RECORD)

If Request("FindLast") <> "" Then Err = oCustomerEntry.RequestFind("Customer", Index, LAST_RECORD)

End If

' Create function To return selected String for design time find Index

Function ShowSelected (Index , Item)

If CStr (Index) = CStr (Item) Then

ShowSelected = "Selected"

Else

ShowSelected = ""

End If

End Function

%>

<form action="CustomerEntry.asp" method="post" name="Customer" OnSubmit="SetChangedStates(this)">

<% ' You MUST have a hidden Rowid field for each DDO in your WBO %>

<input type="hidden" size="15" name="Customer__Rowid" value="<% =oCustomerEntry.DDValue("Customer.Rowid") %>" />

<% ' This is needed if you need field level change state checking %>

<input type="hidden" name="ChangedStates" value="" />

<p class="Toolbar">

Find

<input class="ActionButton" type="submit" name="FindFirst" value="&lt;&lt;" />

<input class="ActionButton" type="submit" name="FindPrev" value="&lt;" />

<input class="ActionButton" type="submit" name="Find" value="=" />

<input class="ActionButton" type="submit" name="FindNext" value="&gt;" />

<input class="ActionButton" type="submit" name="FindLast" value="&gt;&gt;" />

<input class="ActionButton" type="submit" name="RunReport" value="List" />

By

<select size="1" name="Index">

<option value="1" <% =ShowSelected(Index,1) %> >Number</option>

<option value="2" <% =ShowSelected(Index,2) %> >Customer Name</option>

<option value="3" <% =ShowSelected(Index,3) %> >Balance</option>

</select>

&nbsp;&nbsp;

<input class="ActionButton" type="submit" name="Save" value="Save" />

<input class="ActionButton" type="submit" name="Delete" value="Delete" />

<input class="ActionButton" type="submit" name="Clear" value="Clear" />

</p>

<blockquote class="EntryBlock">

<table border="0" class="EntryTable">

<tr>

<% FieldError=oCustomerEntry.DDValue("Customer.Customer_Number", DDFIELDERROR) %>

<td class="Label">

<% If FieldError <> "" Then Response.Write ("<font color=""red"">") %>

Customer Number

<% If FieldError <> "" Then Response.Write ("</font>") %>

</td>

<td class="Data">

<input type="text" size="6" title="" name="Customer__Customer_Number" value="<% =oCustomerEntry.DDValue("Customer.Customer_Number") %>" />

</td>

<% If FieldError <> "" Then %>

<td class="Error">

<% =FieldError %>

</td>

<% End If %>

</tr>

<tr>

<% FieldError=oCustomerEntry.DDValue("Customer.Name", DDFIELDERROR) %>

<td class="Label">

<% If FieldError <> "" Then Response.Write ("<font color=""red"">") %>

Customer Name

<% If FieldError <> "" Then Response.Write ("</font>") %>

</td>

<td class="Data">

<input type="text" size="30" title="" name="Customer__Name" value="<% =oCustomerEntry.DDValue("Customer.Name") %>" />

</td>

<% If FieldError <> "" Then %>

<td class="Error">

<% =FieldError %>

</td>

<% End If %>

</tr>

<tr>

<% FieldError=oCustomerEntry.DDValue("Customer.Address", DDFIELDERROR) %>

<td class="Label">

<% If FieldError <> "" Then Response.Write ("<font color=""red"">") %>

Street Address

<% If FieldError <> "" Then Response.Write ("</font>") %>

</td>

<td class="Data">

<input type="text" size="30" title="" name="Customer__Address" value="<% =oCustomerEntry.DDValue("Customer.Address") %>" />

</td>

<% If FieldError <> "" Then %>

<td class="Error">

<% =FieldError %>

</td>

<% End If %>

</tr>

<tr>

<% FieldError=oCustomerEntry.DDValue("Customer.City", DDFIELDERROR) %>

<td class="Label">

<% If FieldError <> "" Then Response.Write ("<font color=""red"">") %>

City

<% If FieldError <> "" Then Response.Write ("</font>") %>

</td>

<td class="Data">

<input type="text" size="14" title="" name="Customer__City" value="<% =oCustomerEntry.DDValue("Customer.City") %>" />

</td>

<% If FieldError <> "" Then %>

<td class="Error">

<% =FieldError %>

</td>

<% End If %>

</tr>

<tr>

<% FieldError=oCustomerEntry.DDValue("Customer.State", DDFIELDERROR) %>

<td class="Label">

<% If FieldError <> "" Then Response.Write ("<font color=""red"">") %>

State

<% If FieldError <> "" Then Response.Write ("</font>") %>

</td>

<td class="Data">

<% ' This is a VDF dynamic table created as a static combo in ASP

' If you add values To the VDF table you need To add new options. %>

<select name="Customer__State" size="1" >

' The DDSEL in the following code returns " Selected " if field matches passed value

<option value="AK" <% =oCustomerEntry.DDValue("Customer.State" ,DDSEL,"AK") %> >Alaska</option>

<option value="AL" <% =oCustomerEntry.DDValue("Customer.State" ,DDSEL,"AL") %> >Alabama</option>

<option value="AR" <% =oCustomerEntry.DDValue("Customer.State" ,DDSEL,"AR") %> >Arkansas</option>

<option value="AZ" <% =oCustomerEntry.DDValue("Customer.State" ,DDSEL,"AZ") %> >Arizona</option>

<option value="CA" <% =oCustomerEntry.DDValue("Customer.State" ,DDSEL,"CA") %> >California</option>

<option value="CO" <% =oCustomerEntry.DDValue("Customer.State" ,DDSEL,"CO") %> >Colorado</option>

<option value="CT" <% =oCustomerEntry.DDValue("Customer.State" ,DDSEL,"CT") %> >Connecticut</option>

<option value="DC" <% =oCustomerEntry.DDValue("Customer.State" ,DDSEL,"DC") %> >District of Columbia</option>

<option value="DE" <% =oCustomerEntry.DDValue("Customer.State" ,DDSEL,"DE") %> >Delaware</option>

<option value="FL" <% =oCustomerEntry.DDValue("Customer.State" ,DDSEL,"FL") %> >Florida</option>

<option value="GA" <% =oCustomerEntry.DDValue("Customer.State" ,DDSEL,"GA") %> >Georgia</option>

<option value="HI" <% =oCustomerEntry.DDValue("Customer.State" ,DDSEL,"HI") %> >Hawaii</option>

<option value="IA" <% =oCustomerEntry.DDValue("Customer.State" ,DDSEL,"IA") %> >Iowa</option>

<option value="ID" <% =oCustomerEntry.DDValue("Customer.State" ,DDSEL,"ID") %> >Idaho</option>

<option value="IL" <% =oCustomerEntry.DDValue("Customer.State" ,DDSEL,"IL") %> >Illinois</option>

<option value="IN" <% =oCustomerEntry.DDValue("Customer.State" ,DDSEL,"IN") %> >Indiana</option>

<option value="KS" <% =oCustomerEntry.DDValue("Customer.State" ,DDSEL,"KS") %> >Kansas</option>

<option value="KY" <% =oCustomerEntry.DDValue("Customer.State" ,DDSEL,"KY") %> >Kentucky</option>

<option value="LA" <% =oCustomerEntry.DDValue("Customer.State" ,DDSEL,"LA") %> >Louisiana</option>

<option value="MA" <% =oCustomerEntry.DDValue("Customer.State" ,DDSEL,"MA") %> >Massachusetts</option>

<option value="MD" <% =oCustomerEntry.DDValue("Customer.State" ,DDSEL,"MD") %> >Maryland</option>

<option value="ME" <% =oCustomerEntry.DDValue("Customer.State" ,DDSEL,"ME") %> >Maine</option>

<option value="MI" <% =oCustomerEntry.DDValue("Customer.State" ,DDSEL,"MI") %> >Michigan</option>

<option value="MN" <% =oCustomerEntry.DDValue("Customer.State" ,DDSEL,"MN") %> >Minnesota</option>

<option value="MO" <% =oCustomerEntry.DDValue("Customer.State" ,DDSEL,"MO") %> >Missouri</option>

<option value="MS" <% =oCustomerEntry.DDValue("Customer.State" ,DDSEL,"MS") %> >Mississippi</option>

<option value="MT" <% =oCustomerEntry.DDValue("Customer.State" ,DDSEL,"MT") %> >Montana</option>

<option value="NC" <% =oCustomerEntry.DDValue("Customer.State" ,DDSEL,"NC") %> >North Carolina</option>

<option value="ND" <% =oCustomerEntry.DDValue("Customer.State" ,DDSEL,"ND") %> >North Dakota</option>

<option value="NE" <% =oCustomerEntry.DDValue("Customer.State" ,DDSEL,"NE") %> >Nebraska</option>

<option value="NH" <% =oCustomerEntry.DDValue("Customer.State" ,DDSEL,"NH") %> >New Hampshire</option>

<option value="NJ" <% =oCustomerEntry.DDValue("Customer.State" ,DDSEL,"NJ") %> >New Jersey</option>

<option value="NM" <% =oCustomerEntry.DDValue("Customer.State" ,DDSEL,"NM") %> >New Mexico</option>

<option value="NV" <% =oCustomerEntry.DDValue("Customer.State" ,DDSEL,"NV") %> >Nevada</option>

<option value="NY" <% =oCustomerEntry.DDValue("Customer.State" ,DDSEL,"NY") %> >New York</option>

<option value="OH" <% =oCustomerEntry.DDValue("Customer.State" ,DDSEL,"OH") %> >Ohio</option>

<option value="OK" <% =oCustomerEntry.DDValue("Customer.State" ,DDSEL,"OK") %> >Oklahoma</option>

<option value="OR" <% =oCustomerEntry.DDValue("Customer.State" ,DDSEL,"OR") %> >Oregon</option>

<option value="PA" <% =oCustomerEntry.DDValue("Customer.State" ,DDSEL,"PA") %> >Pennsylvania</option>

<option value="RI" <% =oCustomerEntry.DDValue("Customer.State" ,DDSEL,"RI") %> >Rhode Island</option>

<option value="SC" <% =oCustomerEntry.DDValue("Customer.State" ,DDSEL,"SC") %> >South Carolina</option>

<option value="SD" <% =oCustomerEntry.DDValue("Customer.State" ,DDSEL,"SD") %> >South Dakota</option>

<option value="TN" <% =oCustomerEntry.DDValue("Customer.State" ,DDSEL,"TN") %> >Tennessee</option>

<option value="TX" <% =oCustomerEntry.DDValue("Customer.State" ,DDSEL,"TX") %> >Texas</option>

<option value="UT" <% =oCustomerEntry.DDValue("Customer.State" ,DDSEL,"UT") %> >Utah</option>

<option value="VA" <% =oCustomerEntry.DDValue("Customer.State" ,DDSEL,"VA") %> >Virginia</option>

<option value="VT" <% =oCustomerEntry.DDValue("Customer.State" ,DDSEL,"VT") %> >Vermont</option>

<option value="WA" <% =oCustomerEntry.DDValue("Customer.State" ,DDSEL,"WA") %> >Washington</option>

<option value="WI" <% =oCustomerEntry.DDValue("Customer.State" ,DDSEL,"WI") %> >Wisconsin</option>

<option value="WV" <% =oCustomerEntry.DDValue("Customer.State" ,DDSEL,"WV") %> >West Virginia</option>

<option value="WY" <% =oCustomerEntry.DDValue("Customer.State" ,DDSEL,"WY") %> >Wyoming</option>

</select>

</td>

<% If FieldError <> "" Then %>

<td class="Error">

<% =FieldError %>

</td>

<% End If %>

</tr>

<tr>

<% FieldError=oCustomerEntry.DDValue("Customer.Zip", DDFIELDERROR) %>

<td class="Label">

<% If FieldError <> "" Then Response.Write ("<font color=""red"">") %>

Zip/Postal Code

<% If FieldError <> "" Then Response.Write ("</font>") %>

</td>

<td class="Data">

<input type="text" size="10" title="" name="Customer__Zip" value="<% =oCustomerEntry.DDValue("Customer.Zip") %>" />

</td>

<% If FieldError <> "" Then %>

<td class="Error">

<% =FieldError %>

</td>

<% End If %>

</tr>

<tr>

<% FieldError=oCustomerEntry.DDValue("Customer.Phone_Number", DDFIELDERROR) %>

<td class="Label">

<% If FieldError <> "" Then Response.Write ("<font color=""red"">") %>

Phone Number

<% If FieldError <> "" Then Response.Write ("</font>") %>

</td>

<td class="Data">

<input type="text" size="20" title="" name="Customer__Phone_Number" value="<% =oCustomerEntry.DDValue("Customer.Phone_Number") %>" />

</td>

<% If FieldError <> "" Then %>

<td class="Error">

<% =FieldError %>

</td>

<% End If %>

</tr>

<tr>

<% FieldError=oCustomerEntry.DDValue("Customer.Fax_Number", DDFIELDERROR) %>

<td class="Label">

<% If FieldError <> "" Then Response.Write ("<font color=""red"">") %>

Fax Number

<% If FieldError <> "" Then Response.Write ("</font>") %>

</td>

<td class="Data">

<input type="text" size="20" title="" name="Customer__Fax_Number" value="<% =oCustomerEntry.DDValue("Customer.Fax_Number") %>" />

</td>

<% If FieldError <> "" Then %>

<td class="Error">

<% =FieldError %>

</td>

<% End If %>

</tr>

<tr>

<% FieldError=oCustomerEntry.DDValue("Customer.Email_Address", DDFIELDERROR) %>

<td class="Label">

<% If FieldError <> "" Then Response.Write ("<font color=""red"">") %>

E-Mail Address

<% If FieldError <> "" Then Response.Write ("</font>") %>

</td>

<td class="Data">

<input type="text" size="30" title="" name="Customer__Email_Address" value="<% =oCustomerEntry.DDValue("Customer.Email_Address") %>" />

</td>

<% If FieldError <> "" Then %>

<td class="Error">

<% =FieldError %>

</td>

<% End If %>

</tr>

<tr>

<% FieldError=oCustomerEntry.DDValue("Customer.Credit_Limit", DDFIELDERROR) %>

<td class="Label">

<% If FieldError <> "" Then Response.Write ("<font color=""red"">") %>

Credit Limit

<% If FieldError <> "" Then Response.Write ("</font>") %>

</td>

<td class="Data">

<input type="text" size="8" title="" name="Customer__Credit_Limit" value="<% =oCustomerEntry.DDValue("Customer.Credit_Limit") %>" />

</td>

<% If FieldError <> "" Then %>

<td class="Error">

<% =FieldError %>

</td>

<% End If %>

</tr>

<tr>

<% FieldError=oCustomerEntry.DDValue("Customer.Purchases", DDFIELDERROR) %>

<td class="Label">

<% If FieldError <> "" Then Response.Write ("<font color=""red"">") %>

Total Purchases

<% If FieldError <> "" Then Response.Write ("</font>") %>

</td>

<td class="Data">

<input type="text" size="8" title="" name="Customer__Purchases" value="<% =oCustomerEntry.DDValue("Customer.Purchases") %>" />

</td>

<% If FieldError <> "" Then %>

<td class="Error">

<% =FieldError %>

</td>

<% End If %>

</tr>

<tr>

<% FieldError=oCustomerEntry.DDValue("Customer.Balance", DDFIELDERROR) %>

<td class="Label">

<% If FieldError <> "" Then Response.Write ("<font color=""red"">") %>

Balance Due

<% If FieldError <> "" Then Response.Write ("</font>") %>

</td>

<td class="Data">

<input type="text" size="8" title="" name="Customer__Balance" value="<% =oCustomerEntry.DDValue("Customer.Balance") %>" />

</td>

<% If FieldError <> "" Then %>

<td class="Error">

<% =FieldError %>

</td>

<% End If %>

</tr>

<tr>

<% FieldError=oCustomerEntry.DDValue("Customer.Comments", DDFIELDERROR) %>

<td class="Label">

<% If FieldError <> "" Then Response.Write ("<font color=""red"">") %>

Comments

<% If FieldError <> "" Then Response.Write ("</font>") %>

</td>

<td class="Data">

<textarea title="" name="Customer__Comments" rows="5" cols="35"><% =oCustomerEntry.DDValue("Customer.Comments") %> </textarea>

</td>

<% If FieldError <> "" Then %>

<td class="Error">

<% =FieldError %>

</td>

<% End If %>

</tr>

<tr>

<% FieldError=oCustomerEntry.DDValue("Customer.Status", DDFIELDERROR) %>

<td class="Label">

<% If FieldError <> "" Then Response.Write ("<font color=""red"">") %>

Active Status

<% If FieldError <> "" Then Response.Write ("</font>") %>

</td>

<td class="Data">

<input type="radio" title="" name="Customer__Status" value="Y" <% =oCustomerEntry.DDValue("Customer.Status" ,DDCHCK,"Y") %> />Y

<input type="radio" title="" name="Customer__Status" value="N" <% =oCustomerEntry.DDValue("Customer.Status" ,DDCHCK,"N") %> />N

</td>

<% If FieldError <> "" Then %>

<td class="Error">

<% =FieldError %>

</td>

<% End If %>

</tr>

</table>

</blockquote>

</form>

</body>

</html>

If you have worked with HTML, this file should look familiar. If you have worked with ASP, this file should look very familiar. In this sample, the COMWBO object is named oCustomer. Text lines that contain this object name provide the connection to your WBO object.

Each input control contains all of the information required to connect an input form to a Data Dictionary field. For example, the following HTML line:

<input type="text" size="30" title="" name="Customer__Name"

value="<%=oCustomer.DDValue("Customer.Name") %>" >

The name attribute is used to connect to a database table, file and field. The file (table) and field (column) names are separated by a double underscore "__" (i.e., two underscores). When passed to the WBO, the file name and field name are passed as two parameters. In the unlikely case that your file or field names contain double underscores, you can use a different symbol. This setting is maintained in the Application, Properties dialog in the Studio.

The value attribute has been assigned a function value. When the ASP file is being processed, it calls this function and places the returned value in the HTML output file. In this case, it calls COMWBO, requesting the file-field value for "Customer.Name." The COMWBO passes this request on to the WBO, which finds and returns the proper value from its Data Dictionary.

See Also

Building the User Interface


Running a Web Application

Running the Web Application

The following actions must be performed before you can run a Web Application:

  1. Compile WebApp.src

  2. Create a Virtual Web Directory (WebShare alias)

  3. Enable the Web Application in the Administrator

Running the Web Application in a Browser

You can access your web application using a browser from the Studio by clicking the Run button, or selecting Debug -> Run. Once the application is compiled, the debugger is automatically started and your web browser is launched.

If you’re accessing your web application outside of the Studio, then you can simply start your browser and type in the URL of your web application.

If you are running the Web Application over the Internet then the Web Application’s URL is simply…

http://MyWebSite.com/WepAppName

Where MyWebSite.com is the IP address or hostname of the Web Server that is hosting the Web Application; and Web ApplicationName is the Web Application’s virtual directory (WebShare Alias)

If you are running the Web Application locally, then the URL will be…

http://localhost/Web ApplicationName

There is a special IP address 127.0.0.1 that is used to address a local Intranet host. The term LocalHost is an alias for this IP address.

See Also

Writing Web Applications


Compiling Web Application.src

Compiling WebApp.src

Before you can access your Web Application from a browser you must compile the WebApp.src file. WebApp.src is the Web Server application containing each WBO. This application is built, maintained and compiled in the Visual DataFlex Studio.

When running the application from the Studio it’s automatically compiled if necessary. The compiler builds an executable file named WebApp.exe and automatically launches the browser and enters debug mode.

After a successful compile, the Studio will update the Global.asa with a mapping for each WBO in the WebApp.exe. It also generates a TestContents.htm, which contains links to each primary .asp files relating to the WBOs.

See Also

Running the Web Application


Creating a Virtual Web Directory

Before you can run a Web Application you must assign a Virtual Directory (WebShare alias) to the folder containing your Web Application’s homepage (default.asa or default.htm).

The Virtual Directory maps the ASP/HTML directory of your Web Application with a URL. Normally, this maps your WorkspaceName\AppHTML directory to a Web directory. This allows users to access these ASP/HTML files over the Web. Keep in mind that you are setting the name of the virtual directory; you are not setting the name of your Web Application Server application.

The virtual web directories (or web share) is automatically created when you create your web application from the Studio. And it’s also automatically created when you configure the web application in the Web Application Administrator.

See Also

Running the Web Application


Registering the Web Application in the Administrator

The Web Application Administrator maintains a list of available Web Applications. Data for each application is stored in the registry.

This information is initially created for the administrator when the Web Application is created by the Studio. You can maintain this data in the Studio by selecting Properties from the Application menu. You can also maintain it in the Administrator by selecting a Web Application and then viewing its properties sheet.

You can also set up a new Web Application configuration from the Administrator, which can also create the web share. See the section Deploying Web Applications for more information.

See Also

Running the Web Application


Deploying Web Applications

It is recommended that you perform all of your Web Application development in a separate environment from where the finished Web Application will eventually be deployed. This means that your Web Application will need to be migrated to its deployment environment once it has been completed.

Click here to link to a full description on Web Application deployment.


Creating Active Server Pages

Microsoft provides some excellent introductory information on ASP and server side scripting in a document titled "Scripting Guide Overview." This HTML document is loaded into your computer when you install the Microsoft Internet Information Server on Windows NT Server, the Microsoft Peer Web Services on Windows NT Workstation, or the Microsoft Personal Web Server on Windows 95/98. The Personal Web Server can be downloaded from Microsoft and is provided with FrontPage 98 and Windows 98. This document can also be found on the Microsoft Developer’s Network CD (MSDN) and on various Internet sites (search for "Scripting Guide Overview").

A Basic Understanding of the Built-in ASP Objects

ASP provides a number of built-in objects that perform common web application programming tasks. For example a Response object exists that can be used to send responses to your Html page. The most common use of this object is the use of the Write method. This is used to generate Html output. The following code could be used to output the current date to your Html page:

<% response.write ("Welcome, the time is now " & now) %>

ASP provides five built-in objects:

  • Response

  • Request

  • Server

  • Session

  • Application

These are powerful and important objects. Refer to the Microsoft "Scripting Guide Overview" for more information about these objects.

Active Web Server Content

Active server content refers to the manipulation of web pages on the Server before they are made available for download to the client browser. The classic web page is a static HTML document that the server simply downloads in its static form, upon request, to the browser. Microsoft ASP allows for creation of HTML documents "on the fly", according to specifics programmed into ASP documents for that purpose.

There are a number of books available about ASP. You could go down to your local bookstore and do some "old fashioned" browsing. Concentrate on the sections dealing with Server-side Scripting. Most of these books will have a section dealing with accessing a database. You do not need to read this section. Visual DataFlex's Web Application Server provides a much more powerful way to access data over the Internet. Concentrate on these topics:

  • How ASP Generates HTML

  • What <%..%.> and <%=…%> do

  • How to use Server-Side Scripting

  • How Scripting is Used - A basic Knowledge of VBScript

See Also

The Client Web Browser

Web Application Programming Techniques and Samples

The ASP/WBO Interface

ASP Request Functions

DD Request Functions

DDValue Function

Call Function

Conversion Functions

WBO Object Name Substitution

Error Handling Messages

Learning from the ASP Examples


The Client Web Browser

Before discussing how a Web Application interacts with a web browser, a review of browser technology is in order. The biggest advantage of porting applications to the Web is that the application is made available to every person who has access to a web browser. This is the promise of the "thin universal client."

Unfortunately, the data input capabilities of web browsers are somewhat limited. To address this problem, a great deal of industry energy was spent attempting to improve the capabilities of the web browser. Some of the web browser enhancements include HTML 4.0, DHTML, Java applets, and client side scripting.

These enhancements have created their own set of problems.

  • While the majority of web browsers support HTML 3.2, it will be a long time before you can count on most browsers supporting HTML 4.0.

  • As of this writing, the latest web browsers from Netscape and Microsoft support a different sub-set of HTML 4.0 features.

  • While most browsers currently support Java applets, the Java engines used by the different browsers and browser versions differ in capabilities and bugs. Even if Java standards existed, this is no guarantee that your 100% certified Java application will run on a browser.

  • Client side scripting capabilities (and reliability) differ on different web browsers.

  • While Dynamic HTML (DHTML) is very exciting technology, most web browsers do not yet support it.

  • Different web browsers handle non-supported features differently. Some unsupported features are ignored (not good if you are counting on the browser to perform validations), some unsupported features will generate errors, and other unsupported features will simply crash your browser.

Developers have attempted to solve these problems in several ways. Some web sites' introductory HTML pages warn you that they may not run on your browser (never a good way to introduce yourself to the public). Some HTML pages tell you that their site is best viewed with a particular browser (another way of saying it does not work with all browsers). Some HTML pages use client side scripts (if they work) to check the browser’s capabilities and to display text conditionally.

Performance Considerations

A final, and more serious, problem is performance. The thin client is getting fat. It takes time to load client scripts and Java applets in addition to the already needed HTML text and (perhaps not so needed) graphic files. Therefore, your browser is now slower because it is transferring files and features that may not even run once loaded. A sign of this problem is that developers are encouraged not to place too many comments in the HTML client scripts because these comments are transferred from the Web server to the web client, thereby slowing down the load process. Whenever programmers are encouraged not to write comments, there is a problem.

More recently, many developers and the Web industry itself have decided that the web browser is the wrong place to attempt to solve these problems. This has resulted in the push for server-side solutions. ASP is a good example of where the industry is going.

When an ASP file is requested on the server, the HTML output that is sent to the client is dynamically on the server. Your web server is a known quantity. You know what its capabilities are and you can take proper advantage of them. ASP files support server-side scripting, server-side access to Java applets (now referred to as Servlets), and provide object access to other parts of your server network (like the the Web Application Server WBOs). Server-side processing has the following advantages:

  • Server-side processing allows you to work with known capabilities that you control.
  • You can immediately take advantage of new technologies because you only need to update your web server (which you control) and not the web browsers (which you can not control).
  • Server-side processing is faster (no load time).
  • Your HTML output to the browser will be much smaller and, therefore, faster.
  • Your HTML output will work on more browsers.

For all of the above reasons, the Visual DataFlex model for web development embraces server-side processing and encourages the use of thin web server clients. The Web Application Server and Web Wizard generators employ an extremely thin client. Any web browser that supports HTML/3.2 or above will work properly. No client side scripting, Java applets or any type of client object is required.

Although a thin client is supported and encouraged for Web Application development, there are no restrictions on what is placed in your HTML file. You may generate any type of HTML file you want. For example, if you know that all web browsers accessing your data support HTML/4 you can generate HTML/4 files. If you know that all of your users will have very fast access to the web server you may want to employ a number of client side scripting features. More importantly, as the client browser technology improves and the definition of "any web browser" becomes more feature rich, you can immediately take advantage of these browser capabilities.

Recommendations

In general, we offer the following advice when generating Web Application Server-based HTML files:

  • Place as much of your processing code as possible inside your WBOs. In particular, all data processing logic belongs in WBOs.
  • Write most of your scripting on the server-side and not the client-side. This will increase speed and greatly improve browser compatibility.
  • Remember that, once created, your WBO program and your ASP file are independent. You may change one without having to change the other.
  • As you start to enhance your HTML pages with bitmaps, client scripts, and Java applets remember to test the performance of these files under real conditions. If your customers will be dialing into your server with a 28K line make sure that you test the performance under similar conditions.

See Also

Creating Active Server Pages


Web Application Programming Techniques and Samples

The Web Order Sample (in the Order Entry workspace) was created to demonstrate some of the extended features of the Web Application object interface. For this reason, the techniques in this sample go beyond those used by the web wizard. This sample concentrates on techniques that can be used to enhance the functionality of your web page and allows you to take full advantage of the information in your data-dictionaries at runtime.

This sample does not concentrate on visual enhancements to the interface of your web package. While in a normal application you will want to spend time "dressing up" your web pages, we felt that these visual enhancements would confuse the purpose of this sample.

This document and these samples make extensive use of the server side programming capabilities available with Active Server Pages (ASP). In all of these examples, we use VBScript as our scripting language. At some point you may want to review documentation of ASP scripting and on VBScript. Microsoft provides full documentation for both of these subjects as part of the NT/IIS installation. You will want to understand the following concepts:

  • How server side script is embedded within an ASP file using <% … %> and <%= … %>.

  • The basic language syntax of VBScript.

  • How object functions are accessed within VBScript – using the ObjectName.MethodName calling syntax.

  • How procedures are called within VBScript – ObjName.ProcName param1, Param2,.., Param3.

  • How functions are called within VBScript – Var = ObjName.FuncName(Param1, Param2,…, ParamN).

  • Understand how the ASP Response and Request objects works.

  • Understand how HTML FORM controls operate.

  • Understand the process of passing information back to a web server via GET and POST.

This sample will be taking advantage of two important messages supported by the DataFlex COM/WBO object, DDValue and Call. These functions called from within your ASP file and are then passed into your DataFlex WBO object. These functions are fully described in the WebApp Server documentation. You are encouraged to first review this documentation. A brief review is provided below.

See Also

Creating Active Server Pages


The ASP/WBO Interface

These methods are used within an ASP file to request DataFlex information and processing. These methods are passed to the COMWBO, which in turn passes them to the DataFlex WBO.

All of these methods use standard Object-dot-method syntax: (e.g., ObjectName.Method("file",1,Eq))

These functions are called while an ASP page is being processed. In other words, they are called as a new HTML page is being created. In some cases, calling a function will result in an internal process being executed by the DataFlex WBO (a save). In other cases, a function will result in HTML data being output from within the DataFlex WBO (a report). In some cases, both processing and output will occur at the same time.

If you are going to use these functions you must understand how ASP works and how ASP generates an HTML page. In addition, you should study the ASP files generated by the web wizard. These will show you how all of these messages can be used. However, keep in mind that the wizard output only uses a small part of the ASP scripting/HTML output capabilities.

The following table shows how the ASP generated messages are passed to the DataFlex WBO object.

ASP/COMWBO Method | Corresponding WBO Method
DDValue(File.field,iOption,sParam) | DDValue
RequestSave(sFileName) | DoRequestSave
RequestDelete(sFileName) | DoRequestDelete
RequestClear(sFileName,bClearAll) | DoRequestClear
RequestFind(sFileName, sFieldName,iFindMode) | DoRequestFind
RequestDDUpdate | DoRequesDDUpdate
RequestFindByRowId | DoRequestFindByRowId
Call(MessageName, Param1, …Param5) | MyMessage

In addition to the above interfaces, two other ASP/COMWBO methods are provided to make it easy to convert string data from and to the format used by BinaryWrite and BinaryRead. Those are:

UTF8ToString(UTF8Data)

StringToUTF8(StringData)

See Also

Creating Active Server Pages


The ASP Request Functions

The ASP Request messages (RequestSave, RequestFind, RequestClear, RequestDelete, RequestDDUpdate and RequestFindByRowId) all perform high-level data-manipulation operations from an ASP page. For example, RequestSave will move all data from an ASP page into the WBO, update all DDOs, validate the DDOs and perform a save. If an error occurs, the errors will be displayed in your browser.

These complex processes will only work properly if your ASP pages are properly formatted. The page requirements for each message will be listed below. In general, the following standards must be adhered to:

  • All data entry input controls must be properly named, using the format of Name=FileName__FieldName. The separator between the file and field names is called the FileField Separator. By default it is two underscores, and should not be changed. FileName is the name of the table, and FieldName is the name of the field.

<input type="text" size="6"

name="Customer__Customer_Number"

value="<%=oCustomer.DDValue("Customer.Customer_Number") %>">

  • If you use one of the DDValue parameters that generates an input control automatically (DDAUTO, DDFORM, DDTEXT, DDRADIO, or DDCOMBO), the control will be named automatically by the WBO.

<%=oCustomer.DDValue("Customer.State",DDCOMBO)%>

  • All tables that participate in the operation should have a hidden form control that contains the value of the table’s RowId. That control must be named using the format Name=FileName__RowId, where FileName is the name of the table. The text passed within the DDValue function must be "FileName.RowId". The RowId value returned will be a serialized string value of the record’s RowId that can be represented in an HTML page.

<input type="hidden"

name="Customer__RowId"

value="<%=oCustomer.DDValue("Customer.Rowid")%>">

  • Submit buttons must be created for each operation you wish to support. Each button should be given a unique name that will be used to determine which operation was selected. The button’s value (face value) may be anything you wish

<p>

<input type="submit" name="save" value="Save This">

<input type="submit" name="delete" value="Delete It">

<input type="submit" name="clear" value="Start Over">

</p>

  • All input controls, submit buttons, and hidden record RowID must be placed inside an HTML form. It is expected that a button inside this form will be used to post the data to the server.

  • In most cases, the data will be "posted to itself". When the user presses a submit key, the form’s action will be to post the data to the same ASP file that generated the original HTML page. This is a standard ASP technique.

These rules ensure that the input data will be properly posted to the server. Placed at the top of the ASP page will be VbScript code that checks for the request type and sends the appropriate message to the appropriate WBO.

Here is an example of what this ASP processing script looks like:

<%

oCustomer.call "set_pbReportErrors", 1 'normally show any errors that occur

'We either find a record, or clear the WBO

If RowId <> "" Then

Err = oCustomer.RequestFindbyRowId( "Customer", RowId)

else

Err = oCustomer.RequestClear("Customer",1)

End if

' process various buttons that might have been pressed.

' only support Post submissions

If request("Request_method")="POST" Then

if Request("clear")<>"" then

Err = oCustomer.RequestClear("Customer",1)

end if

if Request("save")<>"" then

oCustomer.call "set_pbReportErrors", 0

err = oCustomer.RequestSave("Customer")

if err = 0 then

Response.Write("<center> <h4>Customer record saved</h4> </center>")

else

Response.Write("<font color=""red"">")

Response.Write("<center> <h4>Could not save changes. Errors Occurred</h4> </center>")

oCustomer.call "msg_ReportAllErrors"

Response.Write("</font>")

end if

end if

if Request("delete")<>"" then

oCustomer.call "set_pbReportErrors", 0

Err = oCustomer.RequestDelete("Customer")

if err = 0 then

Response.Write("<center> <h4>The record has been deleted.</h4> </center>")

else

Response.Write("<font color=""red"">")

Response.Write("<center> <h4>The record could not be deleted.</h4> </center>")

oCustomer.call "msg_ReportAllErrors"

Response.Write("</font>")

end if

end if

' note we use the Index variable we created above

if Request("findprev") <>"" then Err = oCustomer.RequestFind("Customer", Index, LT)

if Request("find") <>"" then Err = oCustomer.RequestFind("Customer", Index, GE)

if Request("findnext") <>"" then Err = oCustomer.RequestFind("Customer", Index, GT)

if Request("findfirst")<>"" then Err = oCustomer.RequestFind("Customer", Index, FIRST_RECORD)

if Request("findlast") <>"" then Err = oCustomer.RequestFind("Customer", Index, LAST_RECORD)

end if

%>

The wizards generate properly formatted data entry ASP pages. The best way to see how to use these processes is to study wizard-generated ASP pages.

The Request messages are all functions. They return a non-zero value if an error occurs. Within the ASP file, you can choose to use these messages as either functions or procedures. If used as procedures, you can ignore the return value. VbScript requires different syntax for functions and procedures as follows.

Sample VbScript code using a function:

BErr = oCustomer.RequestSave( "Customer")

Sample VbScript code using a procedure:

oCustomer.RequestSave "Customer"

We suggest that you always use the function syntax. If you don’t need the error return value, just move it to a variable and ignore it. This allows you to use a single syntax and it reminds you that, at some point, you probably will need that error value.

See Also

Creating Active Server Pages


The DD Request Functions

The Request messages...

  • RequestClear

  • RequestDDUpdate

  • RequestDelete

  • RequestFind

  • RequestFindByRowId

  • RequestSave

...all perform high-level data-manipulation operations from an ASP page. For example, RequestSave will move all data from an ASP page into the WBO, update all DDOs, validate the DDOs and perform a save. If an error occurs, the errors will be displayed in your browser.

These complex processes will only work properly if your ASP pages are properly formatted. The page requirements for each message will be listed below. In general, the following standards must be adhered to:

  • All data entry input controls must be properly named, using the format of Name=FileName__FieldName. The separator between the file and field names is called the FileField Separator. By default it is two underscores, and should not be changed. FileName is the name of the table, and FieldName is the name of the field.

<input type="text" size="6" name="Customer__Customer_Number" value="<%=oCustomer.DDValue("Customer.Customer_Number") %>">

  • If you use one of the DDValue parameters that generates an input control automatically (DDAUTO, DDFORM, DDTEXT, DDRADIO, or DDCOMBO), the control will be named automatically by the WBO.

<%=oCustomer.DDValue("Customer.State",DDCOMBO)%>

  • All tables that participate in the operation should have a hidden form control that contains the value of the table’s Rowd. That control must be named using the format Name=FileName__RowId, where FileName is the name of the table. The text passed within the DDValue function must be "FileName.RowId". The RowId value returned will be a serialized string value of the record’s RowId that can be represented in an HTML page.

<input type="hidden" name="Customer__RowId" value="<%=oCustomer.DDValue("Customer.RowId")%>">

  • Submit buttons must be created for each operation you wish to support. Each button should be given a unique name that will be used to determine which operation was selected. The button’s value (face value) may be anything you wish

<p>

<input type="submit" name="save" value="Save This">

<input type="submit" name="delete" value="Delete It">

<input type="submit" name="clear" value="Start Over">

</p>

  • All input controls, submit buttons, and hidden RowId fields must be placed inside an HTML form. It is expected that a button inside this form will be used to post the data to the server.

  • In most cases, the data will be "posted to itself". When the user presses a submit key, the form’s action will be to post the data to the same ASP file that generated the original HTML page. This is a standard ASP technique.

These rules ensure that the input data will be properly posted to the server. Placed at the top of the ASP page will be VbScript code that checks for the request type and sends the appropriate message to the appropriate WBO.

Here is an example of what this ASP processing script looks like:

<%

oCustSample.Call "Set_pbReportErrors", 1 'Normally show any errors that occur

'We either find a record, or clear the WBO

If RowId <> "" Then

Err = oCustSample.RequestFindbyRowId( "Customer", RowId)

Else

Err = oCustSample.RequestClear("Customer",1)

End If

' process various buttons that might have been pressed.

' only support Post submissions

If Request ("Request_Method") = "POST" Then

If Request ("Clear") <> "" Then

Err = oCustSample.RequestClear("Customer",1)

End If

If Request ("Save") <> "" then

oCustSample.Call "Set_pbReportErrors", 0

Err = oCustSample.RequestSave("Customer")

If Err = 0 Then

Response.Write("<center><h4>Customer Record Saved</h4> </center>")

Else

Response.Write("<font color=""red"">")

Response.Write("<center><h4>Could not save changes. Errors Occurred</h4> </center>")

oCustSample.Call "Msg_ReportAllErrors"

Response.Write("</font>")

End If

End If

If Request("Delete") <> "" Then

oCustSample.Call "Set_pbReportErrors", 0

Err = oCustSample.RequestDelete("Customer")

If Err = 0 Then

Response.Write("<center><h4>The record has been deleted.</h4></center>")

Else

Response.Write("<font color=""red"">")

Response.Write("<center><h4>The record could not be deleted.</h4></center>")

oCustSample.Call "Msg_ReportAllErrors"

Response.Write("</font>")

End If

End If

' note we use the Index variable we created above

If Request("FindPrev") <> "" Then Err = oCustSample.RequestFind("Customer", Index, LT)

If Request("Find") <> "" Then Err = oCustSample.RequestFind("Customer", Index, GE)

If Request("FindNext") <> "" Then Err = oCustSample.RequestFind("Customer", Index, GT)

If Request("FindFirst") <> "" Then Err = oCustSample.RequestFind("Customer", Index, FIRST_RECORD)

If Request("FindLast") <> "" Then Err = oCustSample.RequestFind("Customer", Index, LAST_RECORD)

End If

%>

The wizards generate properly formatted data entry ASP pages. The best way to see how to use these processes is to study wizard-generated ASP pages.

The Request messages are all functions. They return a non-zero value if an error occurs. Within the ASP file, you can choose to use these messages as either functions or procedures. If used as procedures, you can ignore the return value. VbScript requires different syntax for functions and procedures as follows.

Sample VbScript code using a function:

BErr = oCustomer.RequestSave( "Customer")

Sample VbScript code using a procedure:

oCustomer.RequestSave "Customer"

We suggest that you always use the function syntax. If you don’t need the error return value, just move it to a variable and ignore it. This allows you to use a single syntax and it reminds you that, at some point, you probably will need that error value.

See Also

Creating Active Server Pages


RequestClear Function

Syntax

RequestClear(sFileName,bClearAll)

What It Does

This function clears a DDO and all its parent DDOs. It calls the WBO function DoRequestClear, passing the name of the table to clear and a boolean indicating if a clear or clear-all should be executed. If clear-all is requested, all DDOs in the structure are cleared. If a clear is requested, the main DDO and all parents are cleared (unless a relates-to constraint exists between the tables, in which case the parent is not cleared)

This function requires that the form submitting the data has properly named input controls (e.g. name="Customer__Name") and a hidden RowId control (e.g. Name="Customer__RowId") for each DDO that will participate in the save.

If you pass the table name as a literal string, you must remember to put quotes around the string.

if Request("clear")<>"" then

Err = oCustomer.RequestClear("Customer",1)

end if

Upon completion of a clear, the DDs within the WBOs are cleared and you can query any field value using the DDValue message. It is never a good idea to assume that a DDO structure is cleared when you start processing an ASP page. You should always explicitly clear your DDO structures or find a record. This ensures that your DDOs are in a known state. Also, if your DD establishes default values for new records, a clear operation is required to set those defaults. For this reason, all wizard-generated entry screens contain the following code at the top of the processing script. This makes sure that a DDO is either cleared or loaded with a record.

See Also

DD Request Functions


RequestDDUpdate Function

Syntax

RequestDDUpdate(sFileName,bShowErrors)

What It Does

This function requests an update and a validation for the passed table and all its parent tables. This is used for two purposes: 1) It sets up the WBO so that it contains the current data from the submitting browser page, and 2) It performs a validation check on all DDO fields. This message is used to support multi-page data entry screens.

It calls the WBO event DoRequestDDUpdate passing the name of the table to update and the bShowErrors flag. Once called, the WBO controls the update and validation process. It will call the ASP page (actually the COM object) as needed to obtain Rowid and field data.

This function requires that the form submitting the data has properly named input controls (e.g. name="Customer__Name") and a hidden RowId control (e.g. Name="Customer__RowId") for each DDO that will participate in the save.

If you pass the table name as a literal string you must remember to put quotes around the string.

The update will be run through the DDOs, making sure that all appropriate updates and validations are performed. If an error or errors occur and bShowErrors is true (it is non zero), appropriate error messages will be displayed to the HTML Page and a non-zero value will be returned from the function.

if Request("validate")<>"" then

err = oCustomer.RequestDDUpdate("Customer",0) >

if Err = 0 then

Response.Write("<h4>Current data is Valid</h4>")

CurrentPage=1

Else

Response.Write("<h4>Current data is not valid</h4>")

oCustomer.call "msg_ReportAllErrors"

CurrentPage=2

end if

end if

Upon completion of an update, the DDOs will contain current updated data, and you can query the value of any field values using the DDValue message.

See Also

DD Request Functions


RequestDelete Function

Syntax

RequestDelete(sFileName)

What It Does

This function will attempt to delete the current record. It calls the WBO event DoRequestDelete, passing the name of the table to delete. Once called, the WBO controls the delete process. It will call the ASP page (actually the COM object) as needed to obtain a record. If an error occurs, this will return a non-zero value.

This function requires that the form submitting the data has a properly named hidden RowID control (e.g. Name="Customer__RowId") for the DDO that will delete the record.

If you pass the table name as a literal string, you must remember to put quotes around the string.

The delete will be run through the DDOs, making sure that all appropriate updates and validations are performed. If an error or errors occur, appropriate HTML error messages will be output to your browser, and a non-zero value will be returned from the function.

if Request("delete")<>"" then

Err = oCustomer.RequestDelete("Customer")

if err = 0 then

Response.Write("<h4>The record has been deleted.</h4>")

Else

Response.Write("<font color=""red"">")

Response.Write("<h4>The record could not be deleted.</h4>")

Response.Write("</font>")

end if

end if

Normally, any delete errors are displayed as part of the delete process. You can suppress these error messages by setting the WBO property pbReportErrors to False.

See Also

DD Request Functions


RequestFind Function

Syntax

RequestFind(sFileName, iIndexNum, iFindMode)

- or -

RequestFind(sFileName, sFieldName, iFindMode)

What It Does

This function performs a find using the passed information to determine the table name, index and find mode.

The first parameter determines which table is used for the find. If you pass the table name as a literal string, you must remember to put quotes around the string.

The second parameter determines the find index. If you pass a number, the function assumes that this is the index you wish to use for the find. If you pass a FieldName, the WBO will use the primary index for that field. If you pass the field name as a literal string, you must remember to put quotes around the string.

The iFindMode determines the mode for the operation. You can pass a mode constant or the integer value of this constant. Possible values are:

Find Mode | Integer Mode | Description
LT | 0 | Find Less than
LE | 1 | Find Less than or Equal to
EQ | 2 | Find Equal to
GE | 3 | Find Greater than or Equal to
GT | 4 | Find Greater than
NEXT_RECORD | 5 | Find next record in current find direction
FIRST_RECORD | 6 | Find the first record
LAST_RECORD | 7 | Find the last record

Note that the relative find modes (LT, LE, EQ, GE, GT) are based on the state of the DDOs after they have been updated. For example, if you are finding on Customer Name and you enter a value into the customer name input control, the find will be based relative to the value of that control. This is, of course, what you would expect a data entry input screen to do.

You can only use the mode constant values if you have included the file ddValue_Constants.inc in your ASP page. All wizard-generated code automatically includes this file in your ASP page. You would manually add this to a page with the following code:

<!-- #INCLUDE FILE="inc/ddValue_Constants.inc" -->

You must make sure that this file is included. If the file is not included, VbScript uses the value 0 for all constant names, thus making all modes LT. If you think this may be the case, you can easily test your value by adding the following code to your ASP page:

The value for GT is <%=GT%>

If it does not show "The value for GT is 4" in your browser, the include file is not being properly included.

RequestFind calls the WBO function DoRequestFind. Once called, the WBO controls the find process. It will call the ASP page (actually the COM object) as needed to obtain Rowid and field data.

This function requires that the form submitting the data has properly named input controls (e.g. name="Customer__Name") and a hidden RowId control (e.g. Name="Customer__RowId") for each DDO that will participate in the find.

If an error or errors occur, appropriate HTML error messages will be displayed to the browser and a non-zero value will be returned from the function.

' note we use the Index variable we created above

If Request("FindPrev") <> "" Then Err = oCustSample.RequestFind("Customer", Index, LT)

If Request("Find") <> "" Then Err = oCustSample.RequestFind("Customer", Index, GE)

If Request("FindNext") <> "" Then Err = oCustSample.RequestFind("Customer", Index, GT)

If Request("FindFirst") <> "" Then Err = oCustSample.RequestFind("Customer", Index, FIRST_RECORD)

If Request("FindLast") <> "" Then Err = oCustSample.RequestFind("Customer", Index, LAST_RECORD)

Normally, any find errors are displayed as part of the find process. You can suppress these error messages by setting the WBO property pbReportErrors to False.

See Also

DD Request Functions


RequestFindByRowId Function

Syntax

RequestFindByRowId(sFileName,RowId)

What It Does

This function finds the record for the passed table name and a serialized RowId string, finding all required parent records as well. It calls the WBO function DoRequestFindByRowId, passing the name of the table and RowId (a serialized representation of RowId) to find. This message requires no special formatting from the submitting form. All information required to find the record is passed as part of the function.

If you pass the table name as a literal string you must remember to put quotes around the string.

If the record is not found, a non-zero value is returned – no additional HTML output occurs.

RowId = request("RowId")

:

Err = oCustomer.RequestFindbyRowId( "Customer", RowId )

Upon completion of a successful find, the DDs within the WBOs are loaded with the newly found record, and you can query any field value using the DDValue message. If the find fails, your DDOs will be cleared.

This message is often used to find a RowId that is passed as part of a QueryString. All the wizard-generated ASP pages support a protocol where a RowId for the page’s main table will be found if it is passed with a query string format of RowId=SerializedRowId. The following ASP code supports this:

If request("Request_method")="GET" Then

' if a GET see if a querystring Customer RowId was passed. If it was

' we should find this record, else just clear the DDO

RowId = request("RowId")

If RowId <> "" Then

' this message is understood by the WebBusinessProcess class

Err = oCustomer.RequestFindbyRowId( "Customer", RowId )

Else

Err = oCustomer.RequestClear("Customer",1)

End If

End if

If the above sample was part of the Customer.Asp file, we could call the page and load a record by passing it the following URL string:

http://localhost/Order_Entry_12/Customer.asp?RowId=02000000

This technique is used extensively to create links between reports and entry pages.

See Also

DD Request Functions


RequestSave Function

Syntax

RequestSave(sFileName)

What It Does

This function requests a save for the passed table and all its parent tables. This calls the WBO event DoRequestSave, passing the name of the table to save. Once called, the WBO controls the save process. It will call the ASP page (actually the COM object) as needed to obtain RowId and field data.

This function requires that the form submitting the data has properly named input controls (e.g. name="Customer__Name") and a hidden RowId control (e.g. Name="Customer__RowId") for each DDO that will participate in the save.

If you pass the table name as a literal string, you must remember to put quotes around the string.

The save will be run through the DDOs making sure that all appropriate updates and validations are performed. If an error or errors occur, appropriate HTML error messages will be output to your browser and a non-zero value will be returned from the function.

if Request("save")<>"" then

err = oCustomer.RequestSave("Customer")

if err = 0 then

Response.Write("<h4>Customer record saved</h4>")

Else

Response.Write("<font color=""red"">")

Response.Write("<h4>Could not save changes. Errors Occurred</h4>")

Response.Write("</font>")

end if

end if

Normally, any save errors are displayed as part of the save process. You can suppress these error messages by setting the WBO property pbReportErrors to False. This property can be changed within your ASP script code as shown here.

if Request("save")<>"" then

oCustomer.call "set_pbReportErrors", 0

err = oCustomer.RequestSave("Customer")

if err = 0 then

Response.Write("<h4>Customer record saved</h4>")

Else

Response.Write("<font color=""red"">")

Response.Write(<h4>Could not save changes. Errors Occurred</h4>")

Response.Write("</font>")

end if

oCustomer.call "set_pbReportErrors", 1

end if

Upon completion of a save, the newly saved record will be loaded into the DDOs within the WBOs and you can then query any field values using the DDValue message. If you wish to clear the DDOs after a save, you should set the WBO property pbClearAfterSave to True.

See Also

DD Request Functions


DDValue Function

If you look at any of the samples or any programs generated by the wizards you will see that the function DDValue is used in all data entry screens. Normally you will see it in the following format:

<td align="right"><em>Customer</em></td>

<td><input type="text" size="13" name="Customer__Name"

Value="<%=CustWebPage.DDValue("Customer.Name")%>">

</td>

When the ASP file is being processed, the function DDValue will be called. This function will be directed to the DataFlex WBO object, where it finds the data dictionary for Customer.Name, retrieve its current value and return this value to ASP. When the HTML is output to the web page, <%=CustWebPage.DDValue("Customer.Name")%> will be replaced with that returned value. If the value of Customer.Name were "John Smith", the resulting HTML output would be:

<td align="right"><em>Customer</em></td>

<td><input type="text" size="13" name="Customer__Name"

Value="John Smith">

</td>

The DDValue function does not have to be used inside a control. This function can be used anywhere within your ASP page. It can be used to generate direct HTML output or it can be used within server side scripts. For example, your ASP page contains the following code:

The current customer name is: <%=CustWebPage.DDValue("Customer.Name")%><br>

This would result in the following HTML line:

The current customer name is: John Smith

Alternatively, you could use this function as part of your ASP server side scripting language:

<% ' Move customer name to a VBScript variable

CustNm = CustWebPage.DDValue("Customer.Name")

' Uppercase the name

CustNm = Ucase(CustNm)

%>

The current customer name is: <%=CustNm%>

This would result in the following HTML line:

The current customer name is: JOHN SMITH

Here is an example of using DDValue for non-display purposes. When building your ASP page, you may want to know whether you are editing or creating a new record. If you are adding a new record, you may choose not to display the delete button in your HTML form. After your have processed your posted information in your ASP file you would add the following code:

<% OldInvt = MyInvtWBO.ddvalue("Invt.RowId") %>

Later, in your ASP file, when you create your buttons you could add the following code:

<p>

<input type="submit" name="clear" value="Clear">

<% If LoginRights = "1" then %>

<input type="submit" name="save" value="Save">

<% If OldInvt<>"" then ' only allow delete if a record exists %>

<input type="submit" name="delete" value="Delete">

<% End if %>

</p>

When the RowId option is used, the value returned will be a serialized string value of the record’s RowId so that it can be represented in an HTML page. Most of the WebApp interfaces, such as RequestFindbyRowId, always expect that any RowId parameter will be a serialized version of RowId. The WBO packages will perform the conversions for you automatically. In the case of custom interfaces such as reports, you will need to perform this serialization yourself using the SerializeRowId() and DeserializeRowId() functions. If the returned value is blank, the RowId is null.

The DDValue function actually passes three parameters; file/field string name, option integer, and extra string parameter. When you call the function with a single parameter the remaining two parameters are passed automatically as 0 and " ". Therefore, the above example could be re-coded as follows:

<td align="right">

<em>Customer</em>

</td>

<td>

<input type="text" size="13" name="Customer__Name"

Value="<%=CustWebPage.DDValue("Customer.Name",0,"")%>">

</td>

DDValue Options

The option parameter and the extra string parameter can be used to pass additional information to WBO object. For example, if a "1" were passed as the option instead of a "0", DataFlex could use that to return some other data dictionary value for that file and field – perhaps the field’s label. The current cWebBusinessProcess class does not support this. It only understands the "0" option and it always returns the field’s current value. The class was constructed to easily allow for a sub class to be created that could process different option values. We will be doing that when we create a cWebBusinessProcess sub-class.

The DDValue function is most often used in ASP code. Some functionality of the DDValue function can also be used in Visual DataFlex code inside a WebBusinessProcess (WBO). For more information on this functionality, please see the cWebBusinessProcess Class

DataDictionary Information Options

These options return data dictionary field information. This information can be used within HTML input controls, within HTML general text, or within server side scripts. Some of these are of limited use but are provided to give an ASP file complete access to a field’s DD values.

Options 0-99 for DataDictionary field information values:

# | Option | Return Value
0 | DDCRNTVALUE | Field_Current_Value
1 | DDDESC | Field_Current_Description
2 | DDLONGLABEL | Field_Label DDLONGLABEL
3 | DDSHORTLABEL | Field_Label DDSHORTLABEL
4 | DDTAGLABEL | Field_Label DDTAGLABEL
5 | DDSTHELP | Status_Help
6 | DDOPT | File_Field_options (w/ foreign support)
7 | DDVALNUM | Number of val-table items
8 | DDVALDATA | Data value for val-table [pass index]
9 | DDVALDESC | Desc value for val-table [pass index]

HTML Helper Strings Options

These options return strings that are formatted to assist in the construction of HTML controls. These can be used to create controls whose data and appearance can be manipulated at runtime as opposed to design time. These should be used with care because they can be processing intensive. To be able to create controls that are completely dynamic, refer to the next set of options (HTML Controls Options).

Options 100-199 for HTML specific "helper":

# | Option | Return Value
103 | DDSEL | returns "Selected" if field matches passed value
104 | DDCHCK | returns "checked" if field matches passed value
105 | DDOPTION | returns the <option....> value
106 | DDREADONLY | returns "ReaddOnly" if RO
108 | DDTITLE | returns Title="status help" or blank if none.
109 | DDFIELDERROR | returns error string for field (if error exists, else blank)
110 | DDSHORTFIELDERROR | returns short error string (good for WML)
111 | DDROWIDS | returns <option...> for all RowIds

HTML Control Options

These options are used to create completely dynamic HTML controls. All of the data for the controls are acquired from the data dictionaries. Options exist for creating Input forms, combo forms, radios, multi-line edits and parent combos. In addition, an option exists that instructs VDF to create the most appropriate field for the passed field.

While the advantages of such options should be obvious, there are some drawbacks that you should recognize. If the control is created dynamically, you will not be able to see these controls when you use visual HTML design tools such as FrontPage. In addition, dynamically created controls may not give you the control you need when designing a web page. Finally, there may be processing overhead involved in creating dynamic controls at runtime that may need to incur (this overhead should be quite small).

These automatic controls retrieve all the information needed to create the form. The name of the control will be generated automatically (e.g., Name=”Customer__Name”). If the field is a DisplayOnly field, the HTML ReadOnly attribute will be set. The field’s status help will be set as a Title attribute. If a field validation error occurred during a save, the error message will also be appended to the title attribute. Note: Not all browsers support ReadOnly and Attribute. If they do not, these are ignored.

Below is an example of how a field’s label and input form can be created dynamically. Note that the label has been set so that it will print in red if the field has a validation error associated with it.

<td align="right">

<em><%=WBO.ddValue("Customer.Name",DDSHORTLABEL,1)%></em>

</td>

<td>

<%=WBO.ddValue("Customer.Name",DDAUTO)%>

</td>

Options 200-299 for HTML control:

# | Option | Return Value
200 | DDFORM | create a single line edit
201 | DDEDIT | create a multi line edit
202 | DDRADIO | create radios for field
203 | DDCOMBO | create a single line list (combo) for val-table
204 | DDPARENTCOMBO | create a single line list of all records
205 | DDAUTO | create the best control type for field
250 | DDWMLINPUT | create WML Input control

See Also

Creating Active Server Pages


DDAUTO

DDAUTO (Option 205)

Syntax

<%=WBO.ddValue("FileName.FieldName",DDAUTO)%>"

or

<%=WBO.ddValue("FileName.FieldName",DDAUTO,Length)%>"

What It Does

This creates the most appropriate control for the passed file/field. If a length parameter is passed it will be used (if the chosen control type supports the setting of a length). This can be used to create form, radios, edits or combos.

<td><%=WBO.ddValue("Customer.Foo",DDAUTO)%> </td>

See Also

DDValue Function


DDCHCK

DDCHCK (Option 104)

Syntax

WBO.ddValue("FileName.FieldName",DDCHCK,FieldValue)

What It Does

The passed FieldValue is compared to the field’s current value. If they are the same the string “checked” is returned. This can be used by radio controls to properly set the selected field value.

<td>

<input TYPE="radio" NAME="Pers0100__Status" VALUE="A"

<%=WBO.ddValue("pers0100.status",DDCHCK,"A")%>">Active

<input TYPE="radio" NAME="Pers0100__Status" VALUE="I"

<%=WBO.ddValue("pers0100.status",DDCHCK,"I")%>">Inactive

</td>

See Also

DDValue Function


DDCOMBO

DDCOMBO (Option 203)

Syntax

<%=WBO.ddValue("FileName.FieldName",DDCOMBO)%>"

What It Does

This creates a select control (combo form). It is assumed that this control will be used with a validation table field type. The number of combo options and the description and value of these options are determined at runtime when the control is created.

<td><%=WBO.ddValue("Customer.State",DDCOMBO)%> </td>

See Also

DDValue Function


DDCRNTVALUE

DDCRNTVALUE (Option 0)

Syntax

WBO.ddValue("FileName.FieldName")

Or

WBO.ddValue("FileName.FieldName",DDCRNTVALUE)

What It Does

This returns the current DD value for the passed file and field. Since this is the default option value for this function, the DDCRNTVALUE symbol is optional.

<td align="right">

<em>Customer</em>

</td>

<td>

<input type="text" size="13" name="Customer__Name"

Value="<%=WBO.ddValue("Customer.Name")%>">

</td>

See Also

DDValue Function


DDDESC

DDDESC (Option 1)

Syntax

WBO.ddValue("FileName.FieldName",DDDESC)

What It Does

This returns the current DD description value for the passed file and field. This would be used when you wish to return the validation table description associated with the current field value. If the field does not have a validation table associated with it, the field’s current value will be returned.

Shipping Code is <%=WBO.ddValue("OrderHea.Ship_Via")%><hr>

Shipping Description is <%=WBO.ddValue("OrderHea.Ship_Via",DDDESC)%><hr>

See Also

DDValue Function


DDEDIT

DDEDIT (Option 201)

Syntax

<%=WBO.ddValue("FileName.FieldName",DDEDIT)%>"

or

<%=WBO.ddValue("FileName.FieldName",DDEDIT, "Length ")%>"

or

<%=WBO.ddValue("FileName.FieldName",DDEDIT, "Length,Rows")%>"

What It Does

This creates a multi-line edit form for the passed file/field. If a third parameter is not passed the form’s width will be 40 with 5 rows. If a length is passed (note it should be within quotes), the form will be set to the passed length with 5 rows. If a length and width (note that they must be within quotes) the length and number of rows will be determined by this value.

<td><%=WBO.ddValue("Customer.text",DDEDIT)%> </td>

<td><%=WBO.ddValue("Customer.text",DDEDIT, "20,10")%> </td>

See Also

DDValue Function


DDFIELDERROR

DDFIELDERROR (Option 109)

Syntax

WBO.ddValue("FileName.FieldName",DDFIELDERROR)

What It Does

After a save or validation process the WBO keeps track of all errors reported for each field. This function returns an error message for the field, if an error exists. If no validation error occurred, the return string will be blank. You can test if a field has an error by testing for an empty string.

<%

FieldError=Customer_WBO.DDValue("Customer.name",DDFIELDERROR)

If FieldError="" then

Response.write("No Error occurred")

Else

Response.Write("Field Error: " & FieldError)

End if

%>

You can use this to display context error messages in your ASP pages.

<td align="right"><strong>Customer Name</strong>

<td><%=Customer_WBO.ddValue("Customer.name",DDAUTO)%></td>

<%FieldError=Customer_WBO.ddValue("Customer.name",DDFIELDERROR)%>

<%If FieldError<>"" then%>

<td><font color="red"><%=FieldError%></font></td>

<%end if%>

See Also

DDValue Function


DDFORM

DDFORM (Option 200)

Syntax

<%=WBO.ddValue("FileName.FieldName",DDFORM)%>"

or

<%=WBO.ddValue("FileName.FieldName",DDFORM,Length)%>"

What It Does

This creates an Input form for the passed file/field. If a length is passed, the form will be set to the passed length. If a length is not passed, the length is determined by the length of the data field (with a minimum of 4 and a maximum of 40).

<td><%=WBO.ddValue("Customer.Name",DDFORM)%> </td>

<td><%=WBO.ddValue("Customer.Name",DDFORM,20)%> </td>

See Also

DDValue Function


DDLONGLABEL

DDLONGLABEL (Option 2)

Syntax

WBO.ddValue("FileName.FieldName",DDLONGLABEL)

or

WBO.ddValue("FileName.FieldName",DDLONGLABEL,ErrorMode)

What It Does

This returns the field’s long label as defined within your data dictionary.

<td align="right">

<em><%=WBO.ddValue("Customer.Name",DDLONGLABEL)%></em>

</td>

<td>

<input type="text" size="13" name="Customer__Name"

Value="<%=WBO.ddValue("Customer.Name")%>">

</td>

If a third parameter ErrorMode is passed, the label can be used to report save field-validation error information. If ErrorMode is 1 and a field validation error occurred during a save, the field label will be displayed in red. If ErrorMode is 2 and a field validation error occurred during a save, the field label will be displayed in red and the validation error message will be displayed below the label.

<td align="right">

<em><%=WBO.ddValue("Customer.Name",DDLONGLABEL,2)%></em>

</td>

<td>

<input type="text" size="13" name="Customer__Name"

Value="<%=WBO.ddValue("Customer.Name")%>">

</td>

See Also

DDValue Function


DDOPT

DDOPT (Option 6)

Syntax

WBO.ddValue("FileName.FieldName",DDOPT)

What It Does

This returns the field’s field option string. This is a bit packed string of all DD Field options - regular or foreign field options will be returned as appropriate.

<% CNameOpts = WBO.ddValue("Customer.Name",DDOPT)%>

See Also

DDValue Function


DDOPTION

DDOPTION (Option 105)

Syntax

WBO.ddValue("FileName.FieldName",DDOPTION)

What It Does

This creates all the options (items) in a Select (combobox) control. All option items are properly formatted and the current value is selected. This can be used to allow you to create combo boxes whose options are generated at runtime.

<td>

<select SIZE="1" NAME="pers0100__state">

<%=DDValue(pers0100.state,DDOPTION) %>

</select>

</td>

See Also

DDValue Function


DDPARENTCOMBO

DDPARENTCOMBO (Option 204)

Syntax

<%=WBO.ddValue("FileName.FieldName",DDPARENTCOMBO)%>"

What It Does

This creates a Select control (combo form) where each item is a record from the table. This can be used to create combo forms that contain all available records from a parent table. Because these items are loaded at runtime, you do not want to use this if your parent table has too many records.

This allows a user to make a parent selection without needing to post the information to the server to determine if the record exists.

The passed file/field determines what field value should be displayed from each parent record. This value is displayed but it is not passed back to the Visual DataFlex WBO – the selected RowId will be returned. If you use this control, you must make sure that you have not included another RowId control for this table. Normally, the web wizard will create a hidden RowId control for every table in the DDO structure. You must find and remove this field.

<td><%=WBO.ddValue("Vendor.Name",DDPARENTCOMBO)%> </td>

See Also

DDValue Function


DDRADIO

DDRADIO (Option 202)

Syntax

<%=WBO.ddValue("FileName.FieldName",DDRADIO)%>"

or

<%=WBO.ddValue("FileName.FieldName",DDRADIO,"aString|bString")%>"

What It Does

This creates a group of radio buttons to represent the passed file/field. It is assumed that this control will be used with a checkbox or validation table field type and, by default, the number of radio buttons and radio labels will be determined by the data dictionary. If the radio is created based on a validation table it uses the validation description field as the description for each radio item. If the radio is based on a checkbox (which is how we handle checkbox items in html) the description is the value of the true and false value for the table field. To allow more flexibility, you can pass an optional parameter string to specify the value for each radio. Each item is separated by the "|" symbol. This is optional, and if not passed the defaults apply.

<%=WBO.ddValue("Customer.Status",DDRADIO,"Yes|No")%> </td>

See Also

DDValue Function


DDREADONLY

DDREADONLY (Option 106)

Syntax

WBO.ddValue("FileName.FieldName",DDREADONLY)

What It Does

If the current field is read-only, a string value of "ReadOnly" will be returned. Regular and foreign field options are used, as appropriate, to determine if a field is read only. The ReadOnly HTML attribute is part of the HTML4 specification and it not currently supported by all browsers.

<td align="right">

<em>Customer</em>

</td>

<td>

<input type="text" size="13" name="Customer__Name"

<%WBO.ddValue("Customer.Name",DDREADONLY)%>

Value="<%=WBO.ddValue("Customer.Name")%>">

</td>

See Also

DDValue Function


DDROWIDS

DDROWIDS (Option 111)

Syntax

WBO.ddValue("FileName.FieldName",DDROWIDS)

What It Does

This is used to create option line (items) for a parent combo control, which is an experimental data entry control. This control is used for parent tables where the number of records in the table are small enough to warrant reading them all in when the web page is created. For each record in the table, an option line is created consisting of the value of the passed file/field. As the description and the RowId for the data value (the value that is passed back during a POST operation). The user will select the parent table by some field value and then the selected RowId is passed back to the DataFlex WBO. To use this you must name the select control with the parent RowId field. In addition, you must make sure that you remove the existing parent RowId field, which may already exist as a hidden field.

<td>

<select SIZE="1" NAME="pers0100__rowid">

<%=WBO.ddValue(pers0100.state,DDROWIDS) %>

</select>

</td>

See Also

DDValue Function


DDSEL

DDSEL (Option 103)

Syntax

WBO.ddValue("FileName.FieldName",DDSEL,FieldValue)

What It Does

The passed FieldValue is compared to the field’s current value. If they are the same the string “selected” is returned. This can be used by Select controls (comboboxes) to properly set the selected field value.

<td>

<select SIZE="1" NAME="pers0100__state">

<option value="CA" <%=WBO.ddValue("pers0100.state",DDSEL,"CA")%>"Calif" </option>

<option value="AZ" <%=WBO.ddValue("pers0100.state",DDSEL,"AZ")%> "Ariz" </option>

<option value="OR" <%=WBO.ddValue("pers0100.state",DDSEL,"OR")%> "Oregon" </option>

<option value="FL" <%=WBO.ddValue("pers0100.state",DDSEL,"FL")%> "Florida" </option>

</select>

</td>

See Also

DDValue Function


DDSHORTFIELDERROR

DDSHORTFIELDERROR (Option 110)

Syntax

WBO.ddValue("FileName.FieldName",DDFIELDERROR)

What It Does

This is a shorter version of DDFIELDERROR, specifically for use with WML. After a save or validation process the WBO keeps track of all errors reported for each field. This function returns an error message for the field, if an error exists. If no validation error occurred, the return string will be blank. You can test if a field has an error by testing for an empty string.

<%

FieldError=Customer_WBO.DDValue("Customer.name",DDSHORTFIELDERROR)

If FieldError="" then

Response.write("No Error occurred")

Else

Response.Write("Field Error:" & FieldError)

End if

%>

You can use this to display context error messages in your WML pages.

<td align="right"><strong>Customer Name</strong></td>

<td><%=Customer_WBO.ddValue("Customer.name",DDAUTO)%></td>

<%FieldError= Customer_WBO.ddValue("Customer.name",DDSHORTFIELDERROR)%>

<%If FieldError<>"" then%>

<td><font color="red"><%=FieldError%></font></td>

<%end if%>

See Also

DDValue Function


DDSHORTLABEL

DDSHORTLABEL (Option 3)

Syntax

WBO.ddValue("FileName.FieldName",DDSHORTLABEL)

or

WBO.ddValue("FileName.FieldName",DDSHORTLABEL,ErrorMode)

What It Does

This returns the field’s short label as defined within your data dictionary.

<td align="right">

<em><%=WBO.ddValue("Customer.Name",DDSHORTLABEL)%></em>

</td>

<td>

<input type="text" size="13" name="Customer__Name"

Value="<%=WBO.ddValue("Customer.Name")%>">

</td>

If a third parameter ErrorMode is passed, the label can be used to report save field-validation error information. If ErrorMode is 1 and a field validation error occurred during a save, the field label will be displayed in red. If ErrorMode is 2 and a field validation error occurred during a save, the field label will be displayed in red and the validation error message will be displayed below the label.

<td align="right">

<em><%=WBO.ddValue("Customer.Name",DDLONGLABEL,2)%></em>

</td>

<td>

<input type="text" size="13" name="Customer__Name"

Value="<%=WBO.ddValue("Customer.Name")%>">

</td>

See DDLONGLABEL for a description of ErrorMode.

See Also

DDValue Function


DDSTHELP

DDSTHELP (Option 5)

Syntax

WBO.ddValue("FileName.FieldName",DDSTHELP)

What It Does

This returns the field’s status help as defined within the data dictionary.

<td align="right">

<em><%=WBO.ddValue("Customer.Name",DDLONGLABEL,2)%></em>

</td>

<td>

<input type="text" size="13" name="Customer__Name"

Value="<%=WBO.ddValue("Customer.Name")%>">

</td>

<td>

<small><%=WBO.ddValue("Customer.Name",DDSTHELP)%>"></small>

</td>

If a third parameter of "1" is passed, field error information is also returned. If the last save operation resulted in a validation error for the field, the error will also be returned along with status help.

<td><small>

<%=WBO.ddValue("Customer.Name",DDSTHELP,"1")%>">

</small></td>

See Also

DDValue Function


DDTAGLABEL

DDTAGLABEL (Option 4)

Syntax

WBO.ddValue("FileName.FieldName",DDTAGLABEL)

or

WBO.ddValue("FileName.FieldName",DDTAGLABEL,ErrorMode)

What It Does

This returns the field’s tag label as defined within the table’s .tag file.

<td align="right">

<em><%=WBO.ddValue("Customer.Name",DDSHORTLABEL)%></em>

</td>

<td>

<input type="text" size="13" name="Customer__Name"

Value="<%=WBO.ddValue("Customer.Name")%>">

</td>

If a third parameter ErrorMode is passed, the label can be used to report save field-validation error information. If ErrorMode is 1 and a field validation error occurred during a save, the field label will be displayed in red. If ErrorMode is 2 and a field validation error occurred during a save, the field label will be displayed in red and the validation error message will be displayed below the label.

<td align="right">

<em><%=WBO.ddValue("Customer.Name",DDTAGLABEL,2)%></em>

</td>

<td>

<input type="text" size="13" name="Customer__Name"

Value="<%=WBO.ddValue("Customer.Name")%>">

</td>

See DDLONGLABEL for a description of ErrorMode.

See Also

DDValue Function


DDTITLE

DDTITLE (Option 108)

Syntax

WBO.ddValue("FileName.FieldName",DDTITLE)

What It Does

This returns a Title string consisting of the keyword “Title=” plus the field’s status help. If a field validation error occurred during a save, the validation error will also be added to the title text. The Title attribute is a loosely defined HTML attribute that can be added to any input control. Some browsers (MS/IE4) use this to present popup tool-tips when the cursor is moved over the field. Other browsers ignore this attribute.

<td align="right">

<em>Customer</em>

</td>

<td>

<input type="text" size="13" name="Customer__Name"

<%WBO.ddValue("Customer.Name",DDTITLE)%>

Value="<%=WBO.ddValue("Customer.Name")%>">

</td>

See Also

DDValue Function


DDVALDATA

DDVALDATA (Option 8)

Syntax

WBO.ddValue("FileName.FieldName",DDVALDATA,Item)

What It Does

This returns the validation table data value for item in the associated DD field. This can be used with DDVALNUM and DDVALDESC to return information about a field’s validation table. See DDVALNUM.

See Also

DDValue Function


DDVALDESC

DDVALDESC (Option 9)

Syntax

WBO.ddValue("FileName.FieldName",DDVALDESC,Item)

What It Does

This returns the validation table description value for the item in the associated DD field. This can be used with DDVALNUM and DDVALDATA to return information about a field’s validation table. See DDVALNUM.

See Also

DDValue Function


DDVALNUM

DDVALNUM (Option 7)

Syntax

WBO.ddValue("FileName.FieldName",DDVALNUM)

What It Does

This returns the number of validation items associated with the DD field. This can be used with DDVALDATA and DDVALDESC to return information about a field’s validation table.

<%

NumOpts = WBO.ddValue("OrderHea.ShipVia",DDVALNUM)

For Opt = 1 to NumOpts

ValData = WBO.ddValue("OrderHea.ShipVia",DDVALDATA,Opt)

ValDesc = WBO.ddValue("OrderHea.ShipVia",DDVALDESC,Opt)

Response.Write ("Data" & ValData & " Desc" & ValDesc)

Next

%>

See Also

DDValue Function


ddwmlinput

DDWMLINPUT (Option 250)

Syntax

<%=WBO.ddValue("FileName.FieldName",DDWMLINPUT)%>"

What It Does

This creates a WML Input form for the passed file/field.

<td><%=WBO.ddValue("Customer.Name",DDWMLINPUT)%> </td>

Example

<%FieldError=oCustomer.ddValue("Customer.Status",DDSHORTFIELDERROR) %>

<b>Status:</b>

<% If FieldError<>"" then %>

<i>(<%=FieldError%>)</i>

<% end if %>

<%=oCustomer.ddValue("Customer.Status",DDWMLINPUT,"A")%>

See Also

DDValue Function


Call Function

The ASP COM/WBO function, Call can be used to send any message to your DataFlex WBO object. You can use this to set properties, execute functions, or call procedures. Note: Call functions must be published in the Web Browser Object.

For example, your ASP code may contain the following line:

<% CustWebPage.Call "set_pbVerboseErrors", 1 %>

This sets the pbVerboseErrors property of your DataFlex WBO to 1 (true). This would be the same as creating the following code in your DataFlex program:

Set pbVerboseErrors to True

Setting this property to "True" results in more detailed error messages (the line number and error number are returned with the error). Developers may wish to set this property to true when debugging their web application. You do not need to set this property in your WBO, which would require you to recompile your program. Instead, you can set it in your ASP file by using the Call function.

You can also use the Call message to retrieve information from your DataFlex program. For example, you may want to know the value of pbClearAfterSave to determine how your web page will be displayed:

<% If CustWebPage.Call("get_pbClearAfterSave_State")=1 then %>

<b>After a successful save the new record will be cleared</b>

<% End If %>

or

<% pbClearAfterSave = CustWebPage.Call("get_pbClearAfterSave_state") %>

<% If pbClearAfterSave=1 then %>

<b>After a successful save the new record will be cleared</b>

<% End If %>

Therefore, you can use Call to access any message (property, function, procedure, procedure set) that your VDF WBO understands.

See Also

Creating Active Server Pages


Commonly Called Functions

Several additional methods have been added to the cWebBusinessProcess class. These were designed to be accessed from an ASP file and will be documented from that perspective. These methods are all functions. When called within VBScript (or JScript), you can choose to call these functions as functions (with a return value) or as procedures (in which case the return value is not returned). The syntax samples below show both methods.

Note: VBScript has an inconsistent syntax for calling functions and procedures. One requires parenthesis and the other does not.

As a Procedure

WBO.MyProcess "Customer"

As a Function

MyVar=WBO.MyProcess("Customer")

AutoEntry

This function creates a label and an input control for each field in the passed table name. Controls are not created for overlap and binary fields. The control type is determined by the DD’s field information. A hidden RowId field is also created. The controls are written out in HTML format using the WriteHtml message.

Refer to AutoEntry for more information.

AutoReport

AutoReport generates a report for the passed tablename, using the passed index with support for hypertext links to another web page. All fields in a table (except overlap and binary) are displayed as a single row in a table.

See AutoReport for more information.

CreateFindIndexCombo

This is a specialized function, that creates a control that lists all available indexes for a table. Each field in the passed table name is checked. If it has an associated index and the field is not an overlap field, the field is added to the combo list. The name to be used by the HTML control is passed. The DefaultField is the name of the field to be set as the default index.

This control is used by the WebAppSample to allow users to select a find and list index. Refer to the sample to see how this is used. This code segment creates the find buttons (<<, <, =, >, >>), list button and the find index combo control.

Refer to CreateFindindexCombo for more information.

See Also

Call Function


Creating Custom Interfaces

You simply create the property, procedure or function within your DataFlex WBO. You can then access it from your ASP file.

For example, we may want to know if a child table (such as INVT) is constrained to its parent (VENDOR). We could access this by getting the Constrain_File property of the INVT data dictionary. The problem is that Call only queries the WBO object, and not its children. To support this, we must add the following custom function to the WBO object:

//VDF Code added to the WBO:

{ Published = True }

Function InvtConstrained returns integer

Integer iFile

Get Constrain_File of Invt_DD to iFile

Function_Return iFile // returns non-zero if constrained

End_Function

This could now be accessed within your ASP file as follows:

//Script Code added to the .ASP file:

<% bConstrained = InvtWBO.Call("get_InvtConstrained")%>

Changing the Constraints within your ASP File

//VDF Code added to the WBO:

{ Published = True }

Procedure Set ConstrainInvt Integer iFile

Handle hDD

Move Invt_DD to hDD

Set Constrain_File of hDD to iFile

Send Rebuild_Constraints of hDD to hDD

End_procedure

This could now be accessed within your ASP file as follows:

//Script Code added to the .ASP file:

<% oInvtWBO.Call "set_ConstrainInvt", 1 %>

See Also

Call Function


Conversion Functions

Active Server Pages support methods that allow you to retrieve posted data and send data in Binary format. Those methods are:

Request.BinaryRead(BytesToRead)

and

Response.BinaryWrite(BinaryTextToWrite)

In both cases, the binary characters that are read or written are in a format that DataFlex cannot deal with directly. Before the data is passed to or from a WBO you need to convert the data to or from a format that DataFlex can handle.

The functions...

UTF8ToString

and

StringToUTF8

are provided for this purpose.

See Also

Creating Active Server Pages


UTF8ToString Function

Syntax

<% sData = WBO.UTF8ToString(UTF8Data) %>

What It Does

This function converts data read with the BinaryRead function into a format that can be passed to your WBO as a string. The BinaryRead function is used most often when your ASP page has been sent data encoded as XML and you need to be send this XML data to your WBO. Your ASP code would look something like this:

<% '

' If Passed data is xml, retrieve the XML data and send it to the WBO

'

dim sStr

sCType=request.ServerVariables("CONTENT_TYPE")

If (sCType="text/xml") then

' We need to Read the XML data and convert it to a string that can be passed to the WBO

iCount = Request.TotalBytes ' number of posted bytes

sStr = Request.BinaryRead(iCount) ' Read the data and then

sStr = oMyWBO.UTF8ToString(sStr) ' convert to usable format

' response.write(sStr) ' good for debugging to see what was passed.

sNew = oMyWBO.call("get_ProcessXML",sStr)

end if

%>

There is no WBO equivalent of this function as it is only needed on the ASP page. All ComWBO objects understand this helper function.

Special Note

This method of posting XML is rendered obsolete in favor of using Web Services, and is only supported for compatibility with existing application. New Web Applications should be using Web Services instead.

See Also

Conversion Functions


StringToUTF8 Function

Syntax

<% UTF8Data = WBO.StringToUTF8(sData) %>

What It Does

If you are sending WBO string data to a client using the BinaryWrite function you will first want to convert this into UTF8 format. The StringToUTF8 helper function is provided to allow you do do this. It would be used as follows:

<% '

sStr = oMyWBO.call("get_XML") ' Assume this returns data from the WBO

sStr = oMyWBO.StringToUTF8(sStr) ' We need to convert this to UTF8 format and then

Response.BinaryWrite(sStr) ' write it using BinaryWrite

%>

There is no WBO equivalent of this function as it is only needed on the ASP page. All ComWBO objects understand this helper function.

Special Note

This method of posting XML is rendered obsolete in favor of using Web Services, and is only supported for compatibility with existing application. New Web Applications should be using Web Services instead.

See Also

Conversion Functions


WBO Object Name Substitution

When you create web views you must create a DataFlex WBO object and a COM WBO. The DataFlex object is created within your VDF web-view and the COM object is created within Global.asa. By default, the two objects have the same name. For example, they may be named CustomerEntryWebView or MyInvtWBO. It is expected that your ASP file will refer to this object by its name. For example:

<%=CustomerEntryWebView.DDValue("Customer.Name")%>

Usually only one COM/WBO will be accessed within an ASP file. Because many of the samples in WebAppSample are hand coded, we want to cut and paste common code across ASP files. We can name substitution within each ASP where the WBO name can be replaced with the name "WBO." This is at the top of each ASP file with a line of code that is similar to the following:

<% set WBO = CustomerEntryWebView %>

Once created, the CustomerEntryWebView can be accessed with the name WBO.

<%=WBO.DDValue("Customer.Name")%>

When we create a different ASP file, which accesses a different WBO, (e.g., MyInvt_Web_WBO), we will add the following line of code to the ASP file.

<% set WBO = MyInvt_Web_WBO %>

Once created, we will access it using the name WBO.

<%=WBO.DDValue("Invt.ID")%>

See Also

Creating Active Server Pages


Error Handling Messages

An Error may be Expected or Unexpected

An Expected error is an error that occurs when the user attempts to do something that is invalid. These errors must be reported back to your user. For example, the user may have attempted to save a record that has validation errors, or a user may have attempted to delete a record that can not be deleted. In such a case, the user must be notified of this error so they can make corrections.

As the developer, you are probably not interested in knowing that these types of errors occurred. They are expected, controlled by your program and can be corrected by the user.

An Unexpected error is an error that occurs when something goes wrong with your program or your server. Most often, these are program bugs. Ideally, your users will never see these errors. When they do, these errors tend to be meaningless to them since there is nothing that they can do to correct the problem. In such a case, the developer will want to see this error.

You would like to see it when it occurs and you may want to see a history of these errors. These errors are not controlled and must be corrected by the developer.

Errors can be Queued or Non-queued

If an error is Queued, it is not immediately displayed to the user. Instead, it is added to a queue of errors. Normally, all of these errors will be reported back to the user at one time. For example, a save request might generate numerous errors during field validation.

When errors are queued, these errors are not reported back to the user as they occur. They are stored in an error queue and are then all reported back to the user at one time. All of the automatic WBO "request" processes (DoRequestSave, DoRequestDelete, DoRequestFind and DoRequestClear) use queued error messages. Normally, these types of errors are expected errors.

If an error is non-queued, it is immediately reported back to the user when the error occurs. Normally, these types of errors are bugs in your program.

When we talk about "reporting the error," we are referring to the process of generating the errors within an HTML page and displaying that error information within a browser. There are actually three places where errors can be reported, the web browser, the web application event log, and the Visual DataFlex application itself. Depending on the task mode (i.e., debugging) and the type of error (expected or unexpected) errors should be displayed to some or all of these error locations.

By default, the error reporting system will "just try to do the right thing." It does this by making the following assumptions:

  • Queued errors are expected.
  • Non queued errors are unexpected.
  • Expected errors should be reported back to the user as part of a controlled queue error handling process. Normally, there is no need to log an expected error in the event log.
  • Unexpected errors should be logged to the web application event log and immediately reported back to the user. In best case scenarios, unexpected errors only occur during debugging so the "user" will be the developer.
  • Normally, a program runs in non-queued mode. Errors that occur while in this mode are unexpected.
  • During the operations, where errors are expected (DoRequestSave, DoRequestDelete, DoRequestClear and DoRequestFind), the error mode is switched to queued-mode. At the end of the process, all errors are properly reported and the error mode is switched back to non-queued mode.

Therefore, by default, bugs are logged in the event log and are reported back to the user. User errors are only reported back to the user. A number of messages and properties exist that allow you to customize this process. The most common customizations are:

Creating a custom queued process

If you create a custom process, where errors might be expected, you will want to queue the errors. Sending the messages ErrorQueueStart, ReportAllErrors and ErrorQueueEnd can control the entire queuing process.

Explicitly logging an error in the event log

In some cases, you may want to log an error in the event log, even if that error is expected. Sending the message LogErrorEvent does this. This generates an error and enters the error in the event log. You can also log non-error events in the event log. This is done by sending the message LogEvent.

Disabling the reporting of all unexpected errors to the user

You may decide that unexpected errors should never be reported to the user. In such a case, you would want to see the error added to the event log but not reported back to the browser. Setting the property pbAllErrorsToHtml to false, would accomplish this.

Creating special reporting conditions when debugging your application

A number of properties are provided to allow you to create special reporting conditions while debugging. You can choose to:

  • log all errors to the event log (pbAllErrorsToEventLog).

  • pass all errors to the standard Visual DataFlex error handler (pbAllErrorsToLocal). Errors would appear in message boxes on the NT server console.

  • Display additional technical information with the error (pbVerboseErrors).

These Visual DataFlex properties can be toggled from within your ASP file, a nice aid to debugging.

The following error handling interface should give you the flexibility to completely control the error reporting process. Keep in mind, that for the most part, the entire error reporting process is automatic. Usually the only special code required will be the messages to handle queued error reporting within custom processes. Those messages will be ErrorQueueStart, ReportAllErrors, and ErrorQueueEnd.

  • Procedure ErrorQueueStart

  • Procedure ErrorQueueEnd

  • Procedure ClearErrors

  • Procedure ReportAllErrors

  • Procedure ReportLastError

  • Procedure ReportErrorItem

  • Function ErrorCount

  • Function FileFieldErrorItem

  • Function ErrorMessage

Error Reporting Properties

The following properties allow you to change the way errors are reported. They are provided primarily to assist you with debugging your programs. Although these properties exist within your WBO object, they are global in nature. In other words, changing these properties in one WBO will also change the property in all other WBOs.

Many of these properties determine where an error should be recorded. An error can be logged to the Visual DataFlex console, HTML file (either directly or queued) and to the event log. An error can be logged to several locations at once. Setting one property does not reset another property.

Note that these properties can be changed from within your ASP file, a feature that is particularly useful when debugging. You can change how errors are reported without needing to recompile your Visual DataFlex program. You "get" and "set" these properties within ASP using the Call Method.

<% WBO.Call "Set_pbAllErrorstoEventLog", 1 %>

The value of pbAllErrorsToEventLog is

<%=WBO.Call("Set_pbAllErrorstoEventLog") %>

  • Property pbQueueErrors

  • Property pbVerboseErrors

  • Property pbAllErrorsToEventLog

  • Property pbAllErrorsToHtml

  • Property pbAllErrorsToLocal

See Also

Creating Active Server Pages


Learning from the ASP Examples

The Order Entry example demonstrates the extendibility of the Web Application Server. It also demonstrates how a developer effectively integrates ASP server script programming and WBO programming.

These programs created with the Web Wizards only scratch the surface of your development capabilities with the Studio.

We suggest that you use the following steps when studying the Order Entry example.

    1. Run the sample. Before you study the code, spend some time running this sample over the web (it can be located in \Examples\Order Entry) This will give you an idea of how this application works.
    2. Review the online help on the cWebBusinessProcess class. These samples will be using features from this class. As you encounter various functions in the sample code, review these functions in the above documentation.
    3. Review the documentation in their source pairs. Each web view component (the .wbo files) has a corresponding ASP component (the .asp files). These should be studied as a unit. The following source pairs are created in \Examples\Order Entry:

VDF File | ASP File | WBO Name
Login.wbo | Login.asp | oLoginUsers
SalesP.wbo | SalesP.asp | oSalesP
Customer.wbo | Customer.asp | oCustomer
Vendor.wbo | Vendor.asp | oVendor
Invt.wbo | Invt.asp | oInvt

    4. Review the files in the order listed. They increase in complexity. Here is a quick overview of each component:

Login: This is the login panel. It shows how to use a WBO for a non-standard (data entry, report) purpose. The Login.wbo WBO has a special function (get login_user) that can be called to process a login. It is passed a user name and a password and checks to see if the user exists. It returns 1 if the login was OK and 0 if the login failed. The Login.ASP file calls this function. Based on the outcome of the login, the ASP file will set browser cookies indicating the user’s login rights. All other ASP files will use these cookies to determine if a user is allowed to edit data.

SalesP: This is a sales person data entry and report component. The SalesP.wbo WBO is actually quite simple and could have been generated with the Web Wizard. The SalesP.asp file uses a number of advanced techniques. This ASP file is fully documented so it is a good place to start.

Customer: This is the customer data entry and report component. It uses all the same techniques as the Sales Person view. Because customer view has additional input controls (multi-line edit and drop-down combo list), it better demonstrates the power of the automatic label and control generation.

Vendor: This is the vendor data entry and report component. It is similar to the Customer entry view with the exception that it allows you to generate a "vendor" report and an "Inventory item by Vendor" report.

Invt: This is the Inventory item entry and report view. It contains the most complicated VDF web view component (invt.wbo) and the most complicated asp component (Invt.asp). The VDF web view contains two reports – a report that lists all Inventory items by a selected index, and a report that lists all inventory items for a selected vendor. To accomplish this, the Visual DataFlex WBO must dynamically change constraints in the DDO.

In addition, these reports are manually coded using a cWebReport object. This was required because the report must be able to link to both the inventory item entry page and the parent, vendor item entry, page. The asp file (Invt.asp) contains the logic to drive both reports. It also uses several other special techniques. The delete button is not displayed if the Invt record is new (since you cannot delete a new record). In addition, parent vendor record is selected using the Parent Combo Form capability provided with the cWebBusinessProcess class.

See Also

Creating Active Server Pages


Creating Web Browser Objects (WBO)

Creating Web Browser Objects

The Class Reference manual in the on-line help, fully describes all of the available classes. The three most used classes are the DataDictionary; cWebBusinessProcess (WBO); and cWebReport Classes.

  • Publishing WBO Methods

  • Global Functions

  • Public Interface (WBO to COMWBO)

  • Public Object Instance Interface

  • Private Object Instance Interface

  • Public Event Interface (COMWBO to WBO)

  • Using Data Dictionary Objects

  • Creating Custom WBOs

  • Web Reporting


Publishing WBO Methods

Objects built from the cWebBusinessProcess class are referred to as Web Browser Objects (WBOs). This is a special class that allows all of its messages be available to ASP Script code. This is referred to as published methods. All Web Service methods within an object must be published before they can be used. Some Web Browser methods must also be published. This is accomplished by selecting the method to be published in the Code Explorer and selecting the "Publish" option from its context menu.

Publishing a method adds two meta tags, Published and Description, to your source code as follows:

{ Published = True }

{ Description = "" }

Function SayHello String sName returns String

String sReply

Move ("Hello" * sName) to sReply

Function_Return sReply

End_Function

There is also a set of predefined method that can be published. Please click on the links for detailed information on the following messages:

Message | Registers These Messages
RegisterStandardInterface | set_pbReportErrors set_pbClearAfterSave get_CreateFindIndexCombo get_peFieldMultiUser msg_ErrorQueueStart msg_ClearErrors msg_ReportAllErrors
RegisterBasicErrorInterface | msg_ErrorQueueStart msg_ErrorQueueEnd msg_ClearErrors msg_ReportAllErrors
RegisterFullErrorInterface | msg_ErrorQueueStart msg_ErrorQueueEnd msg_ClearErrors msg_ReportAllErrors msg_ReportLastError get_ErrorCount msg_ReportErrorItem get_ErrorMessage msg_LogErrorEvent
RegisterDebuggingInterface | set_pbVerboseErrors set_pbAllErrorsToEventLog set_pbAllErrorsToLocal set_pbAllErrorsToHtml set_peHtmlOutput
RegisterAutoEntryInterface | set_psAutoEntryLabelStart set_psAutoEntryLabelEnd set_psAutoEntryDataStart set_psAutoEntryDataEnd get_AutoEntry
RegisterInterface | Fully described below
RemoveInterface | Removes the message from the Call interface

RegisterInterface

This message is used to register a message (property, function, procedure) and make it available as a Call message within an ASP page. This message is almost never used directly in the WBO, unless you’re writing a subclass. In most cases you use the Code Explorer context menu to publish methods, or add the Published metadata tag. But if you’re writing a cWebBusinessProcess subclass, and you want to publish methods from your class you must use RegisterInterface.

RegisterInterface integer iMsgNumber string sMsgName string sParms string sDescription — procedure

Four parameters are required:

iMsgNumber

This is the message number. Normally this is passed as the message name preceded by get_ (for functions and retrieving properties), set_ (for setting properties) or msg_ (for procedures). For example:

get_SomeProperty or get_SomeFuntion
set_SomeProperty
msg_SomeProcedure

sMsgName

This is the name of the message that will be used in the ASP page. Normally, you should make this the same name as the property (just put quotes around the property name).

"get_SomeProperty" or "get_SomeFuntion"
"set_SomeProperty"
"msg_SomeProcedure"

sParams

This records the list of parameters used by the message. This is not required and is used for documentation purposes.

sDescription

This records a description of the message. This is not required and is used for documentation purposes.

Instead of needing to create a RegisterInterface message for each message you plan to register some messages have been combined into interface procedures allowing you to register a single set of interfaces at one time. Those predefined interface messages are:

Send RegisterStandardInterface
Send RegisterBasicErrorInterface
Send RegisterFullErrorInterface
Send RegisterDebuggingInterface
Send RegisterAutoEntryInterface

Typically, you will want to register the standard interface.

Object SalesP_WBO is a WebBusinessProcess

Object Salesp_DD is a Salesp_DataDictionary

Send DefineAllExtendedFields

End_Object // Salesp_DD

Set phMainDD to Salesp_DD

Send RegisterStandardInterface

End_Object // SalesP_WBO

If the same message is registered more than once, only the first registration is applied.

Visual DataFlex Code

Send RegisterInterface get_ddFindbyRowId "get_ddFindbyRowId" ;

"string sTable string sSerializedRowId returns boolean" ;

"Find by serialized Row id: returns True if found"

Script Code

None

See Also

Creating Web Browser Objects


Global Functions

These are Global Functions that make them available from an object built from any class.

FormatNumber and SetNumberFormat

FormatCurrency and SetCurrencyFormat

FormatValue

HtmlEncode

The only difference between the FormatNumber / SetNumberFormat and FormatCurrency / SetCurrencyFormat is that one is used for numbers and one is used for currency. Therefore, only the one set is shown, for a complete description see the Class Reference in the on-line help.

See Also

Creating Web Browser Objects


Public Interface (WBO to COMWBO)

These are the messages sent from WBO to the COMWBO. These messages either request information or request that a certain action be taken by the COMWBO. Typically, these will be sent within a MyProcess, custom procedure. They can also be sent within one of the DoRequest messages (save, delete, clear, and find).

The HTML and WML messages are used to generate code that will be placed within the HTML or WML page that the ASP file is currently building. This is a powerful capability. Dynamic output can be generated directly by the ASP script, or it can be generated by calling a WBO procedure and allowing DataFlex to generate the script. This latter method is used to generate reports. The ASP file sends the message MyProcess to a WBO and this object then generates the entire report (it finds the records and generates the HTML or WML output).

Procedure WriteHtml | Procedure WriteHtmlPlainText | Procedure WriteHtmlBreak
Procedure WriteHtmlTableBegin | Procedure WriteHtmlTableEnd | Procedure WriteHtmlRowBegin
Procedure WriteHtmlRowEnd | Procedure WriteHtmlCell | Procedure WriteHtmlCellHeader
Function HtmlAnchor | Function HtmlBig | Function HtmlBlink
Function HtmlBold | Function HtmlFixed | Function HtmlEmph
Function HtmlFontColor | Function HtmlFontSize | Function HtmlHeader
Function HtmlItalics | Function HtmlLink | Function HtmlSmall
Function HtmlStrike | Function HtmlStrong | Function HtmlSub
Function HtmlSup | Procedure LogEvent | Procedure LogErrorEvent
Procedure WriteWml | Procedure WriteWmlBreak | Procedure WriteWmlTableBegin
Procedure WriteWmlTableEnd | Procedure WriteWmlRowBegin | Procedure WriteWmlRowEnd
Procedure WriteWmlCell | Procedure WriteWmlDataBegin | Procedure WriteWmlDataEnd
Procedure WriteWmlImg | Function WmlAnchor | Function WmlBig
Function WmlBold | Function WmlItalics | Function WmlSmall
Function WmlLink | Function WmlEm | Function WmlStrong

See Also

Creating Web Browser Objects


Public Object Instance Interface

These are messages that will be sent from within a WBO object to itself. These would be sent from within custom methods inside of WBO.

pbReportErrors

pbClearAfterSave

See Also

Creating Web Browser Objects


Private Object Instance Interface

These messages are suitable for augmentation within a WBO object.

Procedure OnReportSaveStatus

Procedure OnReportClearStatus

Procedure OnReportDeleteStatus

Procedure OnReportFindStatus

Procedure OnReportValidateStatus

See Also

Creating Web Browser Objects


Public Event Interface (COMWBO to WBO)

These messages are sent from the ASP file to the COMWBO, which sends them to the WBO. These public event messages are usually initiated by script code within the ASP file. If you look at the ASP code sample, you will see how the ASP file uses these messages. Refer to the Creating ASP section for more information on these messages.

Function DoRequestSave

Function DoRequestFind

Function DoRequestClear

Function DoRequestDelete

Function DoRequestDDUpdate

Function DoRequestFindByRecId

Function DDValue

See Also

Creating Web Browser Objects


Creating Custom WBOs

Web Browser Objects (WBOs) have built-in capabilities and interfaces to support complex data-entry operations. These built-in methods (RequestSave, RequestDelete, RequestClear and RequestFind) perform operations that are quite difficult to execute over the Internet, and they perform these operations using the services and protections of Data Dictionaries (DDs). Entry wizards make it very easy to create data-entry Internet components. Reporting is handled within WBOs by creating Web Report Objects within them. These objects also use the services of Data Dictionary Objects (DDOs). Report wizards can be used to create these reports.

While these built-in WBO capabilities are very useful and powerful, you will probably discover that your applications require your WBOs to perform numerous other processes that cannot be implemented using built-in objects and wizards. Many of these operations, while quite simple, simply cannot be generated using templates, classes, and wizards. While they may be simple, the variety of tasks required in applications will be quite large.

Fortunately, it is very simple to: add custom behaviors to your WBOs; define interfaces to execute these behaviors, and execute these behaviors from your ASP pages. This section will show you how.

These samples will show you how to create WBO processes (functions) that perform database operations. All database operations use DDOs to perform tasks. If you are not familiar with the DDO interface, some of the WBO examples may not make sense. Refer to Using DDOs in your WBO processes for information about the DDO interface.

  • Creating a Simple Custom WBO Behavior

  • Creating a Custom DDO-based WBO Behavior

  • Using DDValue with Custom WBO Behaviors

  • WBO/DDO Persistence within an ASP Page

  • WBO/DDO Persistence across ASP Pages

  • Writing HTML Directly from a WBO

  • Creating a Custom WBO Report

  • Saving Data in your DDOs

  • Saving Data Using RequestSave

See Also

Creating Web Browser Objects


Creating a Simple Custom WBO Behavior

Web Browser Objects can be programmed to perform any kind of behavior. Whether simple or complex, the steps to create and execute a new behavior are the same.

  1. You must create a new WBO or load an existing WBO into the studio.

  2. You create the code within the WBO to perform the action. Sometimes this step will be as simple as creating a single procedure or function. Other times, this step may require the creation of many new methods and objects.

  3. You must make the custom procedure or function available to your ASP page. You do this by publishing the method. Whether you have created a single new method or multiple new methods, one of those methods must be identified as the public interface required to execute the behavior.

  4. You must make sure your WBO is added to yourweb applicationand you must then compile your application.

  5. You add code to your ASP page to call the WBO method when needed. The custom method is called by using the Call message.

A simple example will make these steps clear. In the following example we are going to create a trivial login WBO. We want to create a function called get_LoginUser which will be passed a user ID string. This ID will be compared against a list of known names. If a match is found, the user’s name will be returned to the ASP page.

We will start with the last step and show how this function will be used in an ASP page. The page would contain the following VBScript code:

<% ' login in to the system

sId = "ABC"

sLoginName = oUserLogin.Call("get_LoginUser", sID)

%>

:

Hello <%=sLoginName %> how are you doing today.

In this example, we are calling a WBO object named oUserLogin that has a published method named get_LoginUser. The function is passed a single parameter, the login ID. In this example this parameter is hard-coded as "ABC". Normally you would pass a value that had been submitted to the server page as follows:

<% ' login in to the system
sId = request("LoginName")
sLoginName = oUserLogin.Call("get_LoginUser", sID)
%>
:
Hello <%=sLoginName %> how are you doing today.

Also note that this example moves the return value (the login name) to a variable. An alternate way to code this would be as follows:

:
Hello <%=oUserLogin.Call("get_LoginUser", request("LoginName")) %> how are you doing today.

The WBO function required to perform this login looks like this:

{ Published = True }

Function LoginUser string sID returns string
String sName
Move (Uppercase(sID)) to sID
Case Begin
Case (sID="ABC") Move "Alfred B. Chambers" to sName
Case (sID="DEF") Move "Desmond E. Fleming" to sName
Case (sID="GHI") Move "Greg H. Irving" to sName
Case else Move "Mystery Guest" to sName
Case End
Function_return sName
End_Function

Note that the name of this function is LoginUser and not get_LoginUser which is how it appears in the ASP file. When accessing WBO functions, you must always add the prefix get_. When accessing WBO procedures, you must always add the prefix msg_. When creating either of these functions or procedures you do not add these prefixes. Similarly, when accessing these functions or procedures from within your web application (e.g. Get MyFunction or Send MyProc) you do not include the prefix. When accessing these from the ASP page (e.g. oMyObj.Call("get_MyFunction") or oMyObj.Call("msg_MyProc) you must use the proper prefix.

Before this function can be called from the ASP page, its interface must be published – made available to the ASP page. The method is published by adding the { Published = True } Metadata tag, or selecting Publish from the Code Explorer context menu in the Studio.

The entire WBO object might look like this:

Use cWebBusinessProcess.pkg

Object oUserLogin is a cWebBusinessProcess
set psDescription to "Sample of a simple Login"

{ Published = True }

{ Description = "Pass user ID, return user name" }
Function LoginUser string sID returns string
String sName
Move (Uppercase(sID)) to sID
Case Begin
Case (sID="ABC") Move "Alfred B. Chambers" to sName
Case (sID="DEF") Move "Desmond E. Fleming" to sName
Case (sID="GHI") Move "Greg H. Irving" to sName
Case else Move "Mystery Guest" to sName
Case End
Function_return sName
End_Function

End_Object // oUserLogin

An ASP page that would use this might look like the following:

<html>

<head>
<title>UserLogin</title>
<meta name="GENERATOR" content="Visual DataFlex Studio">
</head>

<body>

<h3>Login System</h3>

<form action="UserLogin.asp" method="POST" name="UserForm">
<p>Please enter your ID: <input type="password" name="LoginName" size="20"><input
type="submit" value="Log-in" name="LoginBn"></p>
</form>

<% if request("LoginBn")<>"" then %>

<% ' login in to the system
sId = request("LoginName")
sLoginName = oUserLogin.Call("get_LoginUser", sID)
%>

Hello <%=sLoginName %> how are you doing today.

<% end if %>
</body>
</html>

The above sample shows the basics of creating and using a custom WBO. You could create additional functions and procedures to model any type of behavior you like.

See Also

Creating Custom WBOs


Creating a Custom DDO-based WBO Behavior

The next step in creating WBO custom behaviors is to allow the WBO to access data. Obviously, a login system that requires that each ID be directly coded into the function is of limited value. We want to access this information from tables by using data dictionaries. In the following example, we will change the WBO so that it uses a DDO for a User table. When the function is called, it will now look up the user id in a user table. If the name exists, it will return the name. If the name is not found, it will return the name "Mystery Guest". Our WBO now looks like this:

Use cWebBusinessProcess.pkg

Use User.dd

Object oUserLogin is a cWebBusinessProcess

set psDescription to "User Login from Table"

Object oUser_DD is a User_DataDictionary

//IDE-DDOsettings-Start

Send DefineAllExtendedFields

//IDE-DDOsettings-End

End_Object

Set phMainDD To oUser_DD

{ Published = True }

{ Description = "Pass user ID, return user name" }

Function LoginUser string sID returns string

String sName

Handle hDD

Move (Uppercase(sID)) to sID

Move oUser_DD to hDD

Send Clear of hDD

Move sID to User.Id

Send Find of hDD EQ 1

If (Found) ;

Move User.Name to sName

Else ;

Move "Mystery Guest" to sName

Function_return sName

End_Function

End_Object // oUserLogin

Within Database Builder, we created a table and data dictionary class for User. Within the Studio we added a User DDO to our WBO. Once added, we can now direct messages from our WBO function to the DDO. The data dictionary required to perform this lookup will be described in the next section. For now, you should understand that the function does the following:

  1. It finds the object handle of the User DDO.

  2. It clears the User DDO.

  3. It seeds the User data-buffer with the passed User ID and attempts to find a record that contains that ID.

  4. If the record is found, the User name is returned. If no record is found the name "Mystery Guest" is returned.

It is important to note that the WBO’s published interface has not changed. If we compiled this object, we could continue to use the same ASP page to retrieve the login name. The ASP page simply calls a function that executes a business rule. It has no idea how that rule operates. As long as the interface does not change, the ASP page remains the same.

See Also

Creating Custom WBOs


Using DDValue with Custom WBO Behaviors

In the previous sample, the User Name is returned to the ASP page. What may not be apparent is that the User DDO now has a record loaded in it. This record contains all field information about the current user. Once this information is loaded into the DDO, it can be accessed by the ASP page by using the DDValue function. This is a very useful capability.

To demonstrate this, we are going to change the way this function works. Instead of returning a user name we will return a status value. If the User ID is valid, we will return a 1. If it is invalid, we will return a 0. If the ASP page needs to get more information about the User record (like the name or ID) it can do so with the DDValue message. Our new function looks like this:

// return 1 if User Id is valid, 0 if invalid.

// If valid, the User_DD object will be loaded with

// the current logged-in user.

{ Published = True }

{ Description = "Pass user ID, returns: true-Valid false-Invalid" }

Function IsUserValid string sID returns Boolean

Boolean bOK

Handle hDD

Move (Uppercase(sID)) to sID

Move oUser_DD to hDD

Send Clear of hDD

Move sID to User.Id

Send Find of hDD EQ 1

Move (Found) to bOK

Function_return bOK

End_Function

We are now using the return value to indicate if our function succeeded. We will get additional information about the user by using the DDValue message. Since we have changed our interface, we will need to change our ASP page. The new code will look like this:

<% ' login in to the system
sId = request("LoginName")
bLoginOk = oUserLogin.Call("get_IsUserValid", sID)
%>

<% If bLoginOK = 1 then %>
Hello <%= oUserLogin.DDValue("User.Name") %> how are you doing today.<br>
Did you know that your user ID is <%= oUserLogin.DDValue("User.ID") %>
<% else %>
I don't know who you are. Go away!
<% end if %>

This sample demonstrates a commonly-used technique. The return value from our custom function is used to return a status or error code. Based on that code, we know if the DDOs contain useful information. If they do, we use DDValue to extract information from them. The entire ASP page now looks like this:

<html>

<head>
<title>UserLogin</title>
<meta name="GENERATOR" content="WebApp Studio">
</head>

<body>

<h3>Login System</h3>

<form action="UserLogin.asp" method="POST" name="UserForm">
<p>Please enter your ID: <input type="password" name="LoginName" size="20"><input
type="submit" value="Log-in" name="LoginBn"></p>
</form>

<% if request("LoginBn")<>"" then %>

<% ' login in to the system
sId = request("LoginName")
bLoginOk = oUserLogin.Call("get_IsUserValid", sID)
%>

<% If bLoginOK = 1 then %>
Hello <%= oUserLogin.DDValue("User.Name") %> how are you doing today.<br>
Did you know that your user ID is <%= oUserLogin.DDValue("User.ID") %>
<% else %>
I don't know who you are. Go away!
<% end if %>

<% end if %>
</body>
</html>

See Also

Creating Custom WBOs


WBO/DDO Persistence within an ASP Page

It is important that you understand what we have done. Once a call to a WBO has loaded data into the data dictionary objects, that data can be retrieved and changed by using server script calls in the rest of your ASP page. This is the technique used byweb applicationserver to find and display records. At the top of an ASP page, the data submitted to the ASP page is queried and, based on that data, messages are sent to the WBO to "prepare" the DDOs. Preparing a DDO may consist of clearing (RequestClear), finding (RequestFind or RequestFindByRowId), saving (RequestSave) or deleting (RequestDelete). Upon completion of any of these tasks, the DDOs are now in a usable state. They are either cleared, or they contain data. Using DDValue, this data is then displayed in the HTML page either as:

  • Text: where data is inserted directly into an HTML page

Your name is <%=oUserLogin.DDValue("User.Name")%>

  • Input Data: where data is inserted into an input control

<input type="text" size="20" name="User__Name"

value="<%=oUserLogin.DDValue("User.Name")%>">

See Also

Creating Custom WBOs


WBO/DDO Persistence across ASP Pages

Once values have been loaded into a DDO, their data is available to the rest of the ASP page that is being processed. Does this data remain available to the client (the browser) as other pages within the application are accessed? The answer is a qualified "yes". Data can be persistent but you should not count on this persistence. As long as your ASP session has not timed out, the WBO data remains available. It is very risky to count on this, because you never know when a session will time out. It is best to not count on session persistence within your application. None of the pages created by our wizards or any of our samples relies on persistence. Each time a new page is requested the DDOs should be initialized and "prepared" anew.

See Also

Creating Custom WBOs


Writing HTML Directly from a WBO

In our previous examples, we have called functions that return data from the WBO. The ASP page is then responsible for displaying this data as HTML output. Rather than returning information from a function call, a WBO method can also directly send HTML code back to the ASP page. The advantage of this method is that a great deal of HTML data can be returned to the ASP page, which is then directly sent to the browser. This technique is commonly used for reporting. The disadvantage of this method is that the ASP page (and its ASP script) has very little control over the formatting of this data. For this reason, you are normally discouraged from outputting HTML text directly from a WBO. The following code should be avoided:

WBO Code

// return 1 if User Id is valid, 0 if invalid.
// If valid, the User_DD object will be loaded with
// the current logged in user.

{ Published = True }

{ Description = "Pass user ID, returns: true-Valid false-Invalid" }
Function IsUserValid string sID returns integer
Integer bOK
Handle hDD
Move (Uppercase(sID)) to sID
Move oUser_DD to hDD
Send Clear of hDD
Move sID to User.Id
Send Find of hDD EQ 1
If (Found) Begin
Send WriteHtml (HtmlEncode("Hello" * User.Name * ;
" how are you doing today.")
Send WriteHtml ("Did you know that your user ID is" *;
User.ID)

Move 1 to bOK
End
Else begin
Send WriteHtml "I don't know who you are. Go away!"
Move 0 to bOK
End
Function_return bOK
End_Function

ASP Code

<% ' login in to the system
sId = request("LoginName")
bLoginOk = oUserLogin.Call("get_IsUserValid", sID)
%>

Whenever possible, it is best to let the ASP page handle most of the visual output, and to let the WBO handle most of the business processes. Again, the above style of coding, while valid, is discouraged.

The exception to this rule is in reporting. Often, WBO custom methods will be used to directly output HTML data within a report. The cWebReport class provides an easy and powerful way to generate reports. You can learn how to create cWebReport objects by using the report wizards to generate code, then studying them. It is also worthwhile to learn how to create a report manually. This exercise will help you add to your WBO customization knowledge.

See Also

Creating Custom WBOs


Creating a Custom WBO Report

In this section, we will create a report without the aid of a reporting object. Although this sample could be quite easily created using the report wizard, we are going to create this "the hard way".

We want to add a new WBO method named get_ListUsers. If this message is called, a report that lists all users in the table will be generated. The function would be called from your ASP page as follows:

Here is a list of the other login ids:
<% bErr = oUserLogin.Call("get_ListUsers") %>

The WBO report function will look like this:

{ Published = True }

{ Description = "List all users in a report, returns Err code" }

Function ListUsers returns integer
Handle hDD
Move oUser_DD to hDD

Send WriteHtmlTableBegin

Send WriteHtmlRowBegin
Send WriteHtmlCellHeader "Id"
Send WriteHtmlCellHeader "User Name"
Send WriteHtmlCellHeader "Last Access"
Send WriteHtmlRowEnd

Send Clear of hDD
Send Find of hDD Ge 1
While (Found)
Send WriteHtmlRowBegin
Send WriteHtmlCell (HtmlEncode(User.Id))
Send WriteHtmlCell (HtmlEncode(User.Name))
Send WriteHtmlCell User.last_Access
Send WriteHtmlRowEnd

Send Find of hDD GT 1
Loop

Send WriteHtmlTableEnd
Function_Return 0 // always OK
End_Function

You will notice that we chose to make ListUsers a function, even though there is no need to use the return information (it always returns 0). We did this because it is easier to create a single interface type (function). VBScript uses very different syntax for calling functions and for calling procedures, and it is easier to just remember a single syntax. Also, processes like a report, that initially require no error return checking, often grow into more complex processes that will eventually require this type of return value error checking.

Our complete WBO, which is now capable of logging in to the system and displaying a report of all users, now looks like this:

Use cWebBusinessProcess.pkg
Use User.dd

Object oUserLogin is a cWebBusinessProcess
Set psDescription To "User Login and report"

Object oUser_DD is a User_DataDictionary
Send DefineAllExtendedFields
End_Object

Set phMainDD To oUser_DD

{ Published = True }

{ Description = "List all users in a report, returns Err code" }
Function ListUsers returns integer
Handle hDD
Move oUser_DD to hDD

Send WriteHtmlTableBegin

Send WriteHtmlRowBegin
Send WriteHtmlCellHeader "Id"
Send WriteHtmlCellHeader "User Name"
Send WriteHtmlCellHeader "Last Access"
Send WriteHtmlRowEnd

Send Clear of hDD
Send Find of hDD Ge 1
While (Found)
Send WriteHtmlRowBegin
Send WriteHtmlCell (HtmlEncode(User.Id))
Send WriteHtmlCell (HtmlEncode(User.Name))
Send WriteHtmlCell User.last_Access
Send WriteHtmlRowEnd

Send Find of hDD GT 1
Loop

Send WriteHtmlTableEnd
Function_Return 0 // always OK
End_Function

// return 1 if User Id is valid, 0 if invalid.
// If valid, the User_DD object will be loaded with
// the current logged in user.

{ Published = True }

{ Description = "Pass user ID, returns: true-Valid false-Invalid" }

Function IsUserValid string sID returns Boolean

Boolean bOK

Handle hDD

Move (Uppercase(sID)) to sID

Move oUser_DD to hDD

Send Clear of hDD

Move sID to User.Id

Send Find of hDD EQ 1

Move (Found) to bOk

Function_return bOK

End_Function

End_Object // oUserLogin

We will modify our ASP page so that it asks for a login user ID. If this ID is valid, it will welcome the new user and print a list of all other user ids (which is admittedly not the most secure thing to do in a Web Application).

<html>

<head>
<title>UserLogin</title>
<meta name="GENERATOR" content="Visual DataFlex Studio">
</head>

<body>

<h3>Login System</h3>

<form action="UserLogin.asp" method="POST" name="UserForm">
<p>Please enter your ID: <input type="password" name="LoginName" size="20"><input
type="submit" value="Log-in" name="LoginBn"></p>
</form>

<% if request("LoginBn")<>"" then %>

<% ' login in to the system
sId = request("LoginName")
bLoginOk = oUserLogin.Call("get_IsUserValid", sID)
%>

<% If bLoginOK = 1 then %>
Hello <%= oUserLogin.DDValue("User.Name") %> how are you doing today.<br>
Did you know that your user ID is <%= oUserLogin.DDValue("User.ID") %><br>
<hr>
Here is a list of the other login ids:
<% bErr = oUserLogin.Call("get_ListUsers") %>
<hr>
<% else %>
I don't know who you are. Go away!
<% end if %>

<% end if %>
</body>
</html>

See Also

Creating Custom WBOs


Saving Data in your DDOs

We will now show you how to change and save data. The WBO class already has an automated method for saving data. We will not use this ability, but instead will create a WBO function to perform this action ourselves.

We are going to make two changes to our WBO.

  1. Every time a user logs in to the system we will store the login date in that user’s record. This will be added to the IsUserValid function.

  2. We will create a new function, ChangeName, which will change the current user’s name.

Adding a custom date stamp is accomplished as shown. The changes in this function are highlighted:

{ Published = True }

{ Description = "Pass user ID, returns: true-Valid false-Invalid" }

Function IsUserValid string sID returns Boolean

Boolean bOK bErr

Handle hDD

Date dToday

Move (Uppercase(sID)) to sID
Move oUser_DD to hDD

Send Clear of hDD

Move sID to User.Id

Send Find of hDD EQ 1

If (Found) Begin

// update date and save

SysDate dToday

Set File_Field_Changed_Value of hDD FILE_FIELD User.Last_Access to dToday

Get Request_Validate of hDD to bErr

If (not(bErr)) Begin

Send Request_Save of hDD

Move (err) to bErr // If err,save failed

End

Move (Not(bErr) to to bOK

end

Function_Return bOK

End_Function

This contains the basic elements required to change a record’s value. You must:

  1. Find the record (or clear it, if you are saving a new record)

  2. Update any DD field values, and mark them as changed.

  3. Perform DD field validation on the current data.

  4. If the data is valid, save it.

Because you are using data dictionaries you know that all DD field and file validations are properly checked; all multi-user considerations are being properly handled, and all relational balances are properly maintained. If the save succeeded, it saved valid data.

Saving a new name is very similar. We assume that this page will receive a request from the browser to change the name. Since we cannot assume that we have a persistent connection, we will want to pass the user’s Record RowId (an internal unique identifier) and the new name. Our WBO function to change a name will look like this:

{ Published = True }

{ Description = "Change name of passed RowId, returns Err code" }

Function ChangeName string sRowId string sName returns Boolean

Boolean bErr

RowId riRowId

Handle hDD

Move oUser_DD to hDD

Move (DeserializeRowId(sRowId)) to riRowId

Send FindByRowId of hDD User.File_Number riRowId

If (Found) Begin

// Update name and save

Set File_Field_Changed_Value of hDD FILE_FIELD User.Name to sName

Get Request_Validate of hDD to bErr

If not bErr Begin

Send Request_Save of hDD

Move (err) to bErr

End

End

Else begin

Move true to bErr

End

Function_return bErr

End_function

The ASP code gets a little more complicated, because code must be created to input and post the name change, and code must be generated to call the WBO function. The code to input the name change looks like this:

<form action="UserLogin.asp" method="POST" name="NameForm">

<p>

If you would like you can change your name:

<input type="hidden" name="User__RowId"

value="<%=oUserLogin.DDValue("User.RowId")%>">

<input type="text" size="30" name="User__Name"

value="<%=oUserLogin.DDValue("User.Name")%>">

<input type="submit" value="Change Name" name="NameBn">

</p>

</form>

We use a hidden form to store the RowId value. We use a single line text control to display and modify the user name. The values of these controls are obtained by using the DDValue message. When the submit button is pressed, the value of User__RowId and User__Name will be posted to the server. When the request is posted to the server, the ASP code that will process it is:

<% if request("NameBn")<>"" then ' change name button ----------- %>

<% ' login in to the system

RowId = request("User__RowId")

sName = request("User__Name")

bErr = oUserLogin.Call("get_ChangeName", RowId, sName)

%>

<% end if ' change name button ----------- %>

If NameBn (Change Name button) was selected, the form will also post User__RowId and User__Name. These values are passed to our WBO and the name is changed.

The complete WBO, with login, report, and name change now looks like this:

Use cWebBusinessProcess.pkg
Use User.dd

Object oUserLogin is a cWebBusinessProcess

Object oUser_DD is a User_DataDictionary
Send DefineAllExtendedFields
End_Object

Set phMainDD To oUser_DD

{ Published = True }

{ Description = "List all users in a report, returns Err code" }

Function ListUsers returns integer

Handle hDD

Move oUser_DD to hDD

Send WriteHtmlTableBegin

Send WriteHtmlRowBegin

Send WriteHtmlCellHeader "Id"

Send WriteHtmlCellHeader "User Name"

Send WriteHtmlCellHeader "Last Access"

Send WriteHtmlRowEnd

Send Clear of hDD

Send Find of hDD Ge 1

While (Found)

Send WriteHtmlRowBegin

Send WriteHtmlCell (HtmlEncode(User.Id))

Send WriteHtmlCell (HtmlEncode(User.Name))

Send WriteHtmlCell User.last_Access

Send WriteHtmlRowEnd

Send Find of hDD GT 1

Loop

Send WriteHtmlTableEnd

Function_Return 0 // always OK

End_Function

// return 1 if User Id is valid, 0 if invalid.

// If valid, the User_DD object will be loaded with

// the current logged in user.

{ Published = True }

{ Description = "Pass user ID, returns: true-Valid false-Invalid" }

Function IsUserValid string sID returns Boolean

Boolean bOK bErr

Handle hDD

Date dToday

Move (Uppercase(sID)) to sID

Move oUser_DD to hDD

Send Clear of hDD

Move sID to User.Id

Send Find of hDD EQ 1

If (Found) Begin

// update date and save

SysDate dToday

Set File_Field_Changed_Value of hDD FILE_FIELD User.Last_Access to dToday

Get Request_Validate of hDD to bErr

If (not(bErr)) Begin

Send Request_Save of hDD

Move (err) to bErr // If err,save failed

End

Move (Not(bErr) to to bOK

End

Function_Return bOK

End_Function

{ Published = True }

{ Description = "Change name of passed RowId, returns Err code" }

Function ChangeName string sRowId string sName returns Boolean

Boolean bErr

RowId riRowId

Handle hDD

Move oUser_DD to hDD

Move (DeserializeRowId(sRowId)) to riRowId

Send FindByRowId of hDD User.File_Number riRowId

If (Found) Begin

// Update name and save

Set File_Field_Changed_Value of hDD FILE_FIELD User.Name to sName

Get Request_Validate of hDD to bErr

If not bErr Begin

Send Request_Save of hDD

Move (err) to bErr

end

End

Else begin

Move true to bErr

End

Function_Return bErr

End_function

End_Object // oUserLogin

The final ASP page looks will look like this:

<html>

<head>
<title>UserLogin</title>
<meta name="GENERATOR" content="Visual DataFlex Studio">
</head>

<body>

<h3>Login System</h3>

<form action="UserLogin3.asp" method="POST" name="UserForm">
<p>Please enter your ID: <input type="password" name="LoginName" size="20"><input
type="submit" value="Log-in" name="LoginBn"></p>
</form>

<% if request("LoginBn")<>"" then ' Login button ------------- %>

<% ' login in to the system
sId = request("LoginName")
bLoginOk = oUserLogin.Call("get_IsUserValid", sID)
%>

<% If bLoginOK = 1 then %>
Hello <%= oUserLogin.DDValue("User.Name") %> how are you doing today.<br>
Did you know that your user ID is <%= oUserLogin.DDValue("User.ID") %><br>

<form action="UserLogin3.asp" method="POST" name="NameForm">

<p>If you would like you can change your name:

<input type="hidden" name="User__RowId" value="<%=oUserLogin.DDValue("User.RowId")%>">

<input type="text" size="30" name="User__Name" value="<%=oUserLogin.DDValue("User.Name")%>">

<input type="submit" value="Change Name" name="NameBn"></p>

</form>

<hr>
Here is a list of the other login ids:
<% bErr = oUserLogin.Call("get_ListUsers") %>
<hr>

<% else %>
I don't know who you are. Go away!
<% end if %>

<% end if ' Login button -------------%>

<% if request("NameBn")<>"" then ' change name button ----------- %>

<% ' login in to the system

RowId = request("User__RowId")

sName = request("User__Name")

bErr = oUserLogin.Call("get_ChangeName", RowId, sName)

%>

Here is a list of the other login ids:
<hr>
<% bErr = oUserLogin.Call("get_ListUsers") %>
<hr>
<% end if ' change name button ----------- %>

</body>
</html>

See Also

Creating Custom WBOs


Saving Data Using RequestSave

This section will be completed by removing a custom WBO function. At this point, the custom save (get_ChangeName) can be replaced by the built-in WBO message RequestSave. If file/field data is passed to the server in the proper format of FileName__FieldName (file name, two underscores, field name) and the RowId is passed using the format FileName__RowId, you can use the RequestSave message to save your data. This built-in function will properly initialize your DDO structure; load the DDOs with changed values; validate the data, and save the data.

The code in our ASP page that processes the name change, therefore, could be changed to:

<% if request("NameBn")<>"" then ' change name button ----------- %>

<% bErr = oUserLogin.RequestSave("User") %>

<% end if ' change name button ----------- %>

See Also

Creating Custom WBOs


Web Reporting

  • Creating Partial Reports

  • Creating Drill Down and Zoom Reports

  • SubHeaders, SubTotals and Breakpoints

  • Writing Runtime Configurable Reports

See Also

Creating Web Browser Objects


Creating Partial Reports

You can choose to print out partial reports by setting several properties. On the web, this is used to break reports into smaller segments. You want to be able to run a report for "x" number of records. When complete, you then want to be able to continue the report at record "x+1". This process is trickier than it might appear. When you continue the report, you can not assume that you are running the same WBO process. Each time the browser makes a request to the server you must expect that the server is starting a new session (i.e., it’s all stateless). Therefore, when you continue a report you are actually starting a new report starting at a particular record.

In the report object, the following properties are used to control this process:

  • Property priStartRowId

  • Property piMaxCount

  • Property piMaxCountBreakLevel

  • Property priLastRowId

Before you start a report you will want to set, priStartRowId, piMaxCount, and piMaxCountBreakLevel.

The property priStartRowId indicates what Rowid the report should start at. If this property is null (e.g. Set priStartRowId to (NullrowId()) ), no first record is seeded. If you do set, the property to a non-null RowId value you must remember to re-set it each time you use the report.

The property piMaxCount determines how many items are allowed before the report stops. If this property is 0, all items are processed. We use the term items and not records because the definition of an item can be changed. An item can be the number of times a main record is found (or, restated, the number of times the OnBody section is called). Alternatively, an item can also be the number of times a breakpoint level is encountered. For example, an item could be the number of times the report breaks on sub-header1 (i.e., the number of times OnSubHeader1 is called). This is defined by piMaxBreakLevel.

The property piMaxBreakLevel determines how items are counted. If the value is 0, the default, items are the same as the main-record. If the value is greater than 0, the item is the corresponding sub-header level. This property is useful because it allows you to stop reports at logical spots. For example, if you are reporting orders by customer you may not want to halt the report in the middle of a customer. So instead of saying, "I want to stop after every 20 orders", you may wish to say "I want to stop the report after every 10 customers".

After a report is halted, you can test how the report was halted by with the property priLastRowId. If it is null, the report completed. If the property is non-zero, the report was halted and this value is the next record that needs to be processed. In other words, if priLastRowId is non-null, it can be used to continue the report by setting this priStartRowId to this value.

Some examples will clear this up:

Sample One

This isn't all that useful, but it shows how the report cycle works. Assume that this function has been created within your report object. This will run a report for all records in sections of 20. Each section, is a new report.

Procedure RunSomeReport

RowId riRec riStart

Integer iRptStat

Set piMaxCount to 20

Set piMaxCountBreakLevels to 0

Repeat

Set priStartRowId to riRec

Get Dorunreport to iRptStat

Get priLastRowId to riRec

Until (IsNullRowId(riRec))

End_Procedure

Sample Two

More typcially the report would be run as follows. The first function is inside the report object. The second procedure is outside the report (inside the WBO) and is used to run an entire report.

Function RunSomeReport Rowid riStart integer iMax returns RowId

RowId riEndRec

Integer iRptStat

Set piMaxCount to 20

Set piMaxCountBreakLevels to 0

Set priStartRowId to riStart

Get Dorunreport to iRptStat

Get priLastRowId to riEndRec

Function_return riEndRec

End_Function

This above function (in the report object) would be called externally as follows:

Procedure RunWholeReport

RowId riRec

Move (NullRowId()) to riRec // actually it already is null

Repeat

Get RunSomeReport of oSomeReport riRec 20 to riRec

Until (IsNullRowId(riRec))

End_Procedure

Sample Three

This one is almost useful. The first function, RunSomeReport, is in the report object. The second method, RunSomeReport, is in the WBO object. The final code, is in your ASP code. We now have a report that runs from the web.

Because the Rowid data-type is special, we cannot pass RowId variables in and out of the ASP page. Before passing RowId we must convert it to a value that can be handled properly by an HTML page. Serialization and Deserialization functions are provided that convert RowId data to string data. Those functions are SerializeRowId() and DeSerializeRowId(). Note that a Null RowId value is serialized as an empty string.

Function RunSomeReport Rowid riStart integer iMax returns RowId

RowId riEndRec

Integer iRptStat

Set piMaxCount to 20

Set piMaxCountBreakLevels to 0

Set priStartRowId to riStart

Get Dorunreport to iRptStat

Get priLastRowId to riEndRec

Function_return riEndRec

End_Function

This above function (in the report object) would be called externally as follows (assume this WBO object is named oMyReport):

Function RunSomeReport String sSerializedStart integer iMax returns String

RowId riEnd riStart

String sSerializedEnd

// convert serialized RowID string to a real rowId

Move (DeserializeRowid(sSerializedStart)) to riStart

Get RunSomeReport of oSomeReport riStart 20 to riEnd

// convert rowId to a serialized RowId string

Move (SerializeRowid(riEnd)) to sSerializedEnd

Function_Return sSerializedEnd

End_Function

<%

' this code is in your ASP file

'

sRec = ""

iMaxRecs = 20

Do

sRec = oMyReport.Call("get_RunSomeReport", sRec, iMaxRecs)

Loop Until (sRec="") ' an empty RowId is a no record

%>

This sample is still not really useful because the ASP page is still running the entire report before it is complete. What you really must do, is run one report, and create a button or reference that allows you to call the ASP page and run the next "page" of the report. This is accomplished as follows:

<%

Start = request("Start")

EndRec = oMyReport.Call("get_RunSomeReport", Start, MaxRecs)

%>

<% If EndRec <> "" then ' an empty rowId is no record %>

<A HREF="MyReport.asp?Start=<%=EndRec%>">Next Page</A>

<% End if %>

At the end of the report, if there are still more records to process, the HRef text label named "Next Page" will appear at the bottom of the page.

Sample Four

Let’s assume that this report lists all orders in customer order. In this case, we want to show all orders for customers, ten customers at a time. The report object code would appear as follows

Function RunSomeReport RowId riStart integer iMax returns RowId

RowId riEndRec

Integer iRptStat

Set piMaxCount to 10

Set piMaxCountBreakLevels to 1 // subheader1 is customer

Set priStartRowId to riStart

Get Dorunreport to iRptStat

Get priLastRowId to riEndRec

Function_return riEndRec

End_Function

See Also

Web Reporting


Creating Drill Down and Zoom Reports

An Html report supports links to other reports by using the <A> html tag to create a call to another HTML or ASP page. In HTML the format looks like this:

<A HREF="URL-Name">Text to be displayed</A>

For example, if you wanted to assign URL to a customer name you would code the following:

<A HREF="Customer_zoom.asp">John Q. Public</A>

Of course the problem with the above, is that the URL being called ("Customer_zoom.asp") will not know what to do because we are passing it no useful information (what record should we be zooming?). Normally, you pass some useful information along with the URL name. For example:

<A HREF="Customer_zoom.asp?RowId=02000000">John Q. Public</A>

The zoom ASP page can use this passed information and do what it needs to do. The zoom form that processes this might look like the following:

<% ' Load the record into the DDO structure

RowId = Request("RowId")

Err = oCustomerReport.RequestFindbyRowId( "Customer", RowId)

%>

In a report, you can create links to other pages. Passing any type of information that you wish. Some methods are provided to make this particularly easy. First let’s do this manually and then show progessively easier ways to accomplish the same task.

In all cases, we will pass the URL name and a record’s RowId. The RowId is passed using the format "RowId=xxxxx". We are using this format as a universal data passing format between ASP files. You may choose to create different or additional information as well.

Assume a report looks like the following:

Procedure OnBody

Send WriteHtmlRowBegin

Send WriteHtmlCell Customer.Customer_Number

Send WriteHtmlCell (HtmlEncode(Customer.Customer_Name))

Send WriteHtmlRowEnd

End_Procedure

We could make customer_number linked text as follows:

Procedure OnBody

String sUrl sParam sHtml

Send WriteHtmlRowBegin

Move "Customer_Zoom.Asp" to sUrl

Move ("RowId="+SerializeRowId(Customer.File_Number)) to sData

Move ("<AHREF="+sUrl+"?"+sData+">"+string(Customer.Customer_Number)+"</A>") to sHtml

Send WriteHtmlCell sHtml

Send WriteHtmlCell (HtmlEncode(Customer.Customer_Name))

Send WriteHtmlRowEnd

End_Procedure

Alternately, we can use the HtmlLink function to make this a little easier:

Procedure OnBody

String sUrl sParam sHtml

Send WriteHtmlRowBegin

Move "Customer_Zoom.Asp" to sUrl

Move ("RowId="+ SerializeRowId(Customer.File_Number)) to sData

Get HtmlLink (sUrl + "?" + sData) Customer.Customer_Number to sHtml

Send WriteHtmlCell sHtml

Send WriteHtmlCell (HtmlEncode(Customer.Customer_Name))

Send WriteHtmlRowEnd

End_Procedure

In addition, there is a property psHRefName and a function AddRowIdLink that will make this even simpler. Set psHRefName property to the name of the table to link to and the function will create a formatted link using the name and RowId of the report’s main table.

// set this before the report is run.

Set psHRefName to "Customer_Zoom.Asp"

Procedure OnBody

String sHtml

Send WriteHtmlRowBegin

Get AddRowIdLink Customer.Customer_Number to sHtml

Send WriteHtmlCell sHtml

Send WriteHtmlCell (HtmlEncode(Customer.Customer_Name))

Send WriteHtmlRowEnd

End_Procedure

There is one problem with this method. When you create a report WBO you don’t really know how it will be used by various ASP pages. What if the ASP page designer doesn’t create a file name "Customer_Zoom.asp" Ideally, you would want the ASP page that calls the WBO reporting object to control this. This is easily done as follows:

  1. Create a method in the WBO object that sets the psHRefName Property.

Procedure SetHRefName string sName

Set psHRefname of oReport to sName

End_Procedure

  2. In the WBO, register the message as part of your external inteface.

Send RegisterInterface msg_SetHRefName "msg_SetHRefName" ;

"string sAspFileName" ;

"Name to link for drill down report"

  3. In your ASP code, set the name before running the report.

<%

Start = request("Start")

MaxRecs = 20

oCustomerReport.call "msg_SetHRefName", "Report_zoom.asp"

EndRec = oCustomerReport.call("get_RunCustomerReport", Start, MaxRecs)

%>

This is very powerful. This means that same WBO object can be called by different asp pages (or by the same asp page with different parameters) and depending upon the set up information, the report will link to different sub reports. Or, if the parameter is blank ("") there will be no linking at all.

There are numerous ways that this linking will be used. The three most common will be:

  • Link to a zoom Page. For example, you may have a customer report where limited data is displayed for each customer. You may want to be able to display a zoom page that displays more information.

  • Link to an entry page. For example, from your customer report you may wish to link to the ASP page that allows you to edit information about the customer.

  • Create a drill down report. For example, you may have customer report. For any customer you may wish to drill down and view all orders for the customer. Then, from the order report, you may wish to drill down and see all detail items for a selected order.

Link to a Zoom Page

A zoom page is just a special ASP page that finds the record passed and displays it. The WBO Report Object used can be the same object used to generate the report. For example, if the Customer_report ASP page links to a zoom page as follows:

oCustomerReport.Call "msg_SetHRefName", "Report_zoom.asp"

The zoom page might look like the following:

<html>

<head>

<meta http-equiv="Content-Type" content="text/html;charset=iso-8859-1">

<title>Customer Zoom</title>

</head>

<body background="Images/Gray%20Weave.gif">

<h3 align="center">Customer Detail Zoom</h3>

<hr>

<% ' Load the record into the DDO structure

RowID = Request("RowId")

Err = oCustomerReport.RequestFindbyRowId( "Customer", RowId)

%>

<table border="0" width="99%">

<tr>

<th valign="top" align="left" width="20%" bgcolor="#C0C0C0">Field Name</th>

<th align="left" bgcolor="#C0C0C0">Value</th>

</tr>

<tr>

<th align="left" valign="top" width="20%">Customer Number</th>

<td align="left"> <%=oCustomerReport.ddValue("Customer.Customer_Number",DDESC)%>

</td>

</tr>

<tr>

<th align="left" valign="top" width="20%">Customer Name</th>

<td align="left"><%=oCustomerReport.ddValue("Customer.Name",DDESC)%></td>

</tr>

:

:

</table>

<hr>

<form action="Customer_report.asp" method="POST">

<p><input type="submit" value="Back" OnClick="history.back()">

<input type="submit" value="New report">

</p>

</form>

</body>

</html>

Zoom pages can be (or will be) generated by the reporting wizard.

Link to an Entry Page

If you set your link to a standard data entry asp page, the page will automatically load the passed record and use that for editing. The following code at the top of our standard data entry asp pages controls this:

<html>

<head>

<meta http-equiv="Content-Type" content="text/html;charset=iso-8859-1">

<title>Customer4</title>

</head>

:

<%

If request("Request_method")="GET" Then

RowId = request("RowId")

If RowId <> "" Then

' this message is understood by the WebBusinessProcess class

Err = oCustomer.RequestFindbyRowId("Customer", RowId)

Else

Err = oCustomer.RequestClear("Customer",1)

End If

else

if Request("clear")<>"" then

Err = oCustomer.RequestClear("Customer",1)

end if

if Request("save")<>"" then

' note that we can return a value here.

err = oCustomer.RequestSave("Customer")

if err = 0 then

Response.Write("<center> <h4>Thank you for sending your information.</h4> </center>")

else

Response.Write("<center> <h4>Could not save changes. Errors Occurred</h4> </center>")

end if

end if

if Request("delete")<>""then

Err = oCustomer.RequestDelete("Customer")

end if

' note we use the Indx variable we created above

if Request("findprev") <>"" then Err = oCustomer.RequestFind("Customer", Indx, 0) ' Find LT

if Request("find") <>"" then Err = oCustomer.RequestFind("Customer", Indx, 3) ' Find EQ

if Request("findnext") <>"" then Err = oCustomer.RequestFind("Customer", Indx, 4) ' Find GT

if Request("findfirst")<>"" then Err = oCustomer.RequestFind("Customer", Indx, 6) ' Find First

if Request("findlast") <>"" then Err = oCustomer.RequestFind("Customer", Indx, 7) ' Find Last

end if

Create a Drill Down Report

A drill down report must call an ASP page that starts another (child) report. You will need to create a report that only prints related children for a passed parent. The report object provides two properties that automates this process: piConstrainFile and priConstrainRowId.

If before starting the report you set these two properties to the desired constraining File and RowId the report will automatically be generated for the one parent. The constraint file is the parent table that should constrain the records of its children. The constraint rowId is the parent record that should used to find the parent.

The following example shows an Order Report that is designed to display all orders for a single customer.

Use cWebBusinessProcess.pkg
Use Customer.dd
Use Saless.dd
Use Orderhea.dd

Object oOrderReport is a cWebBusinessProcess

Object oCustomer_DD is a Customer_DataDictionary
Send DefineAllExtendedFields
End_Object // oCustomer_DD

Object oSalesP_DD is a SalesP_DataDictionary
Send DefineAllExtendedFields
End_Object // oSalesP_DD

Object oOrderhea_DD is a OrderHea_DataDictionary

Send DefineAllExtendedFields

Set DDO_Server to oCustomer_dd

Set DDO_Server to oSalesP_dd

End_Object // oOrderhea_DD

Set phMainDD to oOrderHea_DD

Object oReport Is A cWebReport
Set piOrdering to 2 // Customer x Order number
Set piConstrainFile to Customer.File_number
Set priConstrainRowId to (NullRowId()) // this will get set for each report
Procedure OnPageTop
Send WriteHtmlTableBegin 'border="0" width="50%"'
Send WriteHtmlRowBegin
Send WriteHtmlCellHeader "Customer #: " 'Align="left"'
Send WriteHtmlCell Customer.Customer_Number 'Align="left"'
Send WriteHtmlRowEnd
Send WriteHtmlRowBegin
Send WriteHtmlCellheader "Customer Name: " 'Align="left"'
Send WriteHtmlCell (htmlEncode(Customer.Name)) 'Align="left"'
Send WriteHtmlRowEnd
Send WriteHtmlTableEnd
Send WriteHtmlTableBegin 'border="0" width="99%"'
Send WriteHtmlRowBegin
Send WriteHtmlCellHeader "Order#" 'align="left"'
Send WriteHtmlCellHeader "Order Date" 'align="left"'
Send WriteHtmlCellHeader "Sales Person" 'align="left"'
Send WriteHtmlCellHeader "Ship Via" 'align="left"'
Send WriteHtmlCellHeader "Order Total" 'align="right"'
Send WriteHtmlRowEnd

// WriteTableEnd is in Procedure OnPageBottom.

End_Procedure

Procedure OnBody
integer hDD
string sText
Get server to hDD
// Continue rows from OnPageTop

Send WriteHtmlRowBegin
Get AddRowIdLink OrderHea.Order_Number to sText
Send WriteHtmlCell sText 'align="left"'
Send WriteHtmlCell (HtmlEncode(OrderHea.Order_Date)) 'align="left"'
Send WriteHtmlCell (HtmlEncode(SalesP.Name)) 'align="left"'
Get File_Field_Current_Description of hDD FILE_FIELD OrderHea.Ship_via to sText
Send WriteHtmlCell (HtmlEncode(sText)) 'align="left"'
Send AddSubTotal 1 OrderHea.Order_Total
Send WriteHtmlCell (FormatNumber(OrderHea.Order_Total,2)) 'align="right" '
Send WriteHtmlRowEnd
End_Procedure

Procedure OnPageBottom
Number nTot
Send WriteHtmlCell "" 'colspan="4" align="right" '
Get SubTotal 1 to nTot
Send WriteHtmlCell (FormatNumber(nTot,2)) 'align="right" '
Send WriteHtmlTableEnd
End_Procedure

Function RunOrderReport RowId riCustomerRowId Returns RowId

Integer iStat

Set priConstrainRowId to riCustomerRowId

Get DoRunReport to iStat

Function_return (NullRowId())

End_Function

End_Object

Procedure SetHRefName string sName
Set psHRefname of oReport to sName
End_Procedure

Function RunOrderReport String sCustRec returns string

RowId riEndRec riCustRec

String sEndRec

Move (DeserializeRowId(sCustRec)) to riCustRec

Get RunOrderReport of oReport riCustRec to riEndRec

Move (SerializeRowId(riEndRec)) to sEndRec

Function_return sEndRec

End_Function

Set psDescription to "Order for Customer Report"
// define interface for object
Set pbAllowSaveNew to False
Set pbAllowSaveEdit to False
Set pbAllowDelete to False
Send RegisterInterface get_RunOrderReport "get_RunOrderReport" ;

'string sCustRec returns string' 'Run Order report'

End_Object

The ASP page that uses this report with the ASP page that is linked from the customer Report. The Customer_report.asp file would contain the following:

<%

Start = request("Start")

MaxRecs = 20

oCustomerReport.Call "msg_SetHRefName", "Orders_Report.asp"

EndRec = oCustomerReport.Call("get_RunCustomerReport", Start, MaxRecs)

%>

The Orders_report.asp page would look like this:

<html>

<head>

<meta http-equiv="Content-Type" content="text/html;charset=iso-8859-1">

<title>Order_report</title>

</head>

<body background="Images/Gray%20Weave.gif">

<h3>align="center">List Orders for selected Customer</h3>

<%

RowId = request("RowId")

EndRowId = oOrderReport.call("get_RunOrderReport", RowId)

%>

</body>

</html>

If you look at the report WBO, you will notice that the Order report supports a drill down to order details. The link to an order detail report would be handled in a similar fashion.

If you set priConstrainRowId property to null, it will disable the relates-to constraint relationship between the parent and child table.

Combined Techniques

Moreover, of course you can combine techniques. The following zoom page displays all of the information about the customer (like a standard zoom page) and then it runs a report listing all orders for the customer.

<html>
<head>
<meta http-equiv="Content-Type" content="text/html;charset=iso-8859-1">
<title>Customer Zoom</title>
</head>
<body background="Images/Gray%20Weave.gif">
<h3 align="center">Customer Detail Zoom</h3>
<hr>

<% ' Load the record into the DDO structure

RowId = Request("CustomerRowId")

Err = oCustomerReport.RequestFindbyRowId("Customer", RowId)

%>

<table border="0" width="99%">

<tr>
<th valign="top" align="left" width="20%" bgcolor="Silver">Field Name</th>
<th align="left" bgcolor="Silver">Value</th>
</tr>
<tr>
<th align="left" valign="top" width="20%">Customer Number</th>
<td align="left"><%=oCustomerReport.ddValue("Customer.Customer_Number",DDESC)%></td>
</tr>
<tr>
<th align="left" valign="top" width="20%">Customer Name</th>
<td align="left"><%=oCustomerReport.ddValue("Customer.Name",DDESC)%></td>
</tr>
:
:
</table>

<hr>

<% EndRec = oOrderReport.Call("get_RunOrderReport", RowId) %>

</hr>

<form action="Customer_report.asp" method="POST">
<p><input type="submit" value="Back" OnClick="history.back()">
<input type="submit" value="New report">
</p>
</form>

</body>
</html>

See Also

Web Reporting


SubHeaders, SubTotals and Breakpoints

Note that the method for supporting breakpoints is different than in previous report objects.

Breakpoints

The Web report object allows you to create 9 levels of headers and subheaders. Each level is referred to as a breakpoint. Typically a breakpoint occurs on a field and that field is segment of the reporting index. For example if we were running a report on Orders with an index that was Region Id x Customer Id x Order Id, then you could have the following breakpoints:

Breakpoint 1: Region Id

Breakpoint 2: Customer Id

or

Breakpoint 1: Region Id

or

Breakpoint 1: Customer Id

or

No breakpoints

Each time a new breakpoint is triggered, the event OnSubtotalx is called where "x" is the numeric value of the breakpoint, then the event OnSubHeaderx is called. These events do nothing by default. You can use them to do any kind of header/total processing and display required.

Breakpoints are created by augmenting the OnInitBreakpoints message and listing the Breakpoint check message that should be called for each breakpoint. You must then also create the breakpoint check function for each breakpoint.

Typically, the breakpoint check message will be named Break1, Break2, etc. although the choice of name is yours. This message should return that value that you wish to test for change. This is important. You do not perform the breakpoint test in this function. You simply return the value that should be tested. Most often, the returned value will be a file.field value

For example, assume that an order report’s index is Customer Id x Order Id and that you wish to break on each customer. You would need to create the following code:

Function Break1 Returns string
function_return Customer.Customer_Number
End_Function

Procedure OnInitBreakpoints
Send RegisterBreakpoint get_Break1
End_Procedure

In this sample, assume that an order report’s index is region Id x Customer Id x Order Id and that you wish to break on each region and each customer within the region. You would need to create the following code:

Function Break1 Returns string
function_return Regsion.Id
End_Function

Function Break2 Returns string
function_return Customer.Customer_Number
End_Function

Procedure OnInitBreakpoints
Send RegisterBreakpoint get_Break1
Send RegisterBreakpoint get_Break2
End_Procedure

You can also create more complex calculated breakpoints. Assume that a customer report is listed in customer name order and you wanted to break on when the first letter of the customer name changes. You could do this as follows:

Function Break1 Returns string
function_return (uppercase(left(Customer.name,1)))
End_Function

Procedure OnInitBreakpoints
Send RegisterBreakpoint get_Break1
End_Procedure

You can also create condition breakpoints. In this sample we only want to break on customer name if the report is ordered by customer name. Assume the index 1 is Customer_Number and that index 2 is Customer_name x Customer_number. We only wish to break if the order is 2.

Function Break1 Returns string
function_return Customer.name
End_Function

Procedure OnInitBreakpoints
Integer iOrdering
Get piOrdering to iOrdering // the index
If (iOrdering=2) ;
Send RegisterBreakpoint get_Break1
End_Procedure

Totals and SubTotals

Messages exist that make it easy to manage totals and sub-totals within a report. A report total accumulator array is maintained for each report. Methods exist that allow you to add values to an accumulator, display a value from an accumulator and to clear the accumulators. Each accumulator is identified by an integer number. You may assign any sub total to any accumulator level.

The sub total messages are:

  • Send AddSubTotal iLevel nAmount

  • Send ClearSubTotal iLevel

  • Send ClearAllSubTotals

  • Get SumSubTotal iLevel to nAmount

  • Get SubTotal iLevel to nAmount

Send AddSubTotal iLevel nAmount

This message adds the passed amount (nAmount) to accumulator level iLevel. This is typically used in a body or header event if you need to track an amount for a total or subtotal. The total is most frequently displayed with the SubTotal function.

The following example shows to totals maintained in a report body.

Procedure OnBody
Send WriteHtmlRowBegin
Send WriteHtmlCell OrderHea.Order_Number 'align="left"'
Send WriteHtmlCell (HtmlEncode(OrderHea.Order_Date)) 'align="left"'
Send WriteHtmlCell (HtmlEncode(SalesP.Name)) 'align="left"'
Send WriteHtmlCell (FormatNumber(OrderHea.Order_Total,2)) 'align="right" '
Send WriteHtmlRowEnd
// keep track of order total in acc 1
Send AddSubTotal 1 OrderHea.Order_Total
// keep running count of orders in in acc 2
Send AddSubTotal 2 1
End_Procedure

Send ClearSubTotal iLevel

This message clears the total for the passed accumulator level. Normally, you will not need to use this. If you wish to display (or process) a sub-total you can use the message get SubTotal which returns the current accumulated value and clears the accumulator.

Send ClearAllSubTotals

This message clears all of the accumulator totals. You should never need to use this. When a report is started, all totals are automatically cleared (by calling this message).

Get SubTotal iLevel to nAmount

This message returns the value of current accumulator and then clears it. This is very useful when you wish to display sub-totals in a subtotal. The following example, displays the total from accumulator 1, clears it, and then adds the sub-total to another accumulator (4).

Procedure OnSubTotal1
Number nTot
Send WriteHtmlCell "" 'colspan="4" align="right" '
Get SubTotal 1 to nTot // get value and clear level
Send WriteHtmlCell (FormatNumber(nTot,2)) ' align="right" '
Send AddSubTotal nTot 4
Send WriteHtmlTableEnd
End_Procedure

Get SumSubTotal iLevel to nAmount

This message returns the value of current accumulator without clearing it. This is needed if you wish to process a total without clearining it.

The following example, displays the total from accumulator 1, clears it, and then adds the sub-total to another accumulator (4). It does the same thing as the SubTotal example requiring a few more steps

Procedure OnSubTotal1
Number nTot
Send WriteHtmlCell "" 'colspan="4" align="right" '
Get SumSubTotal 1 to nTot // get value, don’t clear
Send ClearSubTotal 1 // now clear it
Send WriteHtmlCell (FormatNumber(nTot,2)) 'align="right" '
Send AddSubTotal nTot 4
Send WriteHtmlTableEnd
End_Procedure

Sample

The following sample shows how breakpoints, sub-headers, and sub-totals all used in a report.

Object oReport Is A cWebReport

Set piOrdering to 2 // Customer x Order number

Function Break1 Returns string

function_return Customer.Customer_Number

End_Function

Procedure OnInitBreakpoints

Send RegisterBreakpoint get_Break1

End_Procedure

Procedure OnSubHeader1

Send WriteHtmlTableBegin 'border="0" width="50%"'

Send WriteHtmlRowBegin

Send WriteHtmlCellHeader "Customer #: " 'Align="left"'

Send WriteHtmlCell Customer.Customer_Number 'Align="left"'

Send WriteHtmlRowEnd

Send WriteHtmlRowBegin

Send WriteHtmlCellheader "Customer Name: " 'Align="left"'

Send WriteHtmlCell (htmlEncode(Customer.Name)) 'Align="left"'

Send WriteHtmlRowEnd

Send WriteHtmlTableEnd

Send WriteHtmlTableBegin 'border="0" width="99%"'

Send WriteHtmlRowBegin

Send WriteHtmlCellHeader "Order#" 'align="left"'

Send WriteHtmlCellHeader "Order Date" 'align="left"'

Send WriteHtmlCellHeader "Sales Person" 'align="left"'

Send WriteHtmlCellHeader "Order Total" 'align="right"'

Send WriteHtmlRowEnd

End_Procedure

Procedure OnBody

Send WriteHtmlRowBegin

Send WriteHtmlCell OrderHea.Order_Number 'align="left"'

Send WriteHtmlCell (HtmlEncode(OrderHea.Order_Date)) 'align="left"'

Send WriteHtmlCell (HtmlEncode(SalesP.Name)) 'align="left"'

Send WriteHtmlCell (HtmlEncode(OrderHea.Ship_via)) 'align="left"'

Send WriteHtmlCell (FormatNumber(OrderHea.Order_Total,2)) 'align="right"'

Send AddSubTotal 1 OrderHea.Order_Total // total for order

Send WriteHtmlRowEnd

End_Procedure

Procedure OnSubTotal1

Number nTot

Get SubTotal 1 to nTot // total for customer

Send AddSubTotal 2 nTot // total of all customers

Send WriteHtmlCell "" 'colspan="3" align="right" '

Send WriteHtmlCell (FormatNumber(nTot,2)) 'align="right" '

Send WriteHtmlTableEnd

End_Procedure

Procedure OnPageBottom

Number nTot

Get SubTotal 2 to nTot

Send WriteHtmlTableBegin 'border="0" width="99%"'

Send WriteHtmlCell ("Total Orders: " + FormatNumber(nTot,2)) 'align="right" '

Send WriteHtmlTableEnd

End_procedure

End_Object

See Also

Web Reporting


Writing Runtime Configurable Reports

It is possible to write single reports that do many different things. By setting various properties and the proper use of If logic you can use the same report to:

  • Display a constrained report for one parent or a report for all parents.

  • Reports based on different indexes (just change piOrdering).

  • Reports based on different selection criteria.

  • Reports that print all records or are limited by piMaxCount.

  • Reports that haven't a different number of breakpoints, of different type of breakpoints.

As you create more complex reports make sure that each report sets any properties that another variant of the same report might have set. For example, if you use the same report to print constrained and unconstrained make sure you remember to set priConstrainRowId to null in the unconstrained report. If you want the same report to print all records or a limited number of records make sure you remember to set piMaxCount to 0 on the unlimited report.

At some point the work required to create an all in one report becomes greater than the work required to create multiple reports. You have the flexibility to work either way.

See Also

Web Reporting


Debugging your Web Application

Debugging Your Web Applications

This section will illustrate:

  • How to debug ASP scripting code and Visual DataFlex code in VDF Web Applications.

  • Where to find more information than meets the eye if you encounter problems with Web Applications .

  • How to deal with common Web Application errors.

Contents

Debugging Techniques

Visual DataFlex Web Application Basics

Types of Code Debuggers

Using DebugHelp

Logging Your Own Events to the VDF Web Application Event Log

A Debugging Scenario

Log Files

Visual DataFlex Web Application Event Log

Windows Event Viewer

Common Error Messages

HTTP Error 404 'File not Found'

ASP Error '80004005' Unspecified Error

Microsoft VBScript compilation (0x800A03F6)

The page cannot be displayed HTTP 500.100 - Internal Server Error - ASP Error

Tips

Web Application Debugger Limitations

Use Option Explicit to Force Variable Declarations in ASP code

Install Microsoft Internet Information Manager on Windows NT Workstation

Terms

Additional Resources


Visual DataFlex Web Application Basics

A Visual DataFlex Web Application consists of 2 areas where coding is done: ASP and Visual DataFlex. When an ASP page that is part of a Visual DataFlex Web Application is accessed from a browser, code execution starts on the ASP side. Then, code on the Visual DataFlex side is called from ASP scripting code.

Here is a brief sample of what happens when a Visual DataFlex Web Application report is called:

Top of page: (static HTML)

//print title of report

Middle of page: (ASP script code)

//call Visual DataFlex function that runs report

//(Visual DataFlex report writes the report: a list of customers)

Bottom of page: (static HTML)

//print footer of report

The basic order of code execution is this:

  1. An ASP page is accessed in a browser.

  2. The ASP page code is executed from top to bottom, just as normal HTML is executed.

  3. If script code is encountered, the ASP script code executes, including making calls to Visual DataFlex functions.

  4. The Visual DataFlex functions execute.

  5. The ASP page code execution continues.

ASP script code can do a lot of other things besides making calls to Visual DataFlex programs, but this is how Visual DataFlex Web Application code is called and executed.

See Also

Debugging Your Web Applications


Types of Code Debuggers

Since a Visual DataFlex Web Application has 2 areas in which programming code is created, the Visual DataFlex side and the ASP side, it is important to have the ability to debug code on both sides:

Visual DataFlex Code

Visual DataFlex has an integrated debugger in the Studio which can debug Visual DataFlex code, including Visual DataFlex code in Visual DataFlex Web Applications.

ASP Script Code

You should install a script debugger to enable you to debug code on the ASP side. We do not consider this optional for developing Web Applications!

If you have certain Microsoft development tools installed, such as Visual Studio or Visual Studio .Net, you may already have one or more script debuggers installed. The Microsoft Script Debugger is available as a free download from Microsoft. See the Additional Resources section for more information.

We will teach you how to get started using both debuggers, but you should plan to spend time learning both debuggers as expertly as possible.

See Also

Debugging Your Web Applications


Using DebugHelp

An include file named DebugHelp.inc is added to each Web Application’s AppHtml\inc directory. This file allows you to turn on a "trace" mode, which will show all request data submitted to your ASP page by your browser. This is a very useful feature. It lets you see what data is actually being submitted to a server page. Often you will discover that a source of an error is that data being passed back to the server is different to what you expect. Also, this debugging feature is a great learning tool – it shows you how the POST/GET process works.

When trace debugging is enabled, all HTTP request information sent to a server page will be displayed as part of this server’s page HTML output. In other words, you will see the request information in your browser. Here is an example of what that output will look like:

----DEBUG INFORMATION----

content_length = 627

request_method = POST

Customer__RowId= 010000

customer__customer_number= 1

customer__name= Data Access Worldwide

customer__address= 14000 SW 119 Ave

customer__status= Y

customer__city= Miami

customer__state= FL

customer__zip= 331866017

customer__phone_number=

customer__fax_number=

customer__email_address=

customer__credit_limit= 6320

customer__purchases= 10640

customer__balance= 10640

CUSTOMER__COMMENTS= Innovative software company & makers of Visual DataFlex...

ChangedStates=

findnext= >

Index= 1

Querystring =

----END DEBUG INFORMATION----

Adding DebugHelp to your ASP page

If you created your ASP page using the wizards, the code required to display request information has already been added to your page. If you are creating this code manually you will need to add two lines of code to your ASP page after the <body> HTML tag as follows:

<body>

<% ' DebugMode =1 ' uncomment this for page get/post debug help %>

<!-- #INCLUDE FILE="inc/DebugHelp.inc" -->

Look at the Customer.asp file in the Order11 sample application for an example of this.

Enabling DebugHelp in your ASP page

To enable the debug help feature you need to set the VbScript variable DebugMode to 1.

Find line of code that reads <% ' DebugMode =1….%> and remove the comment. The line would look like the following:

<% DebugMode =1 ' uncomment this for page get/post debug help %>

Using the DebugMode Variable for Conditional Debug Code

Additionally, you can use the DebugMode variable to create pockets of conditional debug code within your application. You do this by creating an "If" statement block that tests for DebugMode as follows:

<% If DebugMode>0 then %>

....place your debug asp code here

<% end if %>

Here is an example of how this might be used:

<% If DebugMode>0 then %>

Test code start<br>

The current customer number is

<%=oCustomer.ddValue("Customer.Customer_number") %>

Test code end<br>

<% end if %>

If debug mode is enabled, the following would be displayed in your browser page:

Test code start

The current customer number is 123

Test code end

When debug mode is disabled, you would not see this code.

Once debug mode is enabled, it will remain enabled until the session ends, or until the mode is explicitly turned off. This is very useful. Once debug mode is enabled, all pages that use the DebugHelp.inc will display debug information.

You can and should experiment with debug mode by running the WebAppSample10 application.

See Also

Debugging Your Web Applications


A Debugging Scenario

To see how to debug a Visual DataFlex Web Application, and what happens during a Visual DataFlex Web Application event, let's work through the scenario of saving a customer record in the Web Order Sample application.

Setup the Scenario

  • Open the Visual DataFlex Studio and open the Order11 workspace.

  • Open the Web Order Sample application.

  • Debug-run the program.

  • Once the application is running, switch to the browser and click on the Login (for edit rights) page.

  • Login using the username and password provided on the page. Logging in here enables saving and deleting of records in this sample application.

  • Now click on the Customers page.

  • Click on the > button to find the first record in the Customer table.

When the Save button on the Customers page is clicked, code execution begins in the ASP page. So, the first place to see what is happening is in the ASP code:

  1. In the Visual DataFlex Studio, select Open Web Markup from the Open Component toolbar combobox and open the Customer.asp file.

  2. Search for "Save" in Customer.asp. Stop when you reach this code:

if Request("save")<>"" then

This code checks whether the Save button has been clicked. We want to stop program execution when this happens.

  3. Add a stop statement right after the line of code above. The resulting code should look like this:

if Request("save")<>"" then

stop

oCustomer.call "set_pbReportErrors", 0

  4. Click on the Save button on the Customer page.

When the application reaches the stop statement, the application will break and start the Script Debugger. The Script Debugger will display the Customer.asp page and execution will be stopped on the line with the stop statement.

Note

If the Script Debugger does not start, the application never got to this line of code. In this case, you can place a breakpoint on the first line of the ASP page, then step through each line of code to determine what is happening.

  5. In the Script Debugger, Step Over lines of code until you reach this line:

err = oCustomer.RequestSave("Customer")

This line calls the RequestSave function in the Visual DataFlex code of the application. The next step is to stop execution in the Visual DataFlex code when the call gets to the Visual DataFlex side of the application.

From the Visual DataFlex documentation for the RequestSave function, we know that it calls the DoRequestSave event. We will place a breakpoint in this event in the Visual DataFlex code. This event is not in the local code of most Visual DataFlex Web Applications, but in the global packages distributed with Visual DataFlex that are compiled as part of the application. We need to determine where, so we can place the breakpoint.

  6. In the Visual DataFlex Studio, search for text in multiple files.

  7. Type "Function DoRequestSave" into the Text to find form.

  8. Choose "Global Source" from the "Workspace Zone" comboform.

The search returns RemoteEntryMixin.pkg.

  9. In the Visual DataFlex Debugger, select RemoteEntryMixin.pkg from the source code comboform.

  10. Search for "Function DoRequestSave". Stop when you reach this code::

Function DoRequestSave String sFileName returns integer

  11. Place a breakpoint on the line "Get pbAllowSaveNew to bAllowSaveNew".

  12. If you are new to the Visual DataFlex Debugger, click on the blue dot to place the breakpoint. The blue dot should turn red to indicate that the breakpoint is set.

Now we can return to the Script Debugger, where the execution of the ASP code is still stopped at the oCustomer.RequestSave call.

  13. In the Script Debugger, Run the program to continue execution. A message box will pop up telling you the Visual DataFlex Debugger has encountered a breakpoint.

  14. Click Ok on the message box and switch to the Visual DataFlex Debugger.

The debugger is stopped at the breakpoint in DoRequestSave in RemoteEntryMixin.pkg. This tells us the program has properly executed the call from the ASP code to the Visual DataFlex code.

Another method of checking whether DoRequestSave is called and what is being sent to it is to intercept this function at the WBO code level. This will allow us to place a breakpoint right in the WBO code instead of the global product package code. Intercepting the function at the WBO level could also be used to customize the save process.

  15. Close the browser running the Order11 application. Doing so will also cause the Visual DataFlex Debugger to close.

  16. In the Visual DataFlex Studio, open the Customer.wo.

  17. To intercept DoRequestSave at the WBO level, add the following code to the code of object oCustomer, right below the end of Function RunCustomerReport:

Function DoRequestSave String sFilename Returns Integer

Integer iVoid

Forward Get DoRequestSave sFilename To iVoid

Function_Return iVoid

End_Function // DoRequestSave

  18. Compile and debug-run the program. Follow the same steps as above to login, go to the Customers page and find a customer record.

  19. In the Visual DataFlex Debugger, open the Customer.wo file and search for "Function DoRequestSave".

  20. Once you have found the augmented code we placed in this WBO, place a breakpoint on the line "Forward Get DoRequestSave sFilename To iVoid".

  21. Click on the Save button on the Customer page.

  22. When the Script Debugger stops again at the stop statement, run the program to continue execution. A message box will pop up telling you the Visual DataFlex Debugger has encountered a breakpoint.

  23. Click Ok on the message box and switch to the Visual DataFlex Debugger. The debugger is stopped at the breakpoint in DoRequestSave in Customer.wo.

See Also

Debugging Your Web Applications


Visual DataFlex Web Application Event Log

This log contains application-specific error messages.

To view the Visual DataFlex Web Application Event Log, follow these steps:

  1. In the Visual DataFlex Web Application Administrator, expand the TreeView of web applications and select the application in question.

  2. Expand the tree for the application and select the Event Log.

Tip

You may see a lot of "Session Started" and "Session Closed" entries in the Event Log. If you do not want to log each of these events, and instead only want to log error messages from your web application, do the following:

  1. Right-click on your application and select Properties.

  2. Uncheck the "Log all Access to the Web Application" checkbox.

  3. This will stop all events from being logged, but will still log errors.

  4. Make sure the Maximum log entries is set to 0 for unlimited entries.

See Also

Debugging Your Web Applications


Windows Event Viewer

This log contains error messages that are not specific to any particular Web Application, but are more systemic to Visual DataFlex Web Applications, such as invalid registration codes. Here you will also see error messages about other applications that may affect Visual DataFlex Web Application Server, such as Internet Information Server errors.

To view the Windows Event Viewer's Application Log:

  1. Start > Control Panel > Administrative Tools > Event Viewer.

  2. Select Application in the TreeView.

You can also launch the Windows Event Viewer from the Visual DataFlex Web Application Administrator's Tools menu.

See Also

Debugging Your Web Applications


Common Error Messages

Here are steps to analyzing and solving some of the most common Web Application errors. Please also see the Additional Resources section.

  • HTTP Error 404 'File not Found'

  • ASP Error '80004005' Unspecified Error

  • Microsoft VBScript compilation (0x800A03F6)

  • The page cannot be displayed HTTP 500.100 - Internal Server Error - ASP error

See Also

Debugging Your Web Applications


HTTP Error 404 'File not Found'

This error means that the browser could not show the requested page. The error is also often 'Page not Found' or 'Object not Found', but as long as the error code is 404, the cause is the same. This error code is returned from the server that is supposed to serve the page, rather than the browser itself. The the most 'typical' reason why you might see this error when working with Visual DataFlex Web Application Server is that the file you are trying to access (usually default.asp) is not listed as a default document for the virtual directory.

To resolve this, do the following:

  • Verify that you are actually accessing the right document (check the URL).

  • Verify that the correct default documents are set up for the virtual directory (see default document section for details).

See Also

Common Error Messages


ASP Error '80004005' Unspecified Error

error '80004005'

Unspecified error

/VirtualDirectoryName/global.asa, line 15

This error can occur for any number of reasons. There are a number of ways of obtaining more meaningful information when this error occurs.

  1. Check the Windows Event Viewer.

  2. Check the event log for the VDF Web Application in question.

  3. Make sure there is a program filled in (and it is the correct program) for the Web Application in the VDF Web Application Administrator.

  • Open the VDF Web Application Administrator

  • Expand the TreeView of applications and select the application in question

  • Right-click and choose Properties

  • Make sure the correct program is entered into the Filename window

  • While here, also make sure that the Disable Web Application checkbox is not checked

  4. Debug-Run the Application

  • There might be an error message or other Windows popup dialog that may be hidden when running the application in normal mode using the VDF Web Application Server. When running in debug mode, you will see these types of things.

  • You may be able to stop the Application's execution in the debugger and see where the program is "stuck".

See Also

Common Error Messages


Microsoft VBScript compilation (0x800A03F6)

Microsoft VBScript compilation (0x800A03F6)

'End' expected

/packing/inc/DebugHelp.inc, line 14

You will sometimes encounter this error pointing to one of the include files provided with Visual DataFlex (typically DebugHelp.inc). Most likely this is caused by some other scripting error in your ASP code, such as a missing 'end if', and the error is only 'caught' in the include file. Your best bet for debugging this problem is usually to double-check the last area of ASP code you worked on.

See Also

Common Error Messages


The page cannot be displayed HTTP 500.100 - Internal Server Error - ASP error

This error can be caused by an incorrect firewall configuration, particularly with firewall software. To test this, you could try to temporarily disable the firewall, then see if the error subsides. If so, re-enable your firewall and configure it to allow access to this Web Application and/or Web server.

This error is often caused by a bug in Crystal Reports version 8.0. If you are running that version, please take these steps:

  1. Download and install the patch for this Crystal Reports bug available from http://support.businessobjects.com/communityCS/FilesAndUpdates/scr8_webregfix.exe.asp

  2. Reinstall Visual DataFlex 10. You can reinstall over your existing installation without having to uninstall it first.

See Also

Common Error Messages


Web Application Debugger Limitations

The Visual DataFlex Web Application Server Debugger is a separate program from the Visual DataFlex Web Application Server, which runs on a Windows Server as a Service. As a result of this, the following are not supported:

  • Debugging with Process Pooling

When you enable Process Pooling in a Visual DataFlex Web Application, the Application will run using Process Pooling in the Visual DataFlex Web Application Server, which supports process pooling, but not in the Visual DataFlex Debugger, which does not support process pooling. You can still debug your application if Process Pooling is enabled, it just won't run in the Debugger as a Process Pooled session.

  • Remote Debugging

The Visual DataFlex Debugger only supports debugging applications locally on the same machine. Remote debugging is not supported with either Windows or Web applications. However, you can run the application on your machine and connect to a database on a separate machine. This is probably the most common configuration for Windows applications. This involves setting the various paths in the workspace file so that it points to the remote machine. Often this is accomplished by using relative pathing and referencing the .exe file and the workspace located on a separate machine.


Use Option Explicit to Force Variable Declarations in ASP code

By default, variables in VBScript do not need to be declared. This can easily cause problems that go undetected during development, for example, an accidental change of a variable name will not be trapped as an error.

The option explicit statement causes declaration of errors for undeclared variables. We highly recommend always using this option.

Example

option explicit

dim Error

iError = oCustomerWBO.RequestSave "Customer"

In this example, the last line would generate a VBScript error message, because the declared variable Error does not match the used variable iError:

Microsoft VBScript runtime error '800a01f4'

Variable is undefined: 'iError'

/VirtualDirectoryName/FileName.asp, line ###


Install Microsoft Internet Information Manager on Windows NT Workstation

If you are running Windows NT Workstation, the Microsoft Internet Information Manager is not installed. This is an excellent tool that you should install. To install this tool, check the following options during the Windows NT 4 Option Pack Installation (or reinstallation):

  • Leave all the default options as they are.

  • In addition, check the following:

  • "Personal Web Server" > click on "Show Subcomponents" and check "Internet Service Manager".

  • "Microsoft Management Console"


Terms

Here are some brief explanations of terms that are important when working with Visual DataFlex Web Applications. You are expected to be familiar with some of the terms that are not explained here (i.e. HTML, URL).

Active Server Pages (ASP)

Software technology by Microsoft that allows execution of HTML code with embedded scripting.

Internet Information Server (IIS)

HTTP server software by Microsoft, which allows, among other things, execution of ASP pages. The minimum IIS version requirement for Visual DataFlex Web Application Server is 4.0.

Default Documents

Any virtual directory used by IIS can have a set of HTML and/or ASP pages listed as default documents. This means that, when the URL of the virtual directory is typed into the browser's location bar without specifying a page in the virtual directory, the server automatically looks for any default documents specified and displays the first default document found in the browser.

For example, when launching the Order11 sample application, you typically access the URL http://localhost/DAW.Examples.Order11, but http://localhost/DAW.Examples.Order11/default.asp is actually loaded in your browser.

Here is how to configure default documents for a virtual directory:

  1. Start > Control Panel > Administrative Tools > Internet Information Services

  2. Expand Servers + the Server name your application is hosted on + Web Sites + Default Web Site

  3. Select the virtual directory for your application

  4. Right-click and select Properties

  5. Choose the Documents tab

  6. Make sure that "Enable Default Document" is checked

  7. Make sure that the correct default documents are listed

Virtual Directory

A Virtual Directory maps a physical folder on a disk drive (the ASP/HTML folder of a Web Application) with a URL. It provides for an access method to a Web Application on a Web Server.

For example, the virtual directory for the Order11 sample application is DAW.Examples.Order11. The physical folder for this virtual directory is C:\Program Files\Visual DataFlex 10\Examples\Order11\AppHtml.

When accessing it on the local machine (the machine you are currently working on), the Web Server is usually be accessed via http://localhost. The combination of the server name and the virtual directory name results in the URL to your application: http://localhost/DAW.Examples.Order11.

Web Browser Object (WBO)

This is the most common programming component on the Visual DataFlex code side of a WebApp. A WebApp is usually made up of one or more WBOs, each of which contains a set of DataDictionaries, methods and child objects.

See Also

Debugging Your Web Applications


Additional Resources

  • Visit the Visual DataFlex site to learn more about Visual DataFlex:

  • Visit the Visual DataFlex Support page for information about all of our support offerings, including free support offerings, such as the Technical Knowledge Base, White Papers and Peer Support Newsgroups:

  • Microsoft Script Debugger for Windows NT, 2000 and XP, free download from Microsoft:

http://www.microsoft.com/downloads/details.aspx?FamilyId=2F465BE0-94FD-4569-B3C4-DFFDF19CCD99&displaylang=en

  • ASP Error Codes, Microsoft Knowledge Base article 294271:

http://support.microsoft.com/default.aspx?scid=http://support.microsoft.com:80/support/kb/articles/q294/2/71.ASP&NoWebContent=1&NoWebContent=1

See Also

Debugging Your Web Applications


Troubleshooting Web Applications

Check This List First

  • Understand common problems and their solutions.

  • See the questions that developers ask most.

  • Understand the Global.ASA file

  • Run through an Application Checklist

  • Know what is in the Event Logs

  • Log your own events for more information

  • Check these specific items

  • Can you directly run the application (outside of a browser) without errors? Verify this by running the application from within the Studio.

  • Is your ASP working? Try loading one of the sample ASP pages from Microsoft that installed with your server.

  • Is your Web Application Server running? Bring up Control Panel | Services Web Application Server and look at the Status column. If it doesn't say Started, it isn't running.

  • Is your Web Server running and working? Try to run the Web samples.

Understand How to Fit the Parts and Pieces

When troubleshooting a problem, it is important to understand how the parts of the Web Application Server work together. This is covered in the Requirements to Run A Web Application . It may be beneficial to review this section.


Problems and Solutions

Problem

The Event Log contains Web Application errors:

Event Log:

208 Session denied, Web Application is disabled

Your Web Application is disabled. Load the Web Application administrator and find your Web Application. If it is disabled, you can enable it by selecting properties and un-checking the "Disable Web Application" checkbox.

Event Log: | 305 Session failed to initialize
 | 300 Invalid Web Application wo1
 | 100 Web Application wo1 started

The Web Application defined in Global.asa is not defined as a Web Application within the Web Application administrator. In the above example, the name "wo1" cannot be found within the administrator. The name of the Web Application service on the Web Application Server Administrator must be the same as your workspace – the name that appears in the caption bar within the studio. Load the Web App administrator and create a Web Application with the proper name, or, if an existing application has the wrong name, rename it within the administrator.

Event Log: | 305 Session failed to initialize
 | 312 Session failed to initialize. Error: Maximum concurrent sessions for development license reached
 | 100 Web Application wo started

You are running a Web Application Server development license. Only two sessions are allowed to run at any time. Run fewer sessions or upgrade to a real deployment Web Application Server.

Problem

The Web Application Server installation hangs at 26% or 33%.

Solution

This can happen if you are installing on a Windows NT machine that already has the Web Application Server running as a Service.

To ensure there is no such service already running See if you can uninstall the Web Application Server from Control Panel - Add/Remove Programs. If no uninstall for the Web Application Server is listed there, do the following:

  1. Open Control Panel – Services.

  2. See if Web Application Server is listed as a Service here.

  3. If it is listed, remove it, turn it off using the "Stop" button.

  4. Run the Web Application Server installation again. It should be able to install over the existing service now that it is not running.

If you have Web Application Server already installed, uninstall it before proceeding with a new installation. See the Installation & Environment Guide for detailed information.

Problem

When trying to set your \AppHtml directory to a virtual directory on your NT workstation, you do not see the WebShare tab page.

Solution

The WebShare tab is only available if you have Option pack 4 properly installed. Reinstall Option pack 4, making sure that the IIS or PWS checkbox is selected.

Problem

You see a "Data Missing" error message when clicking on Back or Forward buttons in browser.

<or>

You see a message that posted data is missing or has expired from cache when trying to view the source code of an HTML page.

Solution

Most likely the cache settings in your browser are set to zero or too low. Try setting memory cache to at least 2048 KB and disk cache to 5000 KB.

Problem

I am using a Notebook PC with Win98 and just installed the DataFlex Web Application Server wizards without a real server. Whenever I create a Web Page it contains some characters, I don't know why.

Solution

This is not very strange at all, in fact it's quite normal. You're trying to execute/view an ASP file through a non-ASP supported web server (such as Personal Web Server on Win 98). You need NT Workstation with Peer Web Services or NT Server with Internet Information Server.

The result you see is simply the ASP code, because your web server has no knowledge of ASP server side scripts; it just puts the script in the fields. The web server simply doesn't know what to do with the ASP script.

Problem

What name should be used in the browser?

Solution

The alias that you enter when you created the virtual directory must match the name you use in the browsers. (e.g., localhost\Order11).

Problem

The session will not start.

Solution

Check the NT event log.

Problem

The message "Session failed to initialize" displays.

Solution

You are having an initialization problem. This could mean several things. Most likely, the .exe file is not found, or some other Visual DataFlex problem is occurring. This error message is sometimes combined with other error messages stating more clearly why it failed to initialize. If the NT event log does not make the problem more clear, then at this point, you need to start the debugging process.

Problem

Program does not run.

Solution

  1. Make sure that your Web Server is running IIS and Active Server Pages. Try running some of the sample ASP pages provided by Microsoft and our ASPTest10 Example.

  2. Is an error message returned to Browser? Note this error and see if it matches one of the errors listed in this section.

  3. Check the NT Event log. Look at the event’s for Application (select Application from the Log menu). Note the error number and the error message in the log. This step is very important. Always check the event log!

  4. Check the Web Application Server Administrator:

  • First check if it is running – it is running, if the caption bar reads "Service running". If it is not started, start it.

  • Next, find the application in the list of applications and make sure that exists and is running.

  • Open the application’s property dialog and confirm the following:

    Make sure the application is enabled – The disabled checkbox should be cleared.

    Make sure that the application name and path is correct. It should always point to the program directory and be named "WebApp.exe". A typical name would be "D:\MyApps\App1\Programs\WebApp.exe."

  • Look at the Application's event log. Note any errors or messages that appear.

  5. Make sure your Web Application can run in debug mode. Load the studio and press the "Compile and Debug" button.

  6. Make sure that you have defined a virtual directory for your Application and that you are pointing to the correct physical directory. The virtual directory must point to the "AppHtml" directory in your application area. A typical physical directory would be "D:\MyApps\App1\AppHtml"

Problem

If your Error looks like the following:

Active Server Pages error '8002802b'

Create object failed

?

An error occurred while creating object 'WebAppServerSession'.

Solution

Your Web Application Server or Studio may not be properly installed and/or registered. Check the event log for more detailed information.

Problem

If your Browser displays something like this:

Microsoft VBScript runtime error '800a01b6'

Object doesn't support this property or method: 'RequestSave'

/wo/customerentry.asp, line 41

Solution

You are attempting to call a method that the object does not support. Load the ASP page and check your spelling. The above example should have read "oCustomerEntry.Request.save" instead of "oCustomerEntry.Reqeest.save".

Problem

If your Browser displays something like this:

Call Error: get_xpeFieldMultiUser

Solution

You are using the Call interface to call a method that is not supported in the WBO. Check the following:

  1. Is the method name correctly typed in your ASP page (e.g., sLoginName = oUserLogin.Call("get_LoginUser", sID) )? Does it contain the proper get_ or msg_ prefix?

  2. Is the name defined in your Web Application interface? You can check this by test running the application within the studio, clicking on details, and checking that the interface name exists. If it does not:

  • Perhaps the name is misspelled in the WBO.

  • Perhaps you did not publish the method.

Remember that you must add the msg_ and get_ prefix when accessing methods within your ASP page, but that you should not include these prefixes when creating the WBO procedure or function. Functions will always be prefixed with get_ and procedures will always be prefixed with msg_.

See Also

Troubleshooting Web Applications


Frequently Asked Questions (FAQ)

Question

What creates the Web Application process name and, when in global.asa, are there different events that will change this name?

Answer

When a new application is created, the Studio creates an application entry in the Administrator. Or, you can do this manually. By default, the name of the application will be the same name as your workspace. If you are planning to use the Studio as your development environment, the name of the workspace must be the same as the name of your Web Application. The reason for this is that the studio plugs this name into your Global.asa file every time it compiles a program. Therefore, if you change the name in administrator and change it in Global.asa, the global.asa change will get overwritten the next time you do a Studio compile.

Question

What happens if I do not want my Web Application name to match the Workspace name?

Answer

Things will go wrong. Don’t risk it!

Question

What about the Virtual Directory name?

Answer

The Virtual directory name can be any name you like. We suggest that you use the same name as your workspace, because it makes it easy to remember. However, you can rename this at any time you like. No other changes are required.

Question

What if, for some business reason (e.g., after deployment or during the development process), developers need to change one of these names, how can they do this and not break the application?

Answer

There are two issues at work here. Some changes will be wiped out by the Studio during development, which will create confusion. Other changes can be made during deployment.

Studio issues are:

  1. The name of the Visual DataFlex application must be WebApp.src.

  2. The name of the Web Application (defined in the Administrator) must be the same name as your Workspace.

  3. The name of your ASP objects must be the same as the name of your WBO objects. If you change one, you must change the other.

  4. You can call the virtual directory anything you like.

  5. Don't manually try to change values in Global.asa - they get changed back during compilation.

  6. The other issues concern after you are done with the Studio (or if you are not using it). There’s nothing to stop you creating valid, albeit confusing, applications as follows:

  7. You can name the Virtual Directory anything you want.

  8. You can rename WebApp.exe to another name. When you do this, you must enter the Administrator and change the name in the property sheet (you are changing the name of the Visual DataFlex program, not the name of the application.)

  9. You can change the name of your Web Application. When you do this you must (1) change the name in the Administrator (using rename) and (2) load global.asa and change the name in "WebAppServerSession.Initialize("xxx").

  10. You CANNOT change the name of the Workspace. The name of the workspace is compiled into the program.

  11. You can change the name of any of the COM objects. To do this, you must load global ASA and change the name of the object as follows:

<OBJECT RUNAT=Server SCOPE=Session ID=oChangedMyObj
PROGID="WebAppServer.WebBusinessProcess.12.0">
</OBJECT>

Then you must change the name in the '.Name" property where you change the Object name but do NOT change the value of the property (it must still be the old WBO name - which cannot be changed - see 6). Change this as follows:

oChangedMyObj.Name="oMyObj"

Next you must change ALL of your ASP files and make sure that they now reference the new COM name and not the old one.

  • You CANNOT change the WBO objects. They are compiled within your VDF program.

As you can see, the maintenance of these items can be extremely difficult.

See Also

Troubleshooting Web Applications


Understanding the Global.asa File

This is a very important file. It is stored in the root of your Web Application’s virtual directory (folder alias) and is used to create objects and define the mappings that connect all of your ASP/HTML files with your Web Application’s WBOs. There is only one ASA file per application (virtual directory).

The first time a user requests an ASP file within the virtual directory, global.asa is executed by the Web Server.

When the global.asa file is executed it:

  • Creates a WebAppServerSession COM object.

  • Provides the WebAppServerSession object with the required information to load the WBO program.

  • Creates COM objects to represent the WBOs now running within the Web Application. It also creates a mapping between the COM/WBO objects (used by your ASP files) and your WBO objects.

If your global.asa file is not properly configured, nothing will work properly. Normally, the Studio will handle this for you, but it is worth understanding what the different settings mean and how they can be changed.

  • Initializing the Web Application

  • Starting the Web Application Program

  • Creating and Mapping the COM/WBO Objects

See Also

Troubleshooting Web Applications

Global.asa Management


Initializing the Web Application

When a Web Application is started, the global.asa file must set a property that defines the Web Application Server Application name. This property is used indirectly to specify the name of the WebApp.exe program that must be loaded and run with each session. When the Web Application Server Administrator creates this name, a program path name is associated with it. The global.asa identifies the workspace for a Web Application, which is used to determine the path and name of the WebApp.exe program. When a new session is started, this information is used to load an instance of the program.

This is defined with the following code: (Normally, this setting is maintained by the Studio and you do not need to manually set it.)

<SCRIPT LANGUAGE=VBScript RUNAT=Server>

SUB Session_OnStart

WebAppServerSession.Initialize("Web Application Workspace Name")

END SUB</SCRIPT>

"Web Application Workspace Name" is the name of the Workspace used by the Web Application. The name of the workspace is normally the same name as the Web Application name. Please note that the name provided here is not the name of the application’s virtual directory, it is the name of the workspace key as defined within the Studio.

There are at least two ways to get this wrong:

  • The name you provided for the Web Application workspace might be wrong. The name must already be defined within the application you want to run. You check this by looking at the name in global.asa and verifying that it is correct.

  • The path and name of the WebApp.exe program as defined within the Web Application Server Administrator may be incorrect. The file could either not exist or it could be the wrong program for this application. You can check this by loading the Web Application Server Administrator, looking at the properties for the application in question, and verifying that the path and file name is correct.

The SessionTimeout setting is listed in the global.asa file and can be set in the Studio by selecting the Application, Properties… menu option.

See Also

Understanding the Global.asa File


Starting the Web Application Program

When a session is started, an instance of the Web Application program (WebApp.exe) must be loaded and assigned to the session.

<SCRIPT LANGUAGE=VBScript RUNAT=Server>

SUB Session_OnStart

WebAppServerSession.Initialize("Order_Entry")

;

END SUB

See Also

Understanding the Global.asa File


Creating and Mapping the COM/WBO Objects

Each WBO object within your running WebApp.exe program should have a COM/WBO associated with it. If your program has five WBO objects, you should create five COM objects to represent them. This provides the communication link between your ASP files and the WBOs. An object is created as follows: (Normally, these settings are maintained by the Studio and you do not need to manually set them).

<OBJECT RUNAT=Server SCOPE=Session

ID=ComWBOName PROGID="WebAppServer.WebBusinessProcess.12.0">

</OBJECT>

COMWBOName determines the name of the object within ASP and is usually assigned the same name as the WBO. This name is used to identify this object within your ASP files. For example, if the object was named ID=MyView, the object would be referenced within an ASP file as follows:

<%=MyView.DDValue("Customer.Name") %>

Your COM/WBO object and your WebApp.exe / WBO object may have different names. Each COM object contains a property named name. This specifies the name of the WebApp.exe / WBO. These properties must be set after a session is started, so they are defined within Session_OnStart.

<SCRIPT LANGUAGE=VBScript RUNAT=Server>

SUB Session_OnStart

WebAppServerSession.Initialize("Order_Entry")

ComWBOName="VDFWBOName"

:

ComWBOName="VDFWBOName"

Session.Timeout=1

END SUB

</SCRIPT>

The current suggested naming convention is to assign your COM/WBO and Web Application.exe/WBO objects the same name. A typical global.asa sample might look like the following:

<SCRIPT LANGUAGE=VBScript RUNAT=Server>

SUB Session_OnStart

WebAppServerSession.Initialize("Order_Entry")

CustWBO.Name="CustWBO"

VndrWBO.Name="VndrWBO"

OrderWBO.Name="OrderWBO"

Session.Timeout=1

END SUB

</SCRIPT>

There are several mistakes that you can make here:

  • You can forget to create the COM object within global.asa.

  • The COM name you assign to the object (ID=xxxx) may not be the same name you use within ASP files.

  • The Name property in your COM object may be the same as the name of the VDF WBO object.

All of these errors can be corrected within the global.asa file.

See Also

Understanding the Global.asa File


Application Checklist

When creating a Web Application Server application, you must deal with a number of complimentary programming components. All of these pieces have to be in synchronization. It is the job of the Studio to do this for you.

If you start changing settings that are controlled by the Studio (for example the name of a Web Browser Object), you will find your components are no longer working together and you will get a variety of error messages. If this happens, you need to know how to go back and manually synchronize all the components. If you understand how the various components are created and named, you can do this. That is the purpose of this section.

Here is what you need to do to manually get a Web Application running. Normally, most of these steps are performed by the Studio. Here is how you would do it without the Studio.

Make sure that Web Application Server is running

You can check this from the Web Application Administrator. Select the File menu. If the "Start Service" option is disabled, then the Web Application Server is running.

Conversely, if the "Start Service" option is enabled, then the Web Application Server is not running. In this case you should select the Start Service option to start the Web Application Server.

Create your Web Application Web Browser Object components and compile them

All of your WBO components should be located in the prescribed workspace directories. After you have compiled your Web Application program in the studio you might want to test that it’s working using the debugger. Select Run -> Compile and Debug in the Studio to test and debug your Web Application.

Create your ASP / HTML and Components

Normally these will be placed in a directory named AppHTML located as a sub-directory of the Web Application’s main workspace directory. All of the files in this directory are used to run a single application. In other words, all of these files will use the one WebApp.exe program you created in step 2.

The ASP file will communicate with the WBO by sending messages to COM objects. These objects interface to WBO objects within the WebApp.exe program. The global.asa creates the COM objects and defines the mapping between the COM and the WBO object names.

Linking your ASP to a contents HTML page

You will also need to create a table of contents HTML file. This file contains links to each ASP files that can be accessed. Normally the Studio creates a contents file for you. Once created, you can easily modify this to add, change or remove ASP files. The static HTML files in a normal Web Application Server application are named:

Checking the Global.asa

If your global.asa file is not properly configured, nothing will work properly. Normally, the wizards will handle this for you, but it is worth understanding what the different settings mean and how they can be changed.

See Also

Troubleshooting Web Applications


Checking Event Logs

Two logs need to be monitored when using the Web Application Server, the Web Application Server Administrator Log and the Windows NT log. They will supply you with useful information about problems you are troubleshooting and can give warnings of a problem that may be developing.

Windows NT Log

The Windows NT log can be reached by selecting Start | Programs | Administrative Tools | Event Viewer. There are three logs available. The "Log" pull-down lists all three: System, Security, and Application. The Application log is the one that will list most of your concerns with Web Applications.

The Windows NT log has many features such as sorting and filtering events. If you are not familiar with this utility it would be well worth your time to browse the Event Viewer on-line help.

Detailed information about an event is displayed by double clicking on an event line.

Web Application Server Event Log

The Web Application Server Event Log that can be accessed by the Server Administrator utility. Select Start | Programs | Web Application Server | Web Application Server Administrator.

A few procedures will let you add items to the Administrator’s event log. They are listed below. Unexpected errors are also logged here. Refer to the Visual DataFlex Class Reference for a detailed explanation of these messages.

Procedure LogErrorEvent

This logs an error event. An error event generates a normal error and explicitly logs this error to the Web Application’s event log. Events can be viewed using the Web Application Server Administration tool.

Most unexpected errors (program errors, syntax errors, etc.) are already automatically placed in the event log without any special programming on your part. This message should be used when you are sure the error should be added to the event log. If you are not logging an error event, do not use this message - use the LogEvent message.

Procedure LogEvent

This logs an event to the Web Application’s event log. This is often used to log any type of non-error system activity. Events can be viewed using the DataFlex Web Application Server Administration tool.

You should use this message to log any type of non-error activity to the error log. Errors should be added to the event log using the LogErrorEvent message. This message will generate an error and log the error to the event log. Most unexpected errors (program errors, syntax errors, etc.) are automatically placed in the event log without any special programming on your part.

Understanding Error Conditions

See "Web Application Errors" for descriptions on the various error conditions you may encounter.

See Also

Troubleshooting Web Applications


Logging Your Own Events to the Web Application Event Log

You can write to the Web Application Event Log from a Web Application using the LogErrorEvent and LogEvent messages. Both of these messages can be called from VDF or ASP code. See the Visual DataFlex Help for more information about these messages.

LogErrorEvent can be useful for adding custom errors to your application (e.g. log an error someone attempts to login to an application and enters the wrong password).

LogEvent can be useful for debugging or logging events in your application (to track certain operations, for example).

Example 1

Function DoRequestSave String sFilename Returns Integer

Integer iVoid iEventType

Move 5 to iEventType

Forward Get DoRequestSave sFilename To iVoid

Send LogEvent iEventType "Saving new record"

Function_Return iVoid

End_Function // DoRequestSave

This example augments the DoRequestSave method a WBO to log a message to the event log whenever a new record is saved.

Example 2

dim iEventType

iEventType = 5

oOrderWBO.Call "msg_LogEvent", iEventType, "Saving an order"

This example makes logs the message "Saving an order" to the VDF Web Application Event Log using VBScript code in an ASP page.

Example 3

oOrderWBO.Call "msg_LogErrorEvent", DfErr_Operator, "Attempt to enter an invalid value for Customer City"

This example makes logs the message "Attempt to enter an invalid value for Customer City" to the VDF Web Application Event Log using VBScript code in an ASP page.

When logging error events, you should use the predefined "generic errors" for the event numbers. The generic errors are reserved specifically for this type of use in applications. The generic errors are DfErr_Operator, DfErr_Program, DfErr_Compile and DfErr_Setup. Most likely, you will use the generic errors DfErr_Operator and DfErr_Program most often in your applications.

See Also

Troubleshooting Web Applications


Global.ASA Management

The Global.asa file is a standard part of any IIS Active Server Page application. Any virtual directory on your Web Server will comprise a single application. That single application will contain a single Global.asa file. This Global.asa is used to "glue" together all of the objects within an application. For this reason, it is imperative that your Global.asa is properly configured.

A Visual DataFlex web application uses the standard capabilities of the IIS Global.asa file to create the needed objects and connections between the ASP page and the WBO objects. The Studio maintains this file automatically. After each successful compilation of your web application program, the global.asa is updated. The Studio only maintains the parts of Global.asa that pertain to the Web Application Server. This allows you to use Global.asa for any other purposes required by other parts of your application.

Although you will normally not need to change the Global.asa, this file can be edited. You can edit the file using any text editor or directly within the Studio itself.

To edit a Global.asa file within the Studio use the "Open the global.asa file associated with this web application" button located on the Web Application Toolbar. If you are editing this file, it is assumed that you know what you are doing. If you make improper changes, you may render your global.asa file, and therefore, your web application unusable.

Parts of a Global.asa file

The following describes the sections of the Global.asa maintained by the Studio. These parts will be updated each time you compile an application. All other parts of this file are left alone by the studio.

The sections that are highlighted in black are code areas that must appear exactly as shown below. When a new application is created, these sections are copied into your AppHtml directory from a prototype global.asa file.

IMPORTANT: If you change any of this code or if you add new lines of code, they will remain in your new file. You should only change this code if you know exactly what you are doing!

The sections highlighted in blue are the code segments that are modified each time your application is compiled. You should never manually alter this code or, the next time that your application is compiled, those changes will be lost.

Following is an example of a typical Global.asa file:

<OBJECT RUNAT=Server SCOPE=Session ID=WebAppServerSession

PROGID="WebAppServer.Session.12.0">

</OBJECT>

<OBJECT RUNAT=Server SCOPE=Session ID=oCustomer

PROGID="WebAppServer.WebBusinessProcess.12.0">

</OBJECT>

<SCRIPT LANGUAGE=VBScript RUNAT=Server>

SUB Session_OnStart

WebAppServerSession.Initialize("Order Entry")

oCustomer.Name="oCustomer"

Session.Timeout=1

END SUB

</SCRIPT>

Global.asa sections maintained by the Web Application Studio

It may be instructive to look at each part of the Studio maintained Global.asa code.

<OBJECT RUNAT=Server SCOPE=Session ID=oCustomer

PROGID="WebAppServer.WebBusinessProcess.12.0">

</OBJECT>

Your Globa.asa should contain an object that corresponds to each WBO object in the application. This ID of this object must have the same name as the WBO object’s name and should be formatted as shown above. This object name is the name that must be used within your ASP page to refer to WBO objects (e.g., Err=oCustomer.RequestSave("Customer")).

WebAppServerSession.Initialize("Order Entry")

The Session_OnStart sub-routine must contain the above line. This associates the virtual directory with a Web Application name. The application name (in the above example "Order Entry") should be the name of your application as defined within the Web Application Administrator. When working within the Studio this name by default is the same name as your workspace.

oCustomer.Name="oCustomer"

Each object must also set the internal property "name." The name must also be the same name as your WBO object. This property must be set within the Session_OnStart sub-routine and formatted as shown above.

Session.Timeout=1

The Session_OnStart sub-routine must contain a line that defines your session timeout value. This value is defined in the Studio under Project -> Project Properties on the Web Application tab page. This value is set in minutes. Generally, you want to keep the timeout period short.

Trouble-shooting the Global.asa file

If your Web Application will not start you should check the Global.asa to make sure that required interfaces and objects exist between your WBOs and your ASP page.

Here are some guidelines:

  1. Make sure that your Global.asa is properly formatted. It must contain all of the black highlighted sections shown in the above example. If any of these sections are missing, your application will not run.

  2. Check the application name in Global.asa.

  • Load Web Application Administrator and make sure an application exists for this name.

  • Make sure that the Application is enabled within the administrator.

  • Make sure the Web Application Server is started (check the Administrator.

  3. Make sure that all required objects are defined in Global.asa.

  • Every WBO in the application must have an object of the same Name (ID) defined within global.asa. Each Of these objects must have the Name property properly set.

  • Your ASP files should only refer to objects defined within Global.asa. Remember that Global.asa is the file that creates the connection between the objects named in your ASP files and the WBO objects.

If an application does not start, always remember to check your NT Event Log. When you do this, make sure you are looking at the Application Event area – Select Application from the Log menu. In addition, some errors will be reported to your browser screen. Often this error will indicate that the error occurred in Global.asa. Other errors will appear in the Web Application Administrator’s application log.


.topic 0x10000008
 DLL Dynamic Link Library. A library that is linked to application programs when they are loaded or run rather than as the final phase of compilation. This means that the same block of library code can be shared between several tasks rather than each task containing copies of the routines it uses.

.topic 0x10000012
 Runtime Runtime is a term that refers to a given software application while it is being run.

.topic 0x10000011
 Record A record (or row) is a single unit of organized data from a database file.

.topic 0x1000000b
 File A file (or table) is a repository for storing organized data from your database.

.topic 0x1000000e
 Method A method is a procedure or function that is defined in a class.

.topic 0x1000000c
 Framework An application framework prescribes a consistent and well engineered technique for designing, coding and assembling your programs.

.topic 0x10000001
 Application Source Path The Application Source Path specifies the folder that contains the component packages, the ABdata files, and the program source code (.src) for the current workspace. The path name is stored in the workspace’s AppSrcPath registry key.

.topic 0x10000003
 Context Menu Pop-up menu that is activated by right mouse-clicking an object (the actual mouse button used is configurable in Windows setup).

.topic 0x1000000a
 Field A field (or column) is a data element used for organizing the data that is stored in each record of a database file.

.topic 0x10000009
 Event Events give the developer hooks for specific runtime occurrences, such as mouse actions, database operations and keystrokes. The code that executes when an event occurs is called an event handler.

.topic 0x10000005
 Data Files Folder The Data Files Path specifies the folder that contains the data files and filelist.cfg file for the current workspace. The path name is stored in the workspace’s DataPath registry key.

.topic 0x10000007
 DEO, Data-Entry Object Data Entry Object: An object used to wrap a database-aware Windows control.

.topic 0x10000000
 Application Source Folder The Application Source Path specifies the folder that contains the component packages, the ABdata files, and the program source code (.src) for the current workspace. The path name is stored in the workspace’s AppSrcPath registry key.

.topic 0x10000013
 Subclass A class that is a derived version of another class.

.topic 0x10000015
 Workspace A workspace describes an area for developing and running a Visual DataFlex project. It describes the location of the project’s source code, data files, data dictionary files, help file, bitmaps and program files.

.topic 0x10000006
 DDO Data-Dictionary Object.

.topic 0x10000004
 Data-Dictionary Data-dictionaries allow you to apply a set of rules to all records in a data file without having to repeat those rules in every control that accesses the file.

.topic 0x1000000f
 MDI Multiple Document Interface, a Windows API that enables programmers to easily create applications with multiple windows. Each MDI application has a single main window (MDI Frame), and any number of child windows. All child windows are displayed within the main window.

.topic 0x1000000d
 Index An index is a pre-defined sort order for the data in a database file. It is used for fast searching of records or for listing records in specific order.

.topic 0x10000002
 Component A Component is a single functional unit within a larger application. For example, an Order Entry application would contain view components for customer maintenance and entering orders, report components for printing orders and customer lists, etc.

.topic 0x10000014
 Wizard Wizards automate and simplify complex processes by breaking them into a series of easy to understand steps.

.topic 0x10000010
 Package A file containing DataFlex source code. Usually class definitions or global objects.