From Script To Code

The Web Control Framework is designed to work with HTML Script pages and uses a format that can be used in Visual Studio or any other .NET capable environment. The idea is that you can use a rich editing environment such as VS.NET 2005/2008 and create your script pages.

A Web Connection script page is defined as follows:

<%@ Page Language="C#" 
	ID="Test_Page"	
	GeneratedSourceFile="~\webcontrols\Test_Page.prg"          	
%>
<%@ Register Assembly="WebConnectionWebControls" 
    Namespace="Westwind.WebConnection.WebControls"
    TagPrefix="ww" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <title></title>
    <link href="westwind.css" rel="stylesheet" type="text/css" />
</head>
<body style="margin-top:0px;margin-left:0px">
    <form id="form1" runat="server">
    
    <ww:wwWebErrorDisplay runat="server" id="ErrorDisplay" Text=' rick="test"' />
        
    </form>
</body>
</html>

It's vital that a few key elements are placed into the page:

  • <%@ Page tag
    Generatedsourcefile and ID attributes. These attributes are necessary for Web Connection to be able to generate source code from the page. The GeneratedSourceFile specifies the name of the FoxPro PRG file into which a FoxPro class is generated. The path is a relative path to the current executing directory. The ID specifies the name of the class that is generated for you in this PRG file. Two classes are actually generated - the specified class and a subclass thereof with _WSCX extension that defines the markup control definitions. The main class is for you to add User code to to handle page events.

  • <form runat="server"> tag
    In order for any controls to be processed on the page a server form is required. A script page can contain no more than one server form although it can contain multiple non server forms.

  • Control Tags
    Controls can be added in two ways: Using Web Connection namespace syntax or using stock ASP.NET control syntax for any controls that have Web Connection equivalents. The Web Connection controls all start with a Web prefix (ie. WebTextBox, WebCheckBox etc.) and the parser maps each control declaration to a class. For stock ASP controls the parser reads the ASP tags and appends a Web prefix to the to the classname. This works as long as there's a matching control. So the following are actually equivalent:
    <asp:TextBox runat="Server"/>
    <ww:WebTextBox runat="Server"/>

Note:
In order to render the Web Connection controls in VS.NET's visual designer you need to add the WebConnectionWebControls.dll into your Bin directory and at the following below the page directive:
<%@ Register Assembly="WebConnectionWebControls.dll" Namespace="Westwind.Web.Connection.WebControls" TagPrefix="ww" %>

Script to Code

Web Connection converts the script page you generate in your editor into a Visual FoxPro 8.0 or later PRG file by reading the generatedSourceFile, id and inheritedClass attributes. The Page Compiler is available in WebPageCompiler.prg:

DO WebPageParser with "d:\westwind\wconnect\webControls\FirstForm.wcsx"

which creates the following source code file:

#INCLUDE WCONNECT.H

*** Small Stub Code to execute the generated page
PRIVATE __WEBPAGE
__WEBPAGE = CREATEOBJECT("FirstForm_Page_WCSX")

#IF DEBUGMODE
    __WEBPAGE.Run()
   RELEASE __WEBPAGE
#ELSE
   TRY
      __WEBPAGE.Run()
   FINALLY
      *** MUST MAKE ABSOLUTELY SURE WE RELEASE
      RELEASE __WEBPAGE
   ENDTRY
#ENDIF
RETURN

**************************************************************
DEFINE CLASS FirstForm_Page as WebPage
***************************************
*** Your Implementation Page Class - put your code here
*** This class acts as base class to the generated page below
**************************************************************

FUNCTION OnLoad()

ENDFUNC

ENDDEFINE



*# --- BEGIN GENERATED CODE BOUNDARY --- #*

*******************************************************
*** Generated by PageParser.prg 
***    on: 08/29/2005 01:13:55 AM
***
*** Do not modify manually - class will be overwritten
*******************************************************

DEFINE CLASS FirstForm_Page_WCSX AS FirstForm_Page

   *** Control Definitions
   frmFirstForm = null 
   txtHello = null 
   btnSubmit = null 

FUNCTION Init(loPage)
DODEFAULT(loPage)

__lcHtml = []
__lcHtml = __lcHtml + []+CHR(13)+CHR(10)
__lcHtml = __lcHtml + []+CHR(13)+CHR(10)
__lcHtml = __lcHtml + []+CHR(13)+CHR(10)
__lcHtml = __lcHtml + [<html>]
_1LO02N2KV = CREATEOBJECT("WebLiteralControl",THIS)
_1LO02N2KV.Text = __lcHtml
THIS.AddControl(_1LO02N2KV)

__lcHtml = []
__lcHtml = __lcHtml + []+CHR(13)+CHR(10)
__lcHtml = __lcHtml + [    <title>Untitled Page</title>]+CHR(13)+CHR(10)
__lcHtml = __lcHtml + [</head>]+CHR(13)+CHR(10)
__lcHtml = __lcHtml + [<body>]+CHR(13)+CHR(10)
__lcHtml = __lcHtml + [    ]
_1LO02N2KW = CREATEOBJECT("WebLiteralControl",THIS)
_1LO02N2KW.Text = __lcHtml
THIS.AddControl(_1LO02N2KW)

THIS.frmFirstForm = CREATEOBJECT("WebForm",THIS)
THIS.frmFirstForm.Id = "frmFirstForm"
THIS.AddControl(THIS.frmFirstForm)


__lcHtml = []
__lcHtml = __lcHtml + []+CHR(13)+CHR(10)
__lcHtml = __lcHtml + [    Here's some Html Text]+CHR(13)+CHR(10)
__lcHtml = __lcHtml + [    ]
_1LO02N2L5 = CREATEOBJECT("WebLiteralControl",THIS)
_1LO02N2L5.Text = __lcHtml
THIS.AddControl(_1LO02N2L5)

THIS.txtHello = CREATEOBJECT("webtextbox",THIS)
THIS.txtHello.Id = "txtHello"
THIS.txtHello.value = [Hello]
THIS.AddControl(THIS.txtHello)


__lcHtml = []
__lcHtml = __lcHtml + [ ]+CHR(13)+CHR(10)
__lcHtml = __lcHtml + [    ]
_1LO02N2L6 = CREATEOBJECT("WebLiteralControl",THIS)
_1LO02N2L6.Text = __lcHtml
THIS.AddControl(_1LO02N2L6)

THIS.btnSubmit = CREATEOBJECT("webbutton",THIS)
THIS.btnSubmit.Id = "btnSubmit"
THIS.AddControl(THIS.btnSubmit)


__lcHtml = []
__lcHtml = __lcHtml + [ ]+CHR(13)+CHR(10)
__lcHtml = __lcHtml + [    ]
_1LO02N2L7 = CREATEOBJECT("WebLiteralControl",THIS)
_1LO02N2L7.Text = __lcHtml
THIS.AddControl(_1LO02N2L7)

_1LO02N2L8 = CREATEOBJECT("WebForm",THIS)
_1LO02N2L8.RenderType = 2
THIS.AddControl(_1LO02N2L8)

__lcHtml = []
__lcHtml = __lcHtml + []+CHR(13)+CHR(10)
__lcHtml = __lcHtml + [</body>]+CHR(13)+CHR(10)
__lcHtml = __lcHtml + [</html>]
_1LO02N2L9 = CREATEOBJECT("WebLiteralControl",THIS)
_1LO02N2L9.Text = __lcHtml
THIS.AddControl(_1LO02N2L9)

ENDFUNC
ENDDEFINE

*# --- END GENERATED CODE BOUNDARY --- #*

There are three parts to this source file:

  • The Loader Stub
    Responsible for loading the class and basically executing it. The Run method is a high level method that executes and writes the result into the Response object.

  • Your User Code Class used to write your code
    This is where you will write the logic for the page. The default stub generated implements an empty OnLoad() method that you can fill in to perform some tasks. Note you can reference any of the controls by name in this form such as this.txtHello.Text. You will also implement event code here.

  • The generated Control Class
    The bottom of the source file is the generated class that contains all the control definitions, property assigments parsed from the script code and event definitions. This class is generated and will get regenerated anytime the WebPageParser is run.

Note the class hierarchy: Your code implements the base class and the generated class inherits from this base class. The stub above implements the generated class, calls the run method and output is generated into the Response object.

In Web Connection if you wanted to run this form now you could simple create a Process class and DO

FUNCTION Process_DoSomeThing
DO FirstForm_page
ENDFUNC

And that's it!

Easy as that is there's actually an easier and more convenient way to do this.

How scripts get fired from a wwProcess class

Web Connection 5.0 integrates Web Control processing right into the core framework. wwProcess works by default looking for a matching method to execute based on the page name. In Version 5.0 the framework has been extended so if a method cannot be found it will try to execute the physical page that it maps to on disk. The default execution mode is to process the page as Web Control page.

There's a flag on the wwProcess class - nPageScriptMode that determines this operation and the default is 2 which is to execute the page as Web Control Page. You can also use a value of 1 which is the 'legacy' behavior that uses ExpandTemplate instead.

This means that you can use the same wwProcess based class as your base handler for both method based implementations AND use Web Control Pages. This means you can use a single configuration point for

************************************************************************
*PROCEDURE wwPageDemo
****************************
***  Function: Processes incoming Web Requests for wwPageDemo
***            requests. This function is called from the wwServer 
***            process.
***      Pass: loServer -   wwServer object reference
*************************************************************************
LPARAMETER loServer
LOCAL loProcess
#INCLUDE WCONNECT.H

LOCAL loProcess 
loProcess=CREATE("wwPageDemo",loServer)
loProcess.lShowRequestData = loServer.lShowRequestData

IF VARTYPE(loProcess)#"O"
   *** All we can do is return...
   WAIT WINDOW NOWAIT "Unable to create Process object..."
   RETURN .F.
ENDIF

*** Call the Process Method that handles the request
loProcess.Process()

RETURN

*************************************************************
DEFINE CLASS wwPageDemo AS <<b>>wwWebPageProcess<</b>>
*************************************************************

nPageScriptMode = 2   && Web Control Pages

*********************************************************************
FUNCTION HelloWorld()
************************
THIS.StandardPage("Hello World from wwPageDemo process",;
                  "If you got here, everything should be working fine.<p>" + ;
                  "Time: <b>" + TIME()+ "</b>")
                  
ENDFUNC
* EOF wwPageDemo::HelloWorld

*** Recommend you override the following methods:

*** ErrorMsg
*** StandardPage
*** Error

ENDDEFINE

In fact web Connection automatically maps this process to the WCSX extension within your Web application.


Note:
If you use some alternate extension you need to make sure you create a scriptmap and add the custom extension to the <youapp>Main.prg 's Process method.

Once this is in place you can now instantiate your demo simply by going to the name of the page.

http://localhost/wconnect/webcontrols/firstForm.wcsx

Make sure that you have at least compiled this page once.

Compiling and Debug Modes

As you may have surmised from the above, you need to compile your pages. Without compilation there's nothing to run, so you must compile.

The wwWebPageProcess class can run in one of two modes:

  • Debug Mode with Interpreted Script Enabled
    In this mode the DEBUGMODE flag must be set to .T. and you must be running the Server object nScriptMode=3 (Interpreted Script - you can set this on the Status Form's Script Options). In this mode Web Connection will read the file, parse it and run it, then unload everything, EVERY TIME you run the form. This is not very fast, but it's great for debugging.

  • Compiled Mode
    If DEBUGMODE is .F. or the Server's ScriptMode is not set to 3, Web Connection just tries to the run the file specified in the GeneratedSourceFile attribute of the form. This means if the page has not been generated yet - it will fail. If you make a change to the script code that change will not be reflected because the code is not regenerated.

Generally you'll want to work in Debug mode in the development environment, just be aware that the Server.nScriptMode flag has no effect once DebugMode is turned off.

Very Important Project Note:
Because pages are loaded dynamically by Web Connection, you have to make sure you add pages to your compiled project manually. If you don't the VFP project manager will not include your generated classes and your custom code. Either add them manually or add a dummy method that is never called to your project that executes each of the pages.

© West Wind Technologies, 1996-2019 • Updated: 09/27/16
Comment or report problem with topic