Class: cWebService

Properties  Events  Methods    Index of Classes

Creates Web Service Objects - the basic component of all web-service based Web Applications



Library: Web Application Class Library

Package: cWebService.pkg

Mixins: cCallInterfaceHelper_mixin


Web Applications consist of a web application object (cWebApp) that contains Web Objects (WOs). Web Objects can be Web Browser objects (WBOs - Web Views (cWebView), Web Dialogs (cWebModalDialog)) or Web Service Objects (WSOs - cWebService).

Web Service Object creates a Web-service. This web-service contains operations that can be called by remote clients. Each operation corresponds to a function inside of your WSO. You can make these functions do anything a normal DataFlex can do (in other words, you can do anything). WSO objects may contain a Data Dictionary object structure (DataDictionary). This makes it easy to create web-services that communicate with your data and your data logic.

Web Service Objects are used to communicate with web-service clients. A web-service client will be part of some remote application. When needed, the application will make a call to the web-service client and the client will make the request to a web service. If this web service is part of a DataFlex web-application, the request will be sent to as a function call within the WSO. This function will do whatever it needs to do, and return information to the client. Web Service clients are built in a DataFlex windowss application using the cClientWebService class.

WSDLs - Service Descriptions

It is expected that any web-service provide a description of its service. This is done by providing a formal service description document that describes exactly how the service should be accessed. This document is called a WSDL document (Web Service Description Language).

A WSDL document tells you everything you need to know about a web-service. It tells you where the service is located, how it is accessed and what operations are available for the service. It defines the parameters and data-types for each operation. It also specifies exactly how the SOAP request and response should be encoded.

A WSDL document is an XML file. While it is human readable, it is really designed to be written (generated) and read (parsed) by a computer. On the server side, the DataFlex web-application server generates WSDL documents. On the client side, DataFlex contains a parser that reads WSDL documents and creates client web-service classes.

SOAP Headers

The SoapHeaderRequestNode and AddSoapHeaderNode methods provide a low level mechanism for working with SOAP headers.

Creating a Web Service Object

Web Service obejcts are created within the DataFlex Studio as follows:

Here are these same steps, described in more detail:

1. In the Studio, select the "File | New | Web Object." file menu option. You may also access Web Objects using the New button in the toolbar.

2. Select "Web Service Object". This will create a new Web Service component.

3. Using the Studio's code editor, edit the source code of the Web Service Object and write your code. To keep it simple, we suggest that you create a simple "Hello World" function to start with. This function may look like the following:

Function Hello string sName string sLast returns string
    string sReply
    Move ("Hello," * sName - ", how are you today") to sReply
    Function_Return sReply

Note that this is a very simple example. A WSO object is a business process object and is capable of performing sophisticated operations. You can create data-dictionary object structures within the WSO and use web-service operations to store and retrieve data from your DDOs. You can create additional private processing methods within your WSO, which can be called by your public web-service operations. Additionally, you can choose to have your public operations access program logic outside of your WSO. Think of a web-service operation as a portal into your application, your application logic and your application data.

4. A WSO may contain many functions and not all of them should be exposed as a web-service. You expose a web-service method by publishing it. You do this by finding that method in Code Explorer's outline (the tree view on the left), right-click on the function and select Published from the context menu. After publishing the function, the Studio has inserted the following meta-data tags above the function declaration line in your source code:

{ Published = True }
{ Description = "" }

5. You may create an optional but recommended comment for any web-service function. This comment will be published as part of the service's description in the WSDL file. Type some descriptive text inside the quotes of the Description meta-data tag.

6. You will want to create a description for the entire web-service to be published as part of the service's description. You can do this by find the following source code and replacing it with meaningful information. This is done by setting the psDocumentation property within your code. Note that this source is broken up into multiple lines to demonstrate how to create long, yet readable description within the edit area.

Set psDocumentation to ;
    ("DataFlex Web Service .... " +;
          " ... " +  ;

7. You need to set the Service name. This name uniquely identifies the service within your application and is used by clients to access the service. For example, if the name of your service was "HelloService" in an application whose virtual directory was http://localhost/MyApplication the service would be accessed with the URL http://localhost/MyApplication/HelloService.wso. The name is set with the psServiceName property in the Object Properties window. The default name is tempService.

8. Save and test the component.

You can see more details about creating web services in the Creating Your First Web Service tutorial.

We recommend creating one .WSO file per web service. It makes it easier to use the tools (e.g. Studio) if you do so.

Supported Data Types

Web service parameters may consist of any of the following:

Structs, Arrays and XmlHandle data types can only be used with Document style web services (pbDocumentStyle = true).

Fundamental Data-types

The following fundamental DataFlex data-types can be used as parameters in web-services:

DatetimeFloatChar Uchar

Any of these data-types may be passed or returned in a web-service. All of these data-types will map to an appropriate XML data-type as defined by the XML schema definitions. It is not expected that you will need to use most of these data-types. As with any DataFlex application, you will primarily use String, Number, Date and Integer.

Here are several very simple web-services operations using various data-types:

Function Echo String echoString Returns String
    Function_Return echoString

Function SayHello String sName Returns String
    String sReturn
    Move ("Hello," * sName) to sReturn
    Function_Return sReturn

Function TestDateTime DateTime dDateTime Returns String
    String sReturn
    Move ("The datetime in DataFlex locale is" * string(sDateTime) ) to sReturn
    Function_Return sReturn

Struct Data-types

A web service parameter may be a custom defined type created using the struct command. Using struct parameters allows you to pass and return complex data (e.g. an order), as a single parameter. The struct members may consist of any of the allowed fundamental data types or other structs. Struct members may be defined as arrays.

This sample shows how to define and return struct data.

Struct tCustomerInfo
    integer iCustNumber
    string  sName
    string  sCustAddress
    string  sCity
    string  sState
    string  sZip
    string  sPhoneNumber
    string  sFaxNumber
    string  sEmailAddress
    real    rCreditLimit
    real    rPurchases
    real    rBalance
    string  sComments
    string  sStatus
Function GetCustomerInfo integer iCustNum Returns tCustomerInfo
    tCustomerInfo CustomerInfo
    Get CustomerInfo iCustNum to CustomerInfo // this finds the customer and fill the struct data    
    Function_Return OneCustomer
End_Function  // GetCustomerInfo

The following example is passed a more complex struct parameter that contains a member that is, itself, an array of structs.

// Order Detail
Struct tOrderDet
    string  sItemID
    integer iQty
    real    rUnitPrice
    real    rPrice

// Order
Struct tOrder
    integer     iOrderNumber
    integer     iCustNumber
    date        dOrdDate
    string      sTerms
    string      sShipVia
    string      sOrderedBy
    string      sSalesPerson
    real        rOrderTotal
    tOrderDet[] ArrayOfDetails
Function GetOrderInfo tOrder TheOrder returns Boolean
    Boolean bSuccess

    Send SaveTheOrder TheOrder
    Function_Return True


Any web service parameter may be defined as an array. Arrays may be based on fundamental data types or struct types. Arrays may be single or multi-dimensional. Note that not all web service clients are capable of supporting multi-dimensional arrays.

This sample is passsed an array of customers numbers and returns an array of struct customer information.

Function SelectedCustomerInformation integer[] iCustomers returns tCustomerInfo[]
    tCustomerInfo[] Customers
    integer i iCustomerCount

    Move (SizeOfArray(iCustomers)) to iCustomerCount
    For i from 0 to (iCustomerCount-1)
        Get CustomerInfo iCustomers[i] to Customers[i] // this finds the customer and fill the struct data    

    function_return Customers

XmlHandle Data-type

A special data-type, XmlHandle may be defined as a parameter. The XmlHandle data-type should only be used with web-services. It is used when you define a function`s parameter or return data-type.

Function DelCustomerXMLList XmlHandle CustomerList Returns XmlHandle

Defining this data-type in a web-service function indicates that the data being passed and returned is an object handle pointing to an XML Dom object (based on the cXmlDomDocument class). This provides an easy mechanism for passing data as pure XML. Within your program you treat an XmlHandle data-type exactly the same way you would treat any object handle. The object can be parsed and processed using the standard methods provided for handling XML DOM objects.

The one important distinction about this data-type is that the DataFlex web-services module will automatically handle the disposal of these objects when they are no longer needed. You do not need to destroy these objects yourself.

For example, this web-service operation is passed an XML document containing customer information. The service will search for customers to be deleted and attempt to delete these based on the rules in the data-dictionary. It will then return an XML document containing a list of remaining customers. Notice that the XML data is passed in and out as objects.

Function DelCustomerXMLList XmlHandle CustomerList Returns XmlHandle
   Integer bOk i iItems
   Handle hoRoot hoList hoCust hoWrapper hoXml1 hoRoot1
   String sDel sNumber
   Handle hoCustomerDD hoXML
   Move Customer_dd to hoCustomerDD
   If not CustomerList function_return 0
   Get DocumentElement Of CustomerList To hoRoot
   // create node list of all customers
   Get FindNodeList Of hoRoot "Customer" To hoList
   Get NodeListLength Of hoList To iItems // number of items in our node list.
   Decrement iItems
   // go through array looking for customers to delete
   For i From 0 To iItems
       Get CollectionNode Of hoList i To hoCust
       // if attribute "Delete" is "Y" we will delete it
       Get AttributeValue Of hoCust "Delete" To sDel
       If (sDel="Y") Begin
            // attempt to delete customer
            Get ChildNodeValue Of hoCust "Number" To sNumber
            Send Clear of hoCustomerDD
            Move sNumber to Customer.Customer_number
            Send Find of hoCustomerDD eq 1
            If (found) Begin
                Send Request_delete of hoCustomerDD
                If not (err) begin
                    Get RemoveNode Of hoRoot hoCust To hoCust
       Send Destroy Of hoCust
   Send Destroy Of hoList

   Function_Return CustomerList

Nullable Data Types

DataFlex does not natively support the concept of null in data types. Nullable data types are supported by creating a struct type with a Boolean bNull member. This is already provided for simple data types in tSimpleNullTypes.pkg. For example, for DataTime:

Struct tNDateTime
    Boolean bNull
    DateTime Value

If you are creating a custom data type that requires null support, each struct member needs to support nulls using this method.

In your web service code, you can use this as follows:

Use cWebService.pkg
Use tSimpleNullTypes.pkg

Struct tOrder
    DateTime dtOrderDateTime
    String sCustomerFirst
    String sCustomerLast
    // allow this DateTime column to be nullabe
    tNDateTime dtLastAccess

{ Published=True }
{ Description="" }
Function OrderUpdate tOrder orderData Returns Boolean
    Boolean bResult

    // process order

    Function_Return bResult    

On the client side, this would be accessed as such. This method would probably be called inside a dbView, where the data is entered in data entry objects (DEOs) such as dbForms and then pased to the web service call.

Procedure CallWebService String sCustFirst String sCustLast 
    tOrder orderData dToday
    Boolean bResult

    Move (CurrentDateTime()) to dtNow

    Move dtNow to orderData.dtOrderDateTime
    Move sCustLast to orderData.sCustomerLast
    Move sCustFirst to orderData.sCustomerFirst
    Move True to orderData.dtLastAccess.bNull  // passes a null to the nullable data type

    Get OrderUpdate of oOrderWebService orderData to bResult               

Using XmlHandle versus Using Struct/Array Data-types

Passing data as pure XML has advantages and disadvantages. This provides a mechanism for passing and returning complex data. Often this type of complex data is most efficiently processed as an XML DOM object. The disadvantage of using XML as a parameter is that the data is not fully defined within the WSDL description. The WSDL document simply knows that the data is a well formed XML document.

If you need to pass complex data that is fully defined within the WSDL description, you can pass the parameters as structs and arrays. The above example could easily be rewritten to use an arrays of structs as follows:

Struct tCustomerList
    integer   iCustomerNumber
    string     sCustomerName
    Boolean bDelete
Function DelCustomerXMLList tCustomerList[] CustomerList Returns tCustomerList[]
    tCustomerList NewCustomerList
    Integer i iCustomerCount  iNewCount
    Boolean bWasDeleted

    Move Customer_dd to hoCustomerDD

    Move (SizeOfArray(CustomerList)) to iCustomerCount 
    // go through node list looking for customers to delete
    For i From 0 To (iCustomerCount-1)

        If CustomerList.bDelete begin
            // attempt to delete customer
            Send Clear of hoCustomerDD
            Move CustomerList.iCustomerNumber to Customer.Customer_number
            Send Find of hoCustomerDD eq 1
            If (found) Begin
                Send Request_delete of hoCustomerDD
                Move (not(err)) to bWasDeleted // it is possible the delete will not be allowed
       Else Begin
            Move False to bWasDelete
       if not bWasDeleted
           Move CustomerList[i] to NewCustomerList[iNewCount]
           Increment iNewCount
    Function_Return NewCustomerList



Use cWebService.pkg
Use DataDict.pkg


Object oHelloWSO is a cWebService

    // psDocumentation provides high level documentation of your web service. Clients using
    // this service will see and use this documentation.
    Set psDocumentation to ;
        ("DataFlex Web Service that can do all kind of good" +;
          "things to make your life easier")
    Set psServiceName to "HelloService"
    Set psServiceURI to ""
    Set psServiceTitle to "DataFlex Web Service"

    Object Customer_DD is a Customer_DataDictionary
        Send DefineAllExtendedFields
    End_Object    // Customer_DD

    Set Main_DD to Customer_DD

    Function Hello string sFirst string sLast returns string
        string sReply
        Move ("Hello," * sFirst * sLast - ", here we are again") to sReply
        Function_Return sReply

    Send RegisterInterface get_Hello "get_Hello" "string sFirst string sLast Returns string" "What do  you think it's going to do."
End_Object    // oHelloWSO

Note: The RegisterInterface message determines which functions in your WSO should be exposed as a public operation. Methods are registered by publishing them within the Studio