Class: cWebService
Properties | Events | Methods | Index of Classes
Creates Web Service Objects - the basic component of all web-service based Web Applications.
Hierarchy
- cObject
- cBaseWebComponent
- cWebComponent
- cWebService
Library: Web Application Class Library
Package: cWebService.pkg
Mixins: cCallInterfaceHelper_mixin
Description
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 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 Windows 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 objects are created within the DataFlex Studio as follows:
- Create a New WSO component.
- Create your functions (operations) that you wish to make public.
- Publish these functions.
- Document the operations and the service.
- Set the name of the service.
- Save the component and add it to your web-application.
Here are these same steps, described in more detail:
-
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.
-
Select "Web Service Object". This will create a new Web Service component.
-
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 End_FunctionNote 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.
-
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-clicking on the function, and selecting 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 = "" } -
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.
-
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 finding 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 descriptions within the edit area.
Set psDocumentation to ; ("DataFlex Web Service .... " +; " ... " + ; "documentation") -
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.
-
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:
- Fundamental data types - these are the built-in simple data types (e.g., string, integer).
- Struct data types - these are custom data types created using the struct command (e.g., tMyOrder).
- Arrays - these can be arrays of fundamental or struct data types (e.g., string[], integer[][], MyOrder[]).
- XmlHandle - this is a special type that indicates that the data is passed as XML.
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:
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
End_Function
Function SayHello String sName Returns String
String sReturn
Move ("Hello," * sName) to sReturn
Function_Return sReturn
End_Function
Function TestDateTime DateTime dDateTime Returns String
String sReturn
Move ("The datetime in DataFlex locale is" * string(sDateTime)) to sReturn
Function_Return sReturn
End_Function
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
End_Struct
Function GetCustomerInfo integer iCustNum Returns tCustomerInfo
tCustomerInfo CustomerInfo
Get CustomerInfo iCustNum to CustomerInfo // this finds the customer and fills the struct data
Function_Return CustomerInfo
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
End_Struct
// Order
Struct tOrder
integer iOrderNumber
integer iCustNumber
date dOrdDate
string sTerms
string sShipVia
string sOrderedBy
string sSalesPerson
real rOrderTotal
tOrderDet[] ArrayOfDetails
End_Struct
Function GetOrderInfo tOrder TheOrder returns Boolean
Boolean bSuccess
Send SaveTheOrder TheOrder
Function_Return True
End_Function
Arrays
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 passed an array of customer 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 fills the struct data
Loop
Function_Return Customers
End_Function
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
End
End
End
//
Send Destroy Of hoCust
Loop
Send Destroy Of hoList
Function_Return CustomerList
End_Function
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 DateTime:
Struct tNDateTime
Boolean bNull
DateTime Value
End_Struct
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 nullable
tNDateTime dtLastAccess
End_Struct
{ Published=True }
{ Description="" }
Function OrderUpdate tOrder orderData Returns Boolean
Boolean bResult
// process order
Function_Return bResult
End_Function
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 passed to the web service call:
Procedure CallWebService String sCustFirst String sCustLast
tOrder orderData
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
End_Procedure
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 array of structs as follows:
Struct tCustomerList
integer iCustomerNumber
string sCustomerName
Boolean bDelete
End_Struct
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
End
End
Else Begin
Move False to bWasDeleted
End
If not bWasDeleted
Move CustomerList[i] to NewCustomerList[iNewCount]
Increment iNewCount
End
Loop
Function_Return NewCustomerList
End_Function
Usage
Example:
Use cWebService.pkg
Use DataDict.pkg
Use CUSTOMER.DD
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 kinds of good" +;
"things to make your life easier")
Set psServiceName to "HelloService"
Set psServiceURI to "http://tempuri.org/"
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
End_Function
Send RegisterInterface get_Hello "get_Hello" "string sFirst string sLast Returns string" "What do you think it's going to do."
End_Object // oHelloWSO
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.