Web Application Flow
Related topics: - Web Properties Methods and Events - Positioning and Layout of Controls
Overview
A Web Application works differently than a traditional desktop application. The client (your browser) does not own a single persistent instance of the WebApp process. Instead, the server maintains a pool of WebApp.exe processes. When a client needs a process, it connects to one from the pool, initializes and synchronizes it with data from the client, processes requests, then disconnects and returns the process to the pool.
Starting an Application Process
When your Web Application starts, a number of WebApp.exe processes are loaded and initialized. The number of processes created depends on your process pooling settings. (You generally should use process pooling.) This startup creates all of your objects, sets their default properties, and places the process into the pool.
Important points about this initialization:
- During initialization you are not connected to a client. You are starting a default instance that might be used by any client and by multiple clients.
- Because you are not connected to a client, do not use
WebSet/WebGetto configure web-properties during initialization. UseGetandSetto establish default values that will apply to all clients. - Attempting to
WebSeta property during initialization will cause a runtime error. WebGetduring initialization acts likeGetand returns default values. PreferGetduring initialization unless you explicitly need the web-property behavior.- If an error occurs during initialization there is no client/browser present to handle it; such errors are considered fatal. Under the debugger you will see the error in the debug’s error display. At deployment, startup errors are logged to the Windows event log.
- Every object you create and every property you set during initialization defines the default environment for clients when they first connect. Subsequent changes are stored as web-properties and synchronized between client and server as needed.
Starting a Web Application in your Browser
The URL you open in your browser (for example http://MySite/MyApplication/Index.html) loads a page that contains the JavaScript classes required to run the application and an AJAX-style request handler. From that point the page is not reloaded; all communication is via AJAX-style requests. These requests create browser sessions, display the main application, load views and dialogs, and handle client interactions.
WebApp Client-to-Server Requests
Requests are performed through web-service calls using JSON. This request/response cycle is often called a "round trip to the server". You can view each request/response in your browser’s debugger (for example with Firebug or the browser network console).
Common request types:
- Load the WebApp — starts a new browser session and displays the application shell (menus, toolbars, login, and possibly an initial view).
- Load a new view/dialog — when the view/dialog has not yet been loaded on the client; the server sends the definition so the client can initialize it.
- Show a view/dialog — when the view/dialog is already present in the client; often no server request is required unless configured to do so.
- Interact with a view/dialog — when a client action requires server interaction (e.g., finding, saving, deleting records).
Common behavior for all requests:
- Each request attaches to the next available process in the pool. Do not assume a persistent one-to-one connection between a browser and a process.
- Each request must initialize the instance based on data passed from the browser. The framework synchronizes all web-properties and the state of DDO structures and controls for views/dialogs involved in the request.
- Requests are serviced by calling server-side events (e.g.,
OnClick) or server actions (e.g.,RequestSave). - Handlers and methods called during requests primarily interact with web-properties. Use
WebGetandWebSetduring request processing rather thanGet/Set. - Some server-side events are optional, enabled or disabled using properties such as
pbOnServerEventName(e.g.,pbServerOnShow). - If no server-side events are required for a view change, the operation may occur without a server request (for example, if
pbServerOnShowisFalseon the new view andpbServerOnHideisFalseon the old view). - Low-level attach/detach events,
OnAttachProcessandOnDetachProcess, occur for every request. These are triggered before and after synchronization respectively and should not normally be augmented. Do not useWebGet/WebSetin these events. - Only the views and dialogs that are part of the request are synchronized on the server — this may be a single view, two views (switching), or a view with modal dialogs. The framework determines which views/dialogs need synchronization.
Typical request flow
Most requests sent to a view or dialog follow this outline:
OnAttachProcessis sent to thecWebAppobject.- Synchronize all web-properties.
OnSyncWebAppis sent to yourcWebAppobject.- For each view that needs to be synchronized:
- Check
AllowAccess. Rebuild_Constraintsis sent to all DDOs in the view's main DDO structure.- Synchronize the main DDO structure.
OnSyncViewis sent to the view.- Process all request actions.
- Build the response data.
OnDetachProcessis sent to thecWebAppobject.
Note:
- OnSyncWebApp is sent to the main cWebApp before view synchronization and is useful for global customizations and rights handling.
- If a view’s AllowAccess returns False, the request is canceled for security reasons.
- OnSyncView is sent to each view/dialog used in the request and is useful for rights handling and defining dynamic constraints in the view’s DDO structure. Typically, define custom DDO OnConstrain logic based on web-properties.
- After OnSyncView, Rebuild_Constraints is sent to your DDO structure, so explicit manual rebuild is not required when customizations occur inside OnSyncView.
- The "process all request actions" step may include actions like loading or hiding views, which can trigger additional events (for example OnClick).
- If you change constraints outside of the Rebuild_Constraints process (for example in another event), you must send Rebuild_Constraints to the relevant DDOs.
- Test the value returned by AppSynching in any data dictionary events that may be triggered during a find operation (e.g., OnPostFind, Refresh, OnNewCurrentRecord). AppSynching (see cWebApp::AppSynching) returns True while the framework is synchronizing web-properties and DDO structure, and False while processing request actions. Normally you do not want to process DDO events when AppSynching returns True.
Action — Loading a WebApp
The first time a client requests a WebApp, the server must load the WebApp onto the client. Steps:
CreateSession— create a new session.- Clear all web-properties.
- Send
OnChangeRightsto thecWebAppobject, the command bar, and all of its objects. - Serialize all web-objects to be displayed (sent to the client and converted to client-side objects). Typically this includes the main
cWebAppobject, menus, and toolbars. - Send
OnLoadto every serialized web-object. - If a default login or default view is defined, load it (see Action — Loading a View/Dialog).
Note:
- OnChangeRights is sent during the load and when a user’s rights change (for example after login). It is sent to every menu object and can be used to enable/hide items, toolbars, menus, or the entire command bar system.
- OnLoad is sent for every web-object when it is serialized and usually occurs only once per session.
Action — Loading a View or Dialog
The first time a view or dialog is requested, the view’s object definition must be serialized and sent to the client so it can display the view. Once loaded, the client can hide and reshow these views without needing the definition again.
Typical sequence when loading a view/dialog (including when replacing an existing view or opening a modal dialog):
- Check
AllowAccessof the view. - Send
Clear_Allto the view’s main DDO. OnSyncView.- Serialize all web-objects to be displayed (sent to the client and converted to client-side objects).
- Send
OnLoadto every serialized web-object. OnHideis sent to the old view (if there is an old view andpbServerOnHideisTrue).OnShowis sent to the new view (ifpbServerOnShowisTrue).
Notes:
- If a view’s AllowAccess returns False, the request is canceled for security.
- OnLoad is usually only sent once per session for each object.
- If there was an old view, that view will already have been synchronized as part of the normal request synchronization process.
Action — Showing a View or Dialog Already Loaded
When both the old and new views are already loaded:
OnHideis sent to the old view (if there is an old view andpbServerOnHideisTrue).OnShowis sent to the new view (ifpbServerOnShowisTrue).
If both views are already synchronized and pbServerOnHide / pbServerOnShow are False, there may be no server request at all.
Important Events
OnLoad
`OnLoad` is sent to every web-object when the object is loaded (serialized and sent to the client). This generally occurs once per session per object. `OnLoad` is sent unconditionally — there is no `pbServerOnLoad`.
Example: use `OnLoad` in a view to display a default record:
```dataflex
Procedure OnLoad
Send Find of OrderHea_DD FIRST_RECORD Index.1
End_Procedure
```
Example: use `OnLoad` in `cWebApp` for first-time processing (e.g., automatic login):
```dataflex
Procedure OnLoad
Boolean bOk
Get UserLogin of ghoWebSessionManager "guest" "Guest" to bOk
End_Procedure
```
OnShow
OnShow is sent to a view or dialog when it is being shown. It is sent when the view is first loaded and each time it is re-displayed. OnShow is only called if pbServerOnShow is True. Useful for modal dialogs that require initialization each time they are shown.
OnHide ~~~~~~
OnHide is sent to a view or dialog when it is being hidden (for example, when another view is shown or when a modal dialog is closed). OnHide is only called if pbServerOnHide is True.
OnChangeRights ~~~~~~~~~~~~~~
OnChangeRights is sent whenever user rights change. It is sent to the cWebApp object, the command bar object, and all objects within the command bar. It is not sent to views; use OnSyncView to handle view-specific rights and role requirements.
OnSyncWebApp ~~~~~~~~~~~~
OnSyncWebApp is sent to the cWebApp object with each request after web-properties are synchronized but before any view DDOs are synchronized. Use it for global initializations and rights/role handling.
OnSyncView ~~~~~~~~~~
OnSyncView is sent to each view that needs synchronization during a request. It is sent after web-properties, DDOs, and DEOs are synchronized.
This event is important for controlling user rights, disabling/hiding controls, and initializing dynamic constraints. Use WebGet/WebSet for web-properties inside OnSyncView. If you change constraints in OnSyncView, call Rebuild_Constraints on the DDO so OnConstrain is applied.
Examples: two methods to customize DDO constraints
1) Use OnSyncView to read web-properties and set DDO properties, then call Rebuild_Constraints:
```dataflex Object oCustomerGrid is a cWebView { WebProperty = True } Property String psFilter "" { WebProperty = True } Property String psFilterFrom "" { WebProperty = True } Property String psFilterTo "" Procedure OnSyncView String sFilter sFrom sTo WebGet psFilter of oCustomerGrid to sFilter WebGet psFilterFrom of oCustomerGrid to sFrom WebGet psFilterTo of oCustomerGrid to sTo Set psType of oCustomer_DD to sFilter Set psFrom of oCustomer_DD to sFrom Set psTo of oCustomer_DD to sTo Send Rebuild_Constraints of oCustomer_DD End_Procedure
Object oCustomer_DD is a Customer_DataDictionary
Property String psType
Property String psFrom
Property String psTo
Procedure OnConstrain
String sFilter sFrom sTo
Forward Send OnConstrain
Get psType to sFilter
Get psFrom to sFrom
Get psTo to sTo
If (sFilter = "NUMBER") Begin
Constrain Customer.Customer_Number Between sFrom and sTo
End
If (sFilter = "NAME") Begin
Constrain Customer.Name Between sFrom and sTo
End
End_Procedure
End_Object
End_Object ```
2) Use web-properties directly in OnConstrain so no OnSyncView augmentation is required. Rebuild_Constraints will still call OnConstrain:
```dataflex Object oCustomerGrid is a cWebView { WebProperty = True } Property String psFilter "" { WebProperty = True } Property String psFilterFrom "" { WebProperty = True } Property String psFilterTo "" End_Object
Object oCustomer_DD is a Customer_DataDictionary Procedure OnConstrain String sFilter sFrom sTo Forward Send OnConstrain WebGet psFilter of oCustomerGrid to sFilter WebGet psFilterFrom of oCustomerGrid to sFrom WebGet psFilterTo of oCustomerGrid to sTo If (sFilter = "NUMBER") Begin Constrain Customer.Customer_Number Between sFrom and sTo End If (sFilter = "NAME") Begin Constrain Customer.Name Between sFrom and sTo End End_Procedure End_Object ```
Previous Topic: Web Properties Methods and Events
Next Topic: Positioning and Layout of Controls