< Day Day Up > |
Web Connection server functions typically look in either the QueryString or the post buffer for parameters; then they construct a data command ( SELECT , INSERT , UPDATE , or DELETE ) and execute it; finally, if a SELECT was issued, the results are sent back. There are five objects in the ASP model. Web Connection has classes that mimic each of them. One mimics the Request object, and another the Response object. I like to instantiate these two objects in my Web Connection code with the names Request and Response , so that I forget which language I'm in and start writing in Visual BasicScript. Passing ParametersThere are two ways you can send data to a Web page. One is called GET and the other is called POST . GET means you can see the parameters, whereas POST means you can't. GET ParametersIn an ASP program, the following statement lcName = request("Name") will return the value of Name in a URL that looks like this: http://www.lespinter.com/subscriptions/login.asp?name=JoeBob Web Connection has a Request object, which works a lot like Internet Explorer's Request object. However, Web Connection uses the slightly more formal syntax lcEverything = Request.QueryString() for the entire string, or lcName = request.QueryString("Name") for the Name value. However, because these are programs talking to programs, we generally simply separate the parameters with tildes ("~") and count them, like this: lcName = request.QueryString(3) That's slightly confusing because the first parameter is the class library name and the function name is the second one, making your first parameter the third one as far as Web Connection is concerned . You'll get used to it. Here's an example: The following URL sends the name of a table, a key field, and a value from a user who has just picked a name from a drop-down list of customers in Alabama and wants the customer record: http://www.lespinter.com/wconnect/wc.dll?MyDataServer~GetOneRecord~Customers~CustID~3012214 The server code to respond to this might be as shown in Listing 5.4. Listing 5.4. Web Connection Function to Return a Single RecordFUNCTION GetOnerecord pTable = Request.QueryString(3) pKeyField = Request.QueryString(4) pKeyValue = Request.QueryString(5) cmd = [SELECT * FROM ] + pTable + [ WHERE ] + pKeyField + [=] + pKeyValue cmd = cmd + [ INTO CURSOR C1] &Cmd CursorToXML ( "C1", "lcXML" ) USE IN C1 USE IN ( pTable ) Response.Write ( lcXML ) ENDFUNC However, there are limits to the size of the GET string, which I think is about 128 characters . It's irrelevant, though, because we generally don't want to send our data across the Internet in clear text that absolutely anyone can read, so we'll rarely use GET . Instead, we'll use POST , which stores the variables in a bag called the post buffer . They can also be encrypted, which is what you'll eventually want to do with sensitive information. POST VariablesIf you instead stuff values into the post buffer, they're hidden. To add a variable and its corresponding value to the post buffer, in your client program you might have this: oIP.AddPostKey ( Value, "key" ) The entire URL is then simply http://www.lespinter.com/wconnect/wc.dll?MyDataServer~ShowMeDaData Any parameters, records being sent to be stored, or whatever, are no one's business but your own. There's an AddPostKey function for just that purpose, as you'll see shortly. GET and POST are only important when sending data or requests to a server. Servers send back whatever you want. It can be an HTML page, of course; but it can also be XML, or a DBF, or an encrypted string. The next few lines are calls to the WWIPSTUFF class library that's included in Web Connection. It essentially sends a request to the server, waiting for a string containing the results to be returned in the variable lcBuffer . I've chosen to demonstrate two ways to pass data back: a DBF and an XML string. If a DBF is returned, you just use StrToFile() to turn it back into a DBF and APPEND FROM to read it into the CARRIER cursor. If an XML string is created on the server and returned, it's converted back to a cursor when it's received. In either event it takes about a second (see Listing 5.5). Listing 5.5. Using the Post Buffer to Send Parameters to the Web ServerlnConnect = o.HTTPConnect ( Server ) IF lnConnect <> 0 MessageBox ( ; [Couldn't connect to Internet Server], ; 64, _Screen.Caption ) .cmdCancel.Click ENDIF lcBuffer = [] lnBufLen = 0 o.AddPostKey ( [RESET] ) o.AddPostKey ( [ParmC], ParmC ) o.HTTPGetEx ( FuncC, @lcBuffer, @lnBufLen ) SELECT Carrier ZAP DO CASE CASE gcMethod = [DBF] StrToFile ( lcBuffer, [Carrier.DBF] ) APPEND FROM Carrier.DBF DELETE FILE Carrier.DBF OTHERWISE && must be XML lcXML = ALLTRIM( lcBuffer ) oXML.XMLToCursor ( lcXML,[Carrier] ) ENDCASE ENDIF ENDWITH WITH THISFORM.List1 IF _Tally > 0 SCAN .AddListItem ( Company ) Row = .NewItemID .AddListItem ( City, Row, 2) .AddListItem ( Region, Row, 3) .AddListItem ( Cust_ID, Row, 4) ENDSCAN .ListIndex = 1 .Selected[1] = .T. THISFORM.cmdSelect.Enabled = .T. ELSE THISFORM.cmdSelect.Enabled = .F. ENDIF ENDWITH ENDPROC The AddPostKey method stuffs strings into the HTTP transport and sends them over. It's the cleanest way to send strings that contain blanks; otherwise you get all of those funny tildes and pluses. Show All Customers is even easier; however, it's not advisable in most cases. I'm only doing it here because I know there are just a few records in the table (see Listing 5.6). Listing 5.6. Code to Return All CustomersPROCEDURE cmdall.Click SELECT Carrier ZAP THISFORM.List1.Clear FuncC = Prefix +( gcAllCustomers ) lnConnect = o.HTTPConnect ( Server ) IF lnConnect <> 0 MessageBox ( ; [Couldn't connect to Internet Server], ; 64, _Screen.Caption ) cmdCancel.Click ENDIF lcBuffer = [] lnBufLen = 0 o.HTTPGetEx ( FuncC, @lcBuffer, @lnBufLen ) DO CASE CASE gcMethod = [DBF] StrToFile ( lcBuffer, [Carrier.DBF] ) SELECT Carrier APPEND FROM Carrier.DBF DELETE FILE Carrier.DBF OTHERWISE && must be XML lcXML = ALLTRIM( lcBuffer ) oXML.XMLToCursor ( lcXML, [Carrier] ) ENDCASE WITH THISFORM.List1 SCAN .AddListItem ( Company ) Row = .NewItemID .AddListItem ( City, Row, 2) .AddListItem ( Region, Row, 3) .AddListItem ( Cust_ID, Row, 4) ENDSCAN .ListIndex = 1 .Selected[1] = .T. ENDWITH ENDPROC Think through the code for a few minutes and you'll see what's going on. You send off a query in the first parameter of HttpGetEx and then wait for the answer to be returned in lcBuffer as a string. You'll then convert it from either a DBF or from XML. An XML PrimerXML is simplicity itself. (We'll talk about it in detail in Chapter 7, "XML.") If you have a CUSTOMER record with fields NAME , PHONE , and BALANCE , the XML of that record will look like this: <name>Joe Blow</name> <phone>555-1212</phone> <balance>123.45</balance> All data is converted to strings for XML transport. The XMLTOCURSOR() method of WWIPSTUFF class converts it back to the correct data types, using the corresponding field names in an open cursor to type the data. The method call lcXML = oXML.CursorToXML() reads the currently open cursor and stores its XML representation in string lcXML . Its inverse function is oXML.XMLtoCursor ( lcXML ) which takes the string and dumps it into the cursor that's open in the current work area, using field names alone to determine what goes where and what data types to use. (It doesn't have to be the current work area, but I'm trying to make this as simple as possible.) You can also use something called a DTD. There are thick books about XML, and you don't need to know any of it for what we're doing here. If you're one of those anal-retentive types who delights in theoretical purity, you're reading the wrong book. The Customer FormThe Customer form is based on the StandardForm template. I included some basic capabilities in StandardForm , but a few additional features need to be added for each form that we build. The customer form appears in Figure 5.2. Figure 5.2. The Customer form.
The Load event creates a cursor that matches the data source (see Listing 5.7). If you're using SQL Server, the FoxPro data types are slightly different: SQL's Text is our Memo , Money is our Y field, and TinyInt and Smallint are just Int . For SQL VarChar , you can use either Memo or Char . Listing 5.7. Load Event for the FormPROCEDURE Load CREATE CURSOR Customer (; CUST_ID Char( 6), ; COMPANY Char(40), ; CONTACT Char(30), ; TITLE Char(30), ; ADDRESS Char(60), ; CITY Char(15), ; REGION Char(15), ; POSTALCODE Char(10), ; COUNTRY Char(15), ; PHONE Char(24), ; FAX Char(24), ; MAXORDAMT Y ) ENDPROC The users have to go to the server to pick a record. That's why, unlike what we're used to in the FoxPro world, the screen in most SQL apps is initially empty. The Find function described in Listing 5.8 lets them find a record to display on the form. Listing 5.8. Click Event Code for the Find ButtonPROCEDURE cmdFind.Click WITH THISFORM DO FORM GetCust TO CustKey && GetCust is a MODAL form IF NOT EMPTY ( CustKey ) o.HTTPConnect ( Server ) lcBuffer = [] lnBufLen = 0 o.HTTPGetEx ( Prefix + gcSelectedCustomer + [~] ; + CustKey, @lcBuffer, @lnBufLen ) IF NOT EMPTY ( lcBuffer ) SELECT CUSTOMER ZAP DO CASE CASE gcMethod = [DBF] StrToFile ( lcBuffer, [Carrier.DBF] ) APPEND FROM Carrier.DBF DELETE FILE Carrier.DBF OTHERWISE && must be XML lcXML = ALLTRIM( lcBuffer ) oXML.XMLToCursor ( lcXML, [Customer]) ENDCASE ENDIF .Refresh .cmdEdit.Enabled = .T. .cmdDelete.Enabled = .T. ELSE .cmdEdit.Enabled = .F. .cmdDelete.Enabled = .F. ENDIF .cmdNext.Enabled = .T. .cmdPrev.Enabled = .T. ENDWITH ENDPROC They might just want to add a record. See the template cmdAdd.click code shown in Listing 5.9 to see what happens here. Except for our code to ensure that the cursor is zapped before the default cmdADD.Click method code runs, there's little difference. Listing 5.9. Click Event Code for the Add ButtonPROCEDURE cmdAdd.Click SELECT Customer ZAP DODEFAULT() ENDPROC There's no cmdEdit.Click code because it's exactly the same as the template code ”enable the input fields, then disable all buttons except Save and Cancel. Note that in the template code a form property called Adding is set to True during an add, because it's very, very important when it comes time to save changes or additions. |
< Day Day Up > |