Sample CH 15
Sample CH 15
Sample CH 15
Chapter 15
Working with Web Services
The next generation of Web applications involves the use of Web Services. Visual
FoxPro 7’s new built-in XML capabilities and Web Services extensions make it easy to
create Web Services that can be accessed from anywhere on the Internet.
Before jumping into the topic of Web Services, it’s best to first understand the basics of XML,
how it has been integrated into VFP 7, and where you can use it in your applications.
Introducing XML
In a nutshell, XML is a (relatively) new text-based data format. So what’s all the hubbub
about? Primarily it’s because XML has been universally accepted by all major platform
vendors, paving the way for a universal cross-platform standard for sharing data.
XML bears a strong resemblance to HTML, and with good reason—they are both related
to a parent language definition standard called Standard Generalized Markup Language
(SGML). XML contains tags (words in angled brackets) surrounding blocks of text. However,
unlike HTML where each tag has a specific meaning, XML is extensible—its tags have no
predefined meaning. You can assign your own meaning to the tags.
For example, in HTML, the <TABLE> tag has a specific meaning. Based on this, any
browser that understands the HTML specification can render tables correctly. In contrast, the
<TABLE> tag can mean anything in XML. For example, in the following XML fragment, the
<TABLE> tag refers to different kinds of furniture—a dining room, coffee, or card table:
<FURNITURE>
<TABLE>"Dining Room"</TABLE>
<TABLE>"Coffee"</TABLE>
<TABLE>"Card"</TABLE>
</FURNITURE>
<ccity>Richmond</ccity>
<cstate region="1">VA</cstate>
<czip>22901</czip>
<ctype/>
</customer>
<customer>
<iid>4</iid>
<cacctno>001003</cacctno>
<cname>Sergio Vargas, Attorney at Law</cname>
<caddress1>115 Pacific Coast Highway</caddress1>
<ccity>Malibu</ccity>
<cstate region="5">CA</cstate>
<czip>80766</czip>
<ctype/>
</customer>
</VFPData>
This declaration is not required, but it’s recommended that you place it at the top of all
of your XML documents. It identifies the document as an XML document and specifies the
version of XML used to create it. Optionally, it can contain the character encoding used. The
“standalone” instruction specifies whether the XML document stands alone or needs additional
definitions declared in other files. Note that the word “xml” must be in lowercase. XML tags
(unlike HTML) are case-sensitive.
The next line in the document is the start tag of the root element:
<VFPData>
The XML specification requires that all XML documents contain a single root element that
encompasses all other elements in the document.
Within the root element are two <customer> elements, each representing an individual
customer record. Within the customer element there are nine other elements, each representing
a field in a record.
Elements
Elements are the most common form of markup found in an XML document. They consist of
an opening and closing tag, content between the tags (also referred to as “data”), and optionally
attributes with associated values (see the next section). For example:
If a particular element does not have any content, you can use a single tag element to
represent it. For example, the ctype tag in the previous section contains no data and is
represented as:
<ctype/>
Section 3 Chapter 15: Working with Web Services 227
This contains both the start and end tag information in a single tag element.
Attributes
An attribute is a name-value pair enclosed within the opening tag of an element. For example:
<cstate region="5">CA</cstate>
In this element, region="5" is the name-value pair that comprises the attribute. Attributes
can be used to provide additional information regarding a particular element.
Comments
In an XML document, comments take the form:
Well-formed XML
XML documents are well-formed, if they adhere to the basic rules of XML. For example, the
XML specification dictates that XML documents must contain a unique root node. Another
rule of well-formed XML is that start and end tags match—including their capitalization. For
example, these are valid XML tags:
<cacctno>001003</cacctno>
<cacctno>001003</cAcctNo>
With HTML, you can be somewhat lax about ending tags. Browsers rendering HTML can
be very forgiving—if you leave off an ending tag, the browser can compensate and render the
HTML in a presentable fashion. In contrast, XML parsers are not at all forgiving. For each start
tag, there must be a corresponding end tag.
Reserved characters
There are special reserved characters in XML that cannot be used “as is” in the data portion of
an element because they have an alternate meaning in the XML specification. For example, the
left angle bracket < is used in XML to mark the beginning of a tag; so if you want to use this
character in the data portion of an XML element, you need to replace it with: <.
The reserved characters and their replacement character sequence (entity encoding) are
shown in Table 1.
228 What’s New in Visual FoxPro 7.0
Table 1. This table shows commonly used special reserved characters that must be
replaced by corresponding entity encoding.
For example, in XML, the text “Liederbach & Associates” must be changed to:
The following sections show how a Customer table with the structure shown in Table 2 is
represented by VFP 7 in each of these formats.
Table 2. This table shows the structure of a Customer table used in the XML examples
for this chapter.
Element-centric XML
Records formatted in element-centric XML look like this:
<ccity>Richmond</ccity>
<cstate>VA</cstate>
<czip>22901</czip>
</customer>
<customer>
<iid>4</iid>
<cacctno>001003</cacctno>
<cname>Sergio Vargas, Attorney at Law</cname>
<caddress1>115 Pacific Coast Hwy</caddress1>
<ccity>Malibu</ccity>
<cstate>CA</cstate>
<czip>80766</czip>
</customer>
</VFPData>
In this format, each record is represented as an individual element. Each field is also
represented as an element, but nested within a record element.
Attribute-centric XML
Records formatted in attribute-centric XML look like this:
In this format, each record is represented as a single-tag element (each element is given the
same name as the associated cursor). All field values are represented as an attribute of a record
element. All field values are represented as strings regardless of their original type. As you can
see, attribute-centric XML is more concise than element-centric.
Raw XML
Records formatted in raw XML look like this:
This format is the same as attribute-centric, except each record element is named “row.”
A schema defines the structure and meaning of an XML document including element
names and data types and attributes. You can use a schema to specify the format you expect for
an XML document.
Schemas can be stored in a separate file, or included in an XML document. Here is an
example of an in-line schema:
If you look closely at the in-line schema, you can see it specifies the name of elements,
whether they are required, their length, and their type. Visual FoxPro 7 supports the W3C
XML Schema standard (XSD). For details, see http://www.w3.org/TR/2000/CR-xmlschema-
0-20001024/.
For a table that shows you how Visual FoxPro data types map to XSD types, see the VFP
7 Help file topic “XML Functions.”
XML namespaces
Namespaces are a way to uniquely identify elements in an XML document. This is important
because the author of an XML document defines its XML tags, and if you merge documents
from multiple authors, you run the chance of a collision occurring between tag names.
You can define one or more namespaces for a document with the xmlns attribute in an
opening XML element tag. The namespace applies to all the contents of an element. Since a
namespace is used to uniquely identify tags, the namespace itself must be unique. Often, XML
document authors choose the URL of their company as a namespace since it’s guaranteed to be
unique. For example:
<VFPData xmlns="www.oakleafsd.com">
<customer iid="1" cacctno="001000" cname="Journey Communications"
caddress1="101 Main St." ccity="Richmond" cstate="VA" czip="22901"/>
<customer iid="4" cacctno="001003" cname="Sergio Vargas, Attorney at Law"
caddress1="115 Pacific Coast Hwy" ccity="Malibu" cstate="CA" czip="80766"/>
</VFPData>
CursorToXML()
The new CursorToXML() function does just what its name says—converts a Visual FoxPro
cursor to XML. This command can be used by business objects to convert internal cursors to
XML that can be consumed by clients.
The syntax of CursorToXML() is:
232 What’s New in Visual FoxPro 7.0
The first parameter allows you to specify either the work area or the alias of the cursor to
be converted. The cOutput parameter specifies the name of a memory variable or file to which
the resulting XML is stored. By default, cOutput specifies a variable name. To specify a file
name, you must set the corresponding bit in the nFlags parameter (see the VFP 7 Help topic
“CURSORTOXML() Function” for details).
The nOutputFormat parameter specifies the output format of the XML (1=Element-centric,
2=Attribute-centric, and 3=Raw).
The cSchemaName, cSchemaLocation, and cNameSpace parameters allow you to specify
information regarding schemas and namespaces. The nFlags parameter allows you to specify
additional output options such as preserving white space, output encoding, and how to format
empty elements.
The following command converts the contents of the Customer table to element-centric
XML and stores the result in a memory variable named lcXML:
CursorToXML("Customer", "lcXML")
This next command converts the contents of the Customer table to attribute-centric
XML, stores the results in a file named Results.XML, and generates an inline schema with a
“www.microsoft.com” namespace:
XMLToCursor()
The new XMLToCursor() function converts an XML string to a Visual FoxPro cursor. This
function can be used by business objects to convert XML input received by clients into an
internal cursor format.
The syntax of XMLToCursor() is:
The cXMLExpression parameter specifies either XML text or an expression that evaluates
to XML data. This can be any one of the following:
• A memory variable.
• A memo field.
• The return from an HTTP request.
• The return from a SOAP method call (see the section “Simple Object Access Protocol
(SOAP)” later in this chapter).
Section 3 Chapter 15: Working with Web Services 233
• XML from the XML DOM (Document Object Model). The XML DOM is a
programming interface for XML documents that allows you to access an XML
document as a tree view with nodes.
• An ADO stream.
Alternately, you can specify the name of an XML file in the cXMLFile parameter. The
nFlags parameter specifies how to handle the first parameter. For details, see the table in the
VFP 7 Help topic “XMLToCursor().”
The cCursorName parameter specifies the name of the cursor to store the results. If this
cursor is in use, VFP generates an error. XMLToCursor() can convert XML with or without
a schema.
The following command converts the Results.xml file to a cursor named “MyCursor”:
XMLUpdateGram()
The new XMLUpdateGram() function returns an XML string listing all the changes in a
buffered table or cursor. You must enable table buffering and SET MULTILOCKS ON before
running XMLUpdateGram().
The syntax of XMLUpdateGram() is:
XMLUpdateGram([cAliasList [, nFlags]])
Updating records
To demonstrate how XMLUpdateGram() works when updating records, launch Visual FoxPro,
go to this chapter’s ProjectX\Data directory, and enter the following in the Command Window:
USE Customer
SET MULTILOCKS ON
CURSORSETPROP("Buffering", 5, "Customer") && Enable table buffering
REPLACE caddress1 with "500 Water St." IN Customer && Make a change
lcUpdateXML = XMLUpdateGram("Customer") && Generate the Update Gram
STRTOFILE(lcUpdateXML, "UpdateGram.xml")
MODIFY FILE UpdateGram.xml
234 What’s New in Visual FoxPro 7.0
The updategram has a single “root” node containing a single <updg:sync> element. Nested
within this element are the <updg:before> and <updg:after> elements. The <updg:before>
element contains a list of the record’s original values for all fields. The <updg:after> element
contains a list of all current values. Notice the <caddress1> element contains the new “500
Water St.” value.
If you use CURSORSETPROP() to set the key field list for the table before running
XMLUpdateGram(), the resulting updategram contains only the key and changed fields. You
can try this by entering the following in the Command Window:
<updg:sync>
<updg:before>
<customer>
<iid>1</iid>
<caddress1>101 Main St.</caddress1>
</customer>
</updg:before>
<updg:after>
<customer>
<iid>1</iid>
<caddress1>500 Water St.</caddress1>
</customer>
</updg:after>
</updg:sync>
</root>
Notice the updategram contains only information regarding two fields—the specified key
field (iid) and the changed field (caddress1).
Adding records
To demonstrate how XMLUpdateGram() works when adding records, enter the following in
the Command Window:
Deleting records
To demonstrate how XMLUpdateGram() works when deleting records, enter the following in
the Command Window:
Notice the <updg:before> element contains the original values of the deleted record and
<updg:after/> is an empty single-tag element.
<root xmlns:updg="urn:schemas-microsoft-com:xml-updategram">
The format used for VFP 7 updategrams is the standard format used by SQL Server 2000.
specifies that business objects should be composed of two pieces—an emissary and an
executant. In a distributed desktop system, the emissary portion of the business object resides
on the workstation, and the executant portion resides on an application server elsewhere on
the network.
When the workstation needs data, it sends a request to the emissary portion of the business
object. Rather than retrieving the data directly, the business object passes the request to an
executant object. The executant retrieves the data from the back end and passes it to the
emissary. What transport mechanism can the executant use to send the data to the emissary?
The most common choices are ADO and XML, but given VFP 7’s new XML capabilities
coupled with VFP 7’s lightning fast string-manipulation abilities, there are compelling reasons
to favor XML.
When the business object on the workstation receives the requested data as an XML
string, it can convert it to a VFP cursor to be consumed by the desktop application. The
application can manipulate the cursor—editing, adding, and deleting records. When the user
saves changes, the emissary can run XMLUpdateGram() against the VFP cursor and pass the
resulting updategram to the executant, which then applies the changes to the back-end database.
VFPXMLProgID
The new _VFP.VFPXMLProgID property allows you to specify a COM component that
can be used instead of the built-in VFP 7 XML functions (CursorToXML(), XMLToCursor(),
XMLUpdateGram()).
This property specifies the programmatic identifier (ProgID) of the surrogate COM
component. The COM component you specify must implement VFP 7’s IVFPXML interface.
The VFP 7 Help topic “VFPXMLProgID Property” gives an example creating a COM object
that implements this interface.
Table 3. Some of the more interesting Web Services available on the Internet.
In addition to using the Web Services provided by other sites, you can also publish your
own VFP 7 COM servers as Web Services that others can access.
The SOAP Toolkit 2.0 comes with an excellent Help file (Soap.CHM)
located in the MSSOAP/Documentation folder. Rather than duplicate that
information, this chapter touches on the highlights of the Toolkit. Refer
to the Help file and samples for details.
RPC-oriented operations expect input parameters for input messages, and output messages
contain return values.
SOAP Listeners
A Listener is the entity that handles incoming SOAP messages on the server side. There are
two types of Listeners you can choose from:
• An Internet Server API (ISAPI) Listener
• An Active Server Pages (ASP) Listener
From a sheer performance perspective, an ISAPI Listener is the best choice. Some
developers have reported speeds of up to four times faster for an ISAPI Listener. However, if
you want to do some processing between the request received from the client and the call to a
method on a COM object, you may want to implement an ASP Listener instead. You can place
code in an ASP page surrounding the call to the object. See the SOAP Toolkit 2.0 Help topics
“Specifying an ASP Listener” and “Specifying an ISAPI Listener” for details.
For details on using the SOAP Toolkit with Visual FoxPro, check out Rick
Strahl’s white paper “Using Microsoft SOAP Toolkit for remote object
access” at http://www.west-wind.com/presentations/soap/.
Figure 1. The IntelliSense Manager’s Web Services button launches the Web
Services Registration dialog.
3. In the Web Services Registration dialog’s Web Service Name box, specify a
friendly name for the Web Service (see Figure 2). The name can include spaces
(for example, “Language Translation”). A history of all Web Service names you’ve
entered is stored and displayed in the Web Service Name combo box.
Figure 2. The Web Services Registration dialog allows you to register a Web Service
located anywhere on the Internet for use in your applications.
242 What’s New in Visual FoxPro 7.0
4. In the WSDL URL Location box, enter the WSDL URL of the Web Service you are
registering. For example: http://www.xmethods.net/sd/BabelFishService.wsdl.
5. Click the Register button.
At this point, the dialog generates IntelliSense scripts based on the information you have
entered. Note that this may take several seconds with no visual cue that any processing is going
on! When the process is complete, you will see the dialog shown in Figure 3.
Figure 3. This dialog displays when your Web Service registration has successfully
completed. Note that it may take quite a while for this dialog to appear.
Click the OK button to close this dialog. Your new Web Service is added to the list in the
Types tab of the IntelliSense Manager. The next section discusses how you can access the new
Web Service.
ItManager.
is not required that you register a Web Service using the IntelliSense
However, if you do, VFP provides IntelliSense for Web Service
methods and parameters.
LOCAL loTranslate AS
2. In the dropdown list of IntelliSense types, select a Web Service. For example:
3. When you press the Enter key, Web Service proxy code is automatically added to
your source file. For example:
loTranslate =
loWS.SetupClient("http://www.xmethods.net/sd/BabelFishService.wsdl",
"BabelFish", "BabelFishPort")
This code instantiates the VFP 7 WSClient base class (loWS) and then creates a
SOAP client object (loTranslate).
?loWS.BabelFish("en_es","fox")
This code tells the Babel Fish Web Service to translate the word “fox” from English
to Spanish (“en_es”) and display it on the VFP desktop.
Server
In order to publish Web Services, you must have Internet Information
installed.
2. Right-click your VFP COM server project and select Builder from the context menu
(see Figure 4). This launches the Wizard Selection dialog. In the Wizard Selection
dialog, select Web Services Publisher and click OK.
3. If this is the first time you have published a Web Service, the dialog in Figure 5 is
displayed recommending that you select a default URL for your Web Service support
files such as ASP Listeners and WSDL and WSML files. Specifying a default
directory is not mandatory, but if you don’t specify one, you are prompted for a
location each time you publish a Web Service. Click OK to launch the Web Service
Location dialog.
244 What’s New in Visual FoxPro 7.0
Figure 4. You can launch the Wizard Selection dialog from the Project Manager
context menu. You can also launch it by selecting Tools | Wizards | All Wizards from
the VFP 7 menu, and selecting Web Services Publisher in the Wizard Selection dialog.
Figure 5. The first time you publish a Web Service, the Web Services
Configuration dialog displays recommending that you select a default URL for
your Web Service files.
4. In the Web Service Location dialog, select an existing virtual directory for your Web
Services support files or create a new one (see Figure 6).
You can select an existing virtual directory by clicking the Existing option and
selecting a directory from the Select Virtual Directory combo box.
Section 3 Chapter 15: Working with Web Services 245
You can select a new directory by clicking the New option and entering a directory
name in the New Virtual Directory Name box. Next, click the Path command button
and specify the physical path for the new virtual directory. Typically, you should
create a new directory under your c:\inetpub\wwwroot directory.
Figure 6. The Web Service Location dialog allows you to specify a default virtual
directory for your Web Services support files.
The information entered in this dialog gets saved to a table named FoxWS.DBF
located in your Visual FoxPro 7 program directory.
5. Click the Select button to continue. This launches the Web Services Publisher dialog
(see Figure 7). By default, the COM Server combo box contains a list of all COM
servers associated with open projects as well as previously published COM servers.
Select a COM server from the combo box or click the ellipsis button to select a COM
server that is not in the list.
6. The Select Class combo box displays a list of OLE public classes in the selected
COM server. Select the class you want to publish. If the COM server you choose has
only one class, the combo box is disabled.
If the class you choose contains Currency or Variant parameter or return value types,
an “information” image is displayed next to the Select Class combo box (see Figure
7). If you click on this image, a dialog displays telling you to specify strong typing for
these; otherwise, an invalid WSDL file may be generated.
246 What’s New in Visual FoxPro 7.0
Figure 7. The Web Services Publisher dialog allows you to generate Web Service files
for a VFP 7 COM component.
7. If you click the Advanced button, it launches the Web Services Publisher dialog
shown in Figure 8. This dialog allows you to specify additional information such as:
For details on these settings, see the VFP 7 Help topic “Web Service Publishing.”
If the Web Services Publisher is successful, it displays a dialog similar to the one shown in
Figure 9.
Section 3 Chapter 15: Working with Web Services 247
Figure 8. The Advanced Web Services Publisher dialog allows you to specify
additional information regarding the generated Web Service files.
Figure 9. The Web Services Publisher displays the Results dialog if it successfully
publishes Web Services for your COM component.
248 What’s New in Visual FoxPro 7.0
The primary by-products of the publishing process are the WSDL and WSML files.
These files are stored in the directory you specified in the Web Services Publisher dialog. Here
is a partial listing of a WSDL file generated from the example ProjectX Customer class (all
methods have been protected except GetCustomerByAcctNo):
Here is the associated WSML file generated by the Web Services Publisher:
Section 3 Chapter 15: Working with Web Services 249
For an explanation of the contents of these files, check the SOAP Toolkit 2.0 Help files.
If the Web Services Publisher encounters errors while mapping data types during
generation of the Web Services files, you will see the dialog shown in Figure 10. You can
examine the resulting WSDL file to determine the parameters and/or return values that could
not be mapped.
Figure 10. The Web Services Publisher lets you know if errors are encountered when
mapping data types of your COM component’s methods.
Summary
Once again, the Fox team has done a great job of keeping Visual FoxPro in line with the future
of software development. The enhancements to VFP 7 for XML and Web Services make it
even easier to build distributed, Web-based, “next generation” applications.