34
Team Developer & Web Services By Jean-Marc Gemperle - Technical Support Web Services introduction and description based on the work of Suren Behari (Team Developer Web Services Toolkit white paper) April 2006

Team Developer & Web Services

  • Upload
    others

  • View
    2

  • Download
    0

Embed Size (px)

Citation preview

White Paper Template 2005Team Developer & Web Services
By Jean-Marc Gemperle - Technical Support Web Services introduction and description based on the work of Suren Behari (Team Developer Web Services Toolkit white paper)
April 2006
Abstract.....................................................................4
HTTP GET............................................................................. 5
Anatomy of a WSDL file ....................................................... 6
types ................................................................................... 6
messages ............................................................................ 7
Service ................................................................................ 9
Gupta HTTPREQUEST interface ................................11
Consuming web services via HTTPREQUESTER ........13
Soap Envelope ................................................................... 14
Invoking a JAVA Web Service ............................................ 16
Invoking a Team Developer Web Service........................... 18
Copyright © 2006 Gupta Technologies, LLC
Creating a Simple Web Service with .NET ................20
Team Developer Web Services creation...................25
Consuming Web Services via the MS SOAP toolkit ...29
Conclusion...............................................................34
Abstract
In this paper we will talk specifically about consumption of Web Services using the newly introduced feature in Team Developer 2005.1, the HTTPREQUEST Object found in the XML library and we will also cover the creation and consumption of Web Services in general using Team Developer.
Overview As businesses embrace the Internet as a means for communicating with each other, the need for easy to implement, Internet-based information exchange has grown. Over the past few years many technologies like DCOM have been used for this, but somehow failed in gaining acceptance. Web services are the next step in the evolution of the World Wide Web, allowing programmable elements to be easily deployed on any Web site so that others can access its distributed behavior, regardless of the system and architecture used. Because the underlining technology of Web Services is the ubiquitous HTTP protocol and XML, the accepted standard for data exchange, Web services, is becoming the programmatic backbone for electronic commerce. Web Services with Team Developer are nothing new. SQLWindows 1.5.0 was the first version to support XML in the form of a COM object from Microsoft MSXML. This COM Object also contains an HTTPREQUEST interface, thus containing all the required components for Web Services consumption at a low level. Since then, Team Developer 2.1 solutions were proposed by Gupta to consume and provide Web Services, using the SAL Proxy Generator utility written by Suren Behari. Solutions to consume Web Services also came from the SQLWindows community; see COM WS solution from Lubos Vnuk at http://sqlweb.vnuk.org/index.htm##gup/index.htm##articles/comws.h tml
All those solutions are dependent on MSXM or the MS SOAP Toolkit and also provide extra ease of use in consuming Web Services, thus at a higher level than the use of the MSXML HTTPREQUEST object. Since Team Developer 2005.1 Gupta has included its own XML interface to access XML documents via the Document Object Model (DOM) and later included an HTTPREQUEST interface. This paper also will discuss the creation of Team Developer Web services using the MS SOAP toolkit, .NET simple Web Service creation and the consumption of those services using the HTTPREQUESTER as well as using the MS SOAP Toolkit client, another way to consume Web Services with Team Developer.
Page 4
Page 5
What is a Web Service? XML Web Services are pieces of program logic that are exposed publicly, either on an intranet, extranet, or the Internet. They enable disparate systems to exchange data using Internet standards such as HTTP, XML and SOAP. By implementing the use of standards, XML Web Services become accessible to any client, regardless of their system or architecture. This infrastructure supports the exchange of data in a format that can be used by .NET applications and non-.NET applications, since the data exchange is done using XML, which is text- based, and can be used (to some degree) by any system. Since XML is self-describing, the data exchanged is immediately useful and easily interpreted. Basically, XML Web Services are black boxes of programming logic that abstract the functionality away from the consuming application. The consuming application only needs to know how to invoke the XML Web Service, and what to expect in return. Beyond that, the consuming application is oblivious to what is happening in the XML Web Service. As developers, we can build applications that expose methods over the Internet in the form of XML Web Services. An XML Web Service can be exposed for the intended user, whether that is the world as a whole, a private client, or for use internally on an intranet, by either telling the client where to find the XML Web Service (the URL), or by registering the XML Web Service in the Universal Description, Discovery and Integration (UDDI) database. UDDI is a global organization trying to broaden the acceptance and use of XML Web Services, essentially a registry for XML Web Services. Potential clients can search the UDDI registry to find XML Web Services that match their business needs. When an XML Web Service is created, a Web Service Description Language (WSDL) document is created with it. The WSDL is essentially a contract that a consumer agrees to, which specifies the exposed methods of invoking the XML Web Service, the inputs expected, and the outputs that will be returned. The URL for the WSDL is listed in the UDDI registry, so potential clients can discover it. If we are privately informing a client about the XML Web Service, the URL for the WSDL is all they need to implement the XML Web Service (although a document explaining what the XML Web Service is for may be nice). The WSDL contains all the information needed to invoke the XML Web Service.
How are Web Services implemented? The implementation of these methods is done through cross-Internet calls to the method using HTTP or HTTPS, and accepting the return values as XML. The data exchange can occur using one of three protocols:
HTTP GET XML Web Services are invoked using a basic GET request
Copyright © 2006 Gupta Technologies, LLC
over HTTP. Any inputs are passed in the query string. The results are returned as an XML document.
HTTP POST XML Web Services are invoked using a basic POST request over HTTP. Any input values are passed in the HTTP POST body. The results are returned as an XML document.
SOAP XML Web Services can be invoked using a SOAP message passed over HTTP. Any inputs are passed in the SOAP message body, and the return values are passed in the body of a new SOAP message. For XML Web Services that take in or return simple data types, such as strings or integers, any input arguments can be passed to the method as HTTP GET (query string), HTTP POST (form post) values, or in the body of a SOAP message. For XML Web Services that either take in or return complex types, such as DataSets, images, or objects, method arguments are serialized to XML and sent and received in the body of a SOAP message.
What is a Web Service Description Language file? The WSDL describes the inputs, including data type and name, and the outputs, also including data type and name, for HTTP GET, HTTP POST and SOAP invocation. As long as the XML Web Service interfaces do not change, the WSDL will remain the same. This means that the XML Web Service provider can make changes to the logic, as long as the inputs and outputs don’t change, and the client will not be affected. For example, as a provider of an XML Web Service, we can change what database we are connecting to, or how the logic performs, provided the expected inputs and outputs do not change, and the client will never know we made the change.
Anatomy of a WSDL file Below are the key XML elements of a WSDL document. It is important to understand the WSDL document completely before you can construct the SOAP envelope you intend to send, via the GUPTA HTTPREQUESTER, to the Web Server hosting the Web Services.
types This is a container for the definition of complex data types for message exchange. In the sample below, there are no complex data types so there are no data types defined in this element. <types> <schema targetNamespace='http://tempuri.org/GuptaWebServiceTest/type/' xmlns='http://www.w3.org/2001/XMLSchema' xmlns:SOAP-ENC='http://schemas.xmlsoap.org/soap/encoding/' xmlns:wsdl='http://schemas.xmlsoap.org/wsdl/' elementFormDefault='qualified'> <import namespace='http://schemas.xmlsoap.org/wsdl/'/>
Page 6
Page 6
<import namespace='http://schemas.xmlsoap.org/ws/2002/04/reference/'/>
<import namespace='http://schemas.xmlsoap.org/ws/2002/04/content-type/'/> </schema> </types>
<s:element minOccurs="1" maxOccurs="1" name="pi" type="s:double" /> </s:sequence> </s:complexType> … … </wsdl:types>
messages
This element describes the contents of the messages being exchanged between the client and server. A message has parts that are described by <part> child elements. The example below defines the AddArrays operation to have 2 inputs and 3 outputs. The input message provides the two Arrays to add and the output message returns the result of the addition of the 2 arrays in Result. The AddArrays also defines Array1 and Array2 because the parameters of type anyType is passed by reference. <message name='gws1.HelloWorld'> <part name='s1' type='xsd:string'/> </message> <message name='gws1.HelloWorldResponse'> <part name='Result' type='xsd:string'/> </message> <message name='gws1.AddArrays'> <part name='Array1' type='xsd:anyType'/> <part name='Array2' type='xsd:anyType'/> </message> <message name='gws1.AddArraysResponse'> <part name='Result' type='xsd:anyType'/> <part name='Array1' type='xsd:anyType'/> <part name='Array2' type='xsd:anyType'/> </message>
portType This element lists a set of operations, each assigned to a separate operation child element. For the sample below, the operations are HelloWorld and AddArrays. Each operation child element has two child elements, input and output, describing the input and output for the related operation. The parameterOrder attribute tells the order in which the parameters should be passed.
Page 7
<portType name='GuptaWSTestSoapPort'> <operation name='HelloWorld' parameterOrder='s1'> <input message='wsdlns:GuptaWSTest.HelloWorld'/>
<output message='wsdlns:GuptaWSTest.HelloWorldResponse'/> </operation> <operation name='AddArrays' parameterOrder='Array1 Array2'> <input message='wsdlns:GuptaWSTest.AddArrays'/> <output message='wsdlns:GuptaWSTest.AddArraysResponse'/> </operation> </portType>
bindings Each portType element described above identifies an operation and there is a corresponding binding element that provides the protocol details for the operation. The sample below displays 2 bindings, one for each operation HelloWorld and AddArrays. <binding name='GuptaWSTestSoapBinding' type='wsdlns:GuptaWSTestSoapPort' > <stk:binding preferredEncoding='UTF-8'/> <soap:binding style='rpc' transport='http://schemas.xmlsoap.org/soap/http'/> <operation name='HelloWorld'> ... </operation> <operation name='AddArrays'> ... </operation> </binding>
The type attribute type='wsdlns:GuptaWSTestSoapPort' in the binding element gives the name of the portType for the corresponding binding. The binding element in this sample has 3 child elements: stk:binding : preferredEncoding Determines the character encoding soap:binding : Is a child of the binding element that uses the attributes below to define the protocol details. style='rpc' attribute: Sets all the operations in this binding to be Remote Procedure Call type operations. transport='http://schemas.xmlsoap.org/soap/http' attribute value: Sets the SOAP messages to be sent over HTTP.
Operation from the binding element <soap:operation soapAction='http://tempuri.org/GuptaWebServiceTest/action/GuptaWSTest.HelloW orld'/> <input> <soap:body use='encoded' namespace='http://tempuri.org/GuptaWebServiceTest/message/' encodingStyle='http://schemas.xmlsoap.org/soap/encoding/' parts='s1'/> </input> <output> <soap:body use='encoded' namespace='http://tempuri.org/GuptaWebServiceTest/message/' encodingStyle='http://schemas.xmlsoap.org/soap/encoding/' parts='Result'/> </output> </operation>
soap:operation Element Indicates the soapAction. The soapAction HTTP header must be set in the HTTP headers, for a client to successfully invoke the method HelloWorld or Addarrays
Page 8
Copyright © 2006 Gupta Technologies, LLC
input and output Elements Both of these elements include a soap:body element, indicating that the SOAP request and response messages specifying that the operation will contain only SOAP body (no header). If the operation request or response included a SOAP header, then a soap:header element would also appear in the input, output elements.
The use attribute specifies the encoding; when a user is creating/serializing a SOAP message, it can use either encoded or literal formats. The encodingStyle attribute specifies the type of encoding to be used on the various message parts. The parts attribute indicates the name of the parameter(s) or return values. Service When invoking an operation, a SOAP client must identify the service, the port in that service, and the input parameter name, order and type of the operation to be executed. For this identification, the service element contains one or more port child elements. In turn each port child element contains: The name attribute which uniquely identifies the port in the WSDL document. The binding attribute which refers to the binding element seen before. The soap:address element that provides the address of the server SOAP request handler.
<service name='gws1' > <port name='gws1SoapPort' binding='wsdlns:gws1SoapBinding' > <soap:address location='http://proxima.xs4all.nl:8080/GuptaWS/gws1.WSDL'/> </port> </service>
How do provider and consumer interact? XML Web Services are based around the concept of a provider and a consumer. The provider is the application that exposes the XML Web Service and the consumer is an application that uses the XML Web Service. The user of an application should never see the XML document returned from an XML Web Service. Rather, the application consumes the XML Web Service, and uses the data to provide output to the application user.
Page 6
Page 9
Copyright © 2006 Gupta Technologies, LLC
The figure below shows the communication between the consumer and the provider.
A consumer application connects to an XML Web Service provider. The steps that occur are as follows:
• The consumer finds an available XML Web Service either in the UDDI registry or directly from the provider (not shown).
• The consumer makes a request to the provider for the WSDL document.
• The provider returns the XML-based WSDL document. • The provider makes a request to the XML Web Service in
the WSDL document, passing in any required arguments as defined in the WSDL.
Page 10
Page 11
• The provider processes the request, performing any functions necessary to complete the request, and returns the result to the consumer as either an XML document or a SOAP message.
Gupta HTTPREQUEST interface With Team Developer 2005.1, XML document handling was introduced in the form of a new Class Library XMLIB.APL, a Team Developer Document Object Model (DOM) library based on the Xerces-C XML parser http://xml.apache.org see http://www.guptaworldwide.com/DevCenter/WhitePapersDisplay.aspx? ProdID=2 Team Developer and XML. This now allows a Team Developer programmer to access their XML document without having to use third party libraries like the COM based library from Microsoft (MSXML). Because both MSXML and the GUPTA libraries are based on the DOM standard, they are similar in terms of object and member features and behavior. With version 2005.1 PTF1, a new OBJECT HTTPRequest was introduced in the XML library. While this object is part of XMLIB.APL library, the same as the equivalent MS XMLHttpRequest object, those objects are not limited to being used with XML; they can request or send any type of document and also allow you to SET HTTP HEADERS.
In this section we will focus on using this OBJECT to SEND a SOAP REQUEST in order to consume Web Services.
HTTPREQUEST Object With an HTTP request, an application can make any request to, and get a response from, a web server. This allows the SOAP envelope to be sent to a server and the response to be returned. To use this feature, just include XMLLIB.APL in your Team Developer application and instantiate a HTTPREQUEST object.
Typical HTTP access/response calls to send and receive XML Below is the ascending order of calls a typical application would need to consume a Web Service.
• Boolean open(nMethod, sURL, sUser, sPassword) Initializes the HTTPREQUEST request object and specifies the method, URL, and authentication information for the request. nMethod: HTTP method used to open the connection, such as HTTP_GET, HTTP_POST, HTTP_PUT sURL: Requested URL. Must be an absolute URL, ie: http://localhost/TestWebServicesWithGupta/Service1.asmx?wsdl sUser, sPassword: Name of the user and password for authentication. Example: Call oRequest.open( HTTP_GET, sEndPoint,'','' )
• Boolean setHTTPHeader(sHeader, sValue)
Copyright © 2006 Gupta Technologies, LLC
Specify the name of an HTTP header. sHeader: Header name to set sValue: Value of the header Example: Set sHTTPHeader = "Content-Type: " Set sHTTPValue = "text/xml; charset=utf-8" Call oRequest.setHTTPHeader( sHTTPHeader, sHTTPValue )
• Boolean sendXML(oXMLDocumentToSend) Sends an HTTP request to the server and receives a response. oXMLDocumentToSend: A XMLDocument object Example: If NOT oRequest.sendXML( oSOAPEnvolope )
Call oRequest.getLastError( nError, mlSOAPMsg ) • Boolean getResponseXML(oXMLDocumentReceived) Retrieves the HTTP response into a XMLDocument oXMLDocumentReceived: A XMLDocument object Example:
If NOT oRequest.getResponseXML( oSOAPResponse ) Call oRequest.getLastError( nError, mlSOAPMsg )
Sending and receiving text instead of XML
• Boolean sendText(sContent) • Boolean getResponseText(sResponse)
To retrieve HTTP Headers
• Boolean getAllResponseHeaders(sHeadersReceived) Retrieves the values of all the HTTP headers. sHeadersReceived: The received headers values
• Boolean getResponseHeader(sHeader, sValueReceived) Get the value of an HTTP header from the response body. sHeader: Header name to get sValueReceived: The received header value
Error Handling All methods seen above return a Boolean, TRUE if the call succeeds and FALSE if the call fails. The method below allows you to retrieve the error number and message.
• Boolean getLastError(nErrorTypeReceived, sErrorReceived) nErrorTypeReceived: Error Number sErrorReceived: Error Description
Note that currently the HTTPREQUEST object does not support asynchronous access, thus the method open() and setHTTPHeader() will always return TRUE. Only the Send() method might return FALSE. Therefore, it makes sense to check the error using getLastError()
Copyright © 2006 Gupta Technologies, LLC
Synchronous access The HTTPREQUEST object currently only supports synchronous access; if a request is sent to a Web Server, the HTTPREQUEST object waits until a response is returned from the server, thus blocking the application flow. Setting a timeout allows you to decide arbitrarily when a request should time out and return control to the application.
• Boolean setTimeout(nMilSeconds)
nMilSeconds: The time to wait until HTTPREQUEST returns the control to the application
Proxy Server connection The HTTPREQUEST object has no specific methods to connect via a Proxy Server. The setup of the proxy server is independent to the HTTPREQUEST and has to be configured externally. Since the HTTPREQUEST object uses MS WINHTTP internally, the proxycfg.exe configuration tool has to be used. Unfortunately this currently does not work. A defect:
#86908
XMLIB HTTPREQUEST OBJECT can't be used when the connection requires a proxy server and when proxycfg.exe settings as been set properly
addresses the issue.
Secure HTTPS using SSL and certificates Currently the HTTREQUEST has no option to connect using secure HTTPS.
Consuming web services via HTTPREQUESTER Team Developer 2005.1 PTF 1 includes a sample that consumes a Web Service via the HTTPREQUEST object (see CurrencyExchange.apt). In this section we will see further examples that involve different Web Services; .NET, JAVA and Team Developer using the MS SOAP toolkit server and explain the process involved to successfully invoke a Web Service via the HTTPREQUESTER.
Invoking a Web Service is as simple as calling the requester method in this sequence: open(), setHTTPHeader(), sendXML(), getResponseXML(). It is simple because the only thing that matters to the Web Service you intend to invoke is to receive a valid SOAP envelope. If you have it, it is just a matter of sending it. The only difficulty lies in sending a properly serialized XML SOAP envelope to the server along with the right SOAPAction header, so that we get a response back. The response will have to be parsed using the GUPTA DOM XML object from the XMLIB.APL and converting it to the proper data type in the Team Developer application. This low level approach in invoking a Web Service has the advantage of giving you full control of
Page 13
Copyright © 2006 Gupta Technologies, LLC
what you send and receive. All you need to do is map the data types received to the types used in your application.
Soap Envelope It all starts with getting a valid WSDL (Web Service Description Language) document. As we already explained in a previous section the WSDL file tells us about the location of a Web Service, the operations (methods) that it supports and the description of the parameters and results for each operation. Think of it as a XML Type Library. Because we have not covered the creation process of a Web Service yet, we will use Web Services from the internet and get their WSDL contents.
.NET Web Service
Java Web Services
http://webservices.imacination.com/distance/Distance.jws?wsdl The URLs below are .NET Web Services and Team Developer Web Services using the MS Soap Server that were built for this paper. There is no guarantee the server is online when running the sample application.
http://proxima.xs4all.nl:8008/TestWebServicesWithGupta/Service1.asmx?wsdl http://proxima.xs4all.nl:8008/GuptaWS/GuptaWebServiceTest.WSDL
Invoking .NET Web Services In .NET, web services have an .asmx file extension. When the
ASP.NET runtime receives a request for a file with an .asmx extension, the runtime dispatches the call to the web service handler. Using this handler, ASP.NET is able to dynamically create a HTML page describing the service's capabilities and methods. The generated HTML page also provides the user with a way in which to test the web methods within the service. Another advantage of ASP.NET is in publishing Web Service Definition Language (WSDL) contracts.
To test simply open the following URL in your Web Browser http://www.webservicex.net/uklocation.asmx
Your browser should display this :
GetUKLocationByCounty is the Web Services that we will be invoking using the GUPTA HTTPREQUESTER object. Let’s look further at this service by clicking on GetUKLocationByCounty
Page 14
Copyright © 2006 Gupta Technologies, LLC
On this page you can directly invoke the Web Service, but most importantly this comment about SOAP : “The following is a sample SOAP request and response. The placeholders shown need to be replaced with actual values.” This means we have the needed sample envelope given by .NET, so to invoke this Web Service it is a simple matter to copy and paste the envelope in a Team Developer String, feed in the placeholders with data from a data field and invoke the HTTPREQUESTER method as explained previously. Also the envelope clearly shows what the name of the operation is: GetUKLocationByCounty, the parameter(s): County, and result variable: GetUKLocationByCountyResult
Below is a Team Developer application that would invoke and process the response of the Web Service seen above:
HTTPRequest: oRequest XMLDocument: oSOAPEnvolope XMLDocument: oSOAPResponse XMLNode: oNode XMLNamedNodeMap: oNamedNodeMap String: sURL String: sHTTPHeader String: sHTTPValue String: sSOAPEnvolope Number: nError Number: nErrorType Call SalWaitCursor(TRUE) Set sEndPoint="http://www.webservicex.net/uklocation.asmx?wsdl" Set sSOAPEnvolope = '<?xml version="1.0" encoding="utf-8"?> <soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"> <soap:Body> <GetUKLocationByCounty xmlns="http://www.webserviceX.NET"> <County>'||df1||'</County> </GetUKLocationByCounty> </soap:Body> </soap:Envelope> ' If NOT oSOAPEnvolope.loadFromString( sSOAPEnvolope )
Page 15
Page 16
If NOT oSOAPEnvolope.setOutputEncoding( UTF8 ) If NOT oRequest.open( HTTP_GET, sEndPoint,'','' ) Set sHTTPHeader = "Content-Type: " Set sHTTPValue = "text/xml; charset=utf-8" If NOT oRequest.setHTTPHeader( sHTTPHeader, sHTTPValue ) Set sHTTPHeader = "SOAPAction" Set sHTTPValue = "http://www.webserviceX.NET/GetUKLocationByCounty" If NOT oRequest.setHTTPHeader( sHTTPHeader, sHTTPValue ) If NOT oRequest.sendXML( oSOAPEnvolope ) If NOT oRequest.getResponseXML( oSOAPResponse )
Call oSOAPResponse.setFeature( XMLDOC_FORMAT_PRETTY_PRINT, TRUE ) Set mlSOAPMsg = oSOAPResponse.writeToString()
Call oSOAPResponse.getElementsByTagName( oNamedNodeMap, "GetUKLocationByCountyResult" ) Call oNamedNodeMap.first( oNode )
Call SalWaitCursor(FALSE)
This Team Developer code speaks for itself; it is not complicated. For the invocation to be successful you must provide the right SOAPAction: in the HTTP header; the namespace of the GetUKLocationByCounty and the operation name. You might also consult the WSDL document of the service.
The sample above opened the http://www.webservicex.net/uklocation.asmx?wsdl URL. You could also access the Web Service using this URL http://www.webservicex.net/uklocation.asmx
So invoking .NET services using the HTTPREQUEST is simplified because .NET provides us clear information about the Web Service we want to invoke. It is easier than constructing our SOAP envelope by analyzing the WSDL file: Enter this in your Web Browser…
http://www.webservicex.net/uklocation.asmx?wsdl In the WSDL file you would see the operation name supported by this
service and would have to extract the information to build the right SOAP envelope using the description of the WSDL document we explained earlier on.
This Web Service is simple as it passes only a string and returns a string. If the Web Service passes or returns a complex data type, the asmx handler would not generate a testing page for the service. However the SOAP envelope would still be given.
To see this, open http://www.webservicex.net/GenericNAICS.asmx and click GetNAICSGroupByID.
Invoking a JAVA Web Service Here is a service in which you will have to construct the SOAP envelope from the WSDL file.
Open http://webservices.imacination.com/distance/Distance.jws?wsdl in your
browser and search for all getDistance nodes in the XML file. This is what you should find:
WSDL Operations
message="impl:getDistanceResponse"/>
Page 17
</wsdl:operation>
This shows us that the operation getDistance takes 2 input parameters, fromZip and toZip, defined in the message getDistanceRequest and returns a result on getDistanceResponse defined in the message getDistanceResponse. <wsdl:operation name="getDistance">
<wsdlsoap:operation soapAction="" /> <wsdl:input name="getDistanceRequest"> <wsdlsoap:body use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" namespace="http://DefaultNamespace" />
</wsdl:output> </wsdl:operation>
This further tells us about the getDistance operation; the SOAPAction is empty “”, the input name is defined in getDistanceRequest (a message), the namespace for this operation is “http://DefaultNamespace“ and the output name is getDistanceResponse (in a message).
WSDL Messages <wsdl:message name="getDistanceResponse">
<wsdl:part name="getDistanceReturn" type="xsd:double" /> </wsdl:message> This tells us about the output parameter type and name;
getDistanceReturn is of type double. <wsdl:message name="getDistanceRequest"> <wsdl:part name="fromZip" type="xsd:string" />
<wsdl:part name="toZip" type="xsd:string" /> </wsdl:message>
This informs us about the input parameters types and names; fromZip and toZip are of type string.
SOAP Envelope This is our SOAP envelope from the information above, only what is in between the soap:Body tag is specific to the getDistance service.
Set
<soap:Body> <getDistance xmlns="http://DefaultNamespace">
</soap:Body> </soap:Envelope>
SOAPAction Here we set the HTTP header of SOAPAction to be what we found in the WSDL.
Set sHTTPHeader = "SOAPAction" Set sHTTPValue =""
If NOT oRequest.setHTTPHeader( sHTTPHeader, sHTTPValue )
Page 18
Copyright © 2006 Gupta Technologies, LLC
Invocation of the getDistance operation and result extraction Here we send the request to the server and get the response in a XMLDocument object that we parse for ns1:getDistanceReturn.
If NOT oRequest.sendXML( oSOAPEnvolope ) If NOT oRequest.getResponseXML( oSOAPResponse ) Call oSOAPResponse.setFeature( XMLDOC_FORMAT_PRETTY_PRINT, TRUE )
Set mlSOAPMsg = oSOAPResponse.writeToString() If oSOAPResponse.getElementsByTagName( oNodeList, "ns1:getDistanceReturn" ) If oNodeList.first( oNode ) Set df3 = oNode.getTextContent( )
Call oSOAPEnvolope.release( )
Call oSOAPResponse.release( ) Invoking a Team Developer Web Service 'Using the MS SOAP toolkit, you can build Web Services out of any COM
object as long as the COM object uses the IDISPATCH interface (which is the case in a Team Developer COM server) and as long as you use only COM data types. Strings and numbers are allowed. The next section will explain the creation of such Web Services further, but for the moment we will focus on the consumption of such Web Services using the HTTPREQUEST. If you decide to consume such services, chances are you will develop the Web Service yourself. If that is the case, you can test this Web Service using Visual Basic and use the trace utility provided in the MS SOAP toolkit, thus revealing the envelope sent to the server.
Again, there is no guarantee that the web server below will be online when trying to test the sample provided. Making a Web Service from a Team Developer COM application is simple and we will cover that later on.
Open this URL in your browser: http://proxima.xs4all.nl:8008/GuptaWS/GuptaWebServiceTest.WSDL and search for AddArrays node WSDL Operations <operation name="AddArrays">
<soap:operation soapAction="http://tempuri.org/GuptaWebServiceTest/action/GuptaWSTe st.AddArrays" />
namespace="http://tempuri.org/GuptaWebServiceTest/message/" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
parts="Result Array1 Array2" /> </output> </operation> We know the SOAPAction:
http://tempuri.org/GuptaWebServiceTest/action/GuptaWSTest.AddArrays The name space:
http://tempuri.org/GuptaWebServiceTest/message/ The method in parts: takes 2 input parameters Array1 and Array2 and returns 3 output parameters: Result, Array1 and Array2 <operation name="AddArrays" parameterOrder="Array1 Array2"> <input message="wsdlns:GuptaWSTest.AddArrays" /> <output message="wsdlns:GuptaWSTest.AddArraysResponse" />
</operation> The method AddArrays passes 2 parameters and defines an input AddArrays and an output AddArraysResponse message.
WSDL Messages
<message name="GuptaWSTest.AddArrays"> <part name="Array1" type="xsd:anyType" /> <part name="Array2" type="xsd:anyType" />
</message> The input types for the 2 parameters are of type anyType (VARIANT) <message name="GuptaWSTest.AddArraysResponse">
<part name="Result" type="xsd:anyType" /> <part name="Array1" type="xsd:anyType" /> <part name="Array2" type="xsd:anyType" /> </message>
The output types for the 3 parameters are of type anyType (VARIANT) Trying to build the SOAP envelope from the above information seems
relatively easy as in our Java example, but because we are using arrays of specific types it is not.
Set sSOAPEnvolope = '<?xml version="1.0" encoding="UTF-8" standalone="no" ?>
<SOAP-ENV:Envelope SOAP-ENV:encodingStyle="" xmlns:SOAPSDK1="http://www.w3.org/2001/XMLSchema" xmlns:SOAPSDK2="http://www.w3.org/2001/XMLSchema-instance" xmlns:SOAPSDK3="http://schemas.xmlsoap.org/soap/encoding/"
<SOAPSDK3:anyType SOAPSDK2:type="SOAPSDK1:int">'||df3||'</SOAPSDK3:anyType> </Array1>
<Array2 SOAPSDK3:arrayType="SOAPSDK1:anyType[3]" SOAPSDK3:offset="[0]" SOAPSDK2:type="SOAPSDK3:Array"> <SOAPSDK3:anyType SOAPSDK2:type="SOAPSDK1:int">'||df4||'</SOAPSDK3:anyType> <SOAPSDK3:anyType SOAPSDK2:type="SOAPSDK1:int">'||df5||'</SOAPSDK3:anyType>
<SOAPSDK3:anyType SOAPSDK2:type="SOAPSDK1:int">'||df6||'</SOAPSDK3:anyType> </Array2>
</SOAPSDK4:AddArrays> </SOAP-ENV:Body> </SOAP-ENV:Envelope>’'
This demonstrates that building a SOAP envelope is obviously proportional to the complexity of the Web Service that you want to invoke, in this case an array. The MS SOAP COM server makes it more
Page 20
Copyright © 2006 Gupta Technologies, LLC
complex because the types passed and received need to be mapped from XML types to COM data types. The screen shot below shows the accompanying sample demonstrating what we discussed in this section. The C# Web Service samples and the Team Developer one require that you have .NET and the MS SOAP toolkit to build the Web Services locally. Still, you can test other Web Services and also attempt to use the URL hosting my sample Web Services. The sample is located in “\SAMPLES\SAMPLE APP Consuming WebService via Gupta HTTPRequester”.
Creating a Simple Web Service with .NET This section provides help to anyone that wants to build simple Web
Services using .NET and C#, also showing .NET creating the required setup (virtual directory) on the Web Server to allow access to Web Services. The examples we will build are used to demonstrate the consumption of Web Services via the GUPTA HTTPREQUEST object, but also using the MS SOAP client using a wrapper on the WSDLReader MS SOAP toolkit object. We will cover that later on.
The creation of web services using .NET is very simple. We are using .NET2003 to demonstrate this. Before creating the Web Service, ensure that IIS Web Server is running on your machine, and that the Computer Management (from the control panel) shows IIS service started.
Page 21
Copyright © 2006 Gupta Technologies, LLC
Execute Microsoft Visual Studio .NET 2003 and create a new project as shown below. Adjust the URL of your Web Server to your environment
We will be creating a new method so simply click on switch to code view.
Remove the sample comments….
And paste this in its place:
public struct ReturnInformation { public string ReturnMessage; public double pi; }; public struct PComplex { public string ReturnMessage; public double pi; }; [WebMethod] public string HelloWorld(string MyMessage){ return MyMessage + "Hello World"; } [WebMethod]
public ReturnInformation TestReturnComplex(string MessageToPass){ ReturnInformation R; R.ReturnMessage=MessageToPass + "C# WebService say: PI is in ReturnCode Element, it is in the next nodelist item... "; R.pi= 3.14159265; return R; } [WebMethod] public ReturnInformation TestPassComplex(PComplex PassComplex){ ReturnInformation R; R.ReturnMessage=PassComplex.ReturnMessage; R.pi=PassComplex.pi; return R; }
The code above creates 3 methods: HelloWorld, which passes and returns a string, TestReturnComplex that passes a string and returns a structure and finally TestPassComplex that passes and returns a structure.
Build the solution
Copyright © 2006 Gupta Technologies, LLC
Building the solution should succeed as shown below. If that is the case, open Computer management from the control panel and you should see a new virtual directory, TestWebServicesWithGupta, created.
Page 23
Copyright © 2006 Gupta Technologies, LLC
To test your new Web Service, click View In Browser in the solution explorer on the Service1.asmx file.
As shown previously you can test your Web Service directly and .NET will also display the SOAP envelope.
Page 24
Copyright © 2006 Gupta Technologies, LLC
To see the WSDL file, just append ?wsdl in your URL http://localhost/TestWebServicesWithGupta/Service1.asmx?wsdl
Team Developer Web Services creation To build a Web Service from a Team Developer COM Server application, you will need to download and install the MS SOAP Toolkit version 3 from this URL :
http://www.microsoft.com/downloads/details.aspx?familyid=c943c0dd-ceec-
4088-9753-86f052ec8450&displaylang=en The MS SOAP Toolkit exposes COM server applications to clients using the SOAP protocol, basically making the COM server a Web Service. There are certain limitations to be aware of. Here are some guidelines:
• The COM objects must implement the IDispatch interface, which is the case with a Team Developer COM application.
• The methods exposed can only use Automation compatible datatypes; use VARIANT as much as possible for your parameters. Strings are allowed as they are converted to BSTR. Numbers are also allowed, but remember that Team Developer defines them as doubles per default (VT_R8).
• In and out (receive) parameters must be VARIANTS. The screen shot below shows a Team Developer COM application with a CoClass named GuptaWSTest and an interface IGuptaWSTest which defines 2 methods HelloWorld() and AddArrays(). The methods use SAFEARRAYS. Notice the use of the SAL Trace function and especially the use of SalComCleanupMode() on SAM_AppStartup.
Page 25
Copyright © 2006 Gupta Technologies, LLC
The use of SalComCleanupMode() is important because with this feature you tell the GUPTA Runtime not to enter its cleanup, SAM_AppExit, each and every time a Service is executed. It can be a MTS service or, as in this case, a Web Service.
Below SalComCleanupMode(FALSE) was set (its default) and the invocation of the a Web Service Operation made the runtime exit each and every time the operation was called. Setting SalComCleanupMode(TRUE) would never execute SAM_AppExit. It would only execute when the actual Web Server is shutdown.
Page 6
Page 26
Copyright © 2006 Gupta Technologies, LLC
Once the MS SOAP Toolkit is installed and you are done with a working Team Developer COM server application, you are ready to make it a Web Service. The directory \TD WEB SERVICES\Web Services SERVER\Gupta TD WebService MS SAOP SERVER\ contains the example GuptaWebServiceTest.apt used in this paper. Load it in Team Developer and make it a COM DLL. Double check that the DLL is registered once the application is built. Create a Virtual directory on your Web Server pointing to where the COM DLL is located (I simply created a directory under \Inetpub\wwwroot\GuptaWS).
Execute WSDL Generator from the MS SOAP toolkit and click next to the first page of the wizard. This should show you the screen below. Give a name to the service, GuptaWebServiceTest in this case, and give the path to the DLL of your COM server DLL built in the previous steps.
Click next and select the method you would like to expose as a Web
Service.
Copyright © 2006 Gupta Technologies, LLC
Click next and enter the listener URL (basically the virtual directory you have created previously) and use the ISAPI listener. In my case I use http://localhost:8008/GuptaWS/. Use the port your Web Server is configured on; if it’s the default port 80 then enter http://localhost/GuptaWS/
Click next and change the URIs to your server domain name. In our
sample we leave it at its default tempuri.org.
Click next and give the path where the WSDL and WSML file should be stored. As mentioned in the wizard, the files need to be Web accessible, so just enter the path of your virtual directory as shown below.
Page 28
Copyright © 2006 Gupta Technologies, LLC
The virtual directory and its path where the WSDL and WSML file should be located.
IMPORTANT: Lastly, set up the Internet Server API (ISAPI) handler for that virtual directory by calling this MS SOAP cmd file:
\Program Files\MSSOAP\Binaries soapvdir.cmd UPDATE GuptaWS
This is it! You have now created a Team Developer Web Service. If you used the accompanying sample of a Team Developer COM server (GuptaWebServiceTest.apt), you can now test the Web Service with the application “TD HTTPREQUEST WEB SERVICES CONSUMPTION.apt” found in the “\SAMPLES\SAMPLE APP Consuming WebService via Gupta HTTPRequester” directory.
Consuming Web Services via the MS SOAP toolkit The MS SOAP toolkit has a server component, as we have seen in a
previous section, but it also has client components that consume Web Services. So using the MS SOAP toolkit makes it possible to consume Web Services.
Page 29 A solution to consume Web Services for Team Developer using the MS SOAP toolkit was already proposed by Suren Behari with the Proxy
Copyright © 2006 Gupta Technologies, LLC
Generator. Here again is another COM Proxy class generator. It uses a C++ DLL that returns analyzed information from a WSDL file. The information (order, in/out flag, types and method names) are retuned to a Team Developer application that generates, via the CDK, the COM Proxy class to the service(s) of the selected WSDL document. All the source files are included. I have tested a few Web Services with good success like the US NAICS structure Web Service (see example). But, in case of a problem, the source is included as I did the mapping of the data types the best I could, but I could not test it all.
The generator converts the Web Service type to VARIANT in case of DATE and COMPLEX type and maps NUMBER to their proper VT TYPES, feeding it to the SOAP toolkit client that invokes the service. Complex data types are defined as VARIANT since they might contain SAFEARRAY or valid XMLDomNodeList IDISPATCH objects, thus it is possible to invoke Web Services having complex data types.
WSAnalyserTool WSAnalyserTool is a Team Developer CDK application to be installed as a tool in the Team Developer IDE. It can also function as a normal application. With it you can generate a COM Proxy Class for a given WSDL document.
How does it work? It functions pretty much the same way as the ActiveX explorer; the only
difference is that all methods are generated (you can’t select which ones you do not want to generate). Also the generator can use either MSOFFICE SOAP or the MS SOAP toolkit. The advantage of using MSOFFICE SOAP toolkit is that you do not have to deploy the MS SOAP components if the deployed machine already contains MSOFFICE 2003. Still, for the generator to function, the MS SOAP toolkit must be installed.
If the generator finds an existing method name in the COM Proxy Class name, it will give a warning and ignore the method. Each generated COM Proxy Class in an outline has an Init() method that actually connects to the Web Service to be invoked. In the Init() method you can also pass a username and password if the service requires a basic authentication. If multiple Services are generated in a given COM Proxy Class, the tool verifies that the endpoint and the address of the service is identical to the one already existing in the Init() method.
The figure below shows the tool installed in Team Developer having generated some COM Proxy class from some WSDL documents
Page 30
Copyright © 2006 Gupta Technologies, LLC
How to use it? Unzip the sample and Install soapsdk.exe from
http://www.microsoft.com/downloads/details.aspx?familyid=c943c0dd-ceec- 4088-9753-86f052ec8450&displaylang=en
The SOAP SDK is only required for the generator. If using a MS OFFICE
SOAP TOOLKIT generated COM Proxy class, the deployed machine having MS OFFICE installed does not need the MS SOAP toolkit.
The sample directory “\SAMPLES\WSDLAnalyser” contains:
\src: the C++ source of a DLL that interfaces to TD. WSAnalyserTool.apt : The Team Developer 2005.1 application; this should work fine with older versions of Team Developer.
Microsoft Office Soap Type Library v3.0.apl : a minimal ActiveX
interface for MS office SOAP. Microsoft Soap Type Library v3.0.apl : Same as above using the MS
SOAP toolkit. msxml.apl : MS XML ActiveX interface used by the examples but not
used by the generator. TD WS CONSUMPTION with proxygen interface.apt : The same samples that we covered in Consuming web services via HTTPREQUESTER section.
WSDLAnalyser.dll : An MS SOAP toolkit WSDLREADER interface to
GUPTA Team Developer. Once you build the WSAnalyserTool.apt, ensure you can successfully
generate a COM proxy using one of the WSDL sources given in the endpoint combo. Try:
http://webservices.imacination.com/distance/Distance.jws?wsdl Uncheck “in the current outline” check box and click generate. Check that the APL interface has been created.
Page 31
Test TD WS CONSUMPTION with proxygen interface.apt.
The sample below uses the same web services as the HTTPREQUESTER sample and the proxy is in the GuptaProxyTest.apl. To test the accompanying C# and Team Developer Web Services you will have to build the Web Services samples or you can try to use the remote URL indicated in the sample.
Below is an example of a generated COM Proxy class for the US NAICS service:
Function: GetNAICSByID
FunctionalVar: NAICSData Class: Variant Static Variables
Local variables Boolean: tmpret Actions
Call __ObjectPushString(NAICSCode) Call __ObjectPushVariantByRef(NAICSData) Set tmpret = __ObjectInvoke("GetNAICSByID", INVOKE_FUNCTION)
Call __ObjectPopNumber(-1,GetNAICSByIDResult) Call __ObjectPopVariant(1,NAICSData) Call __ObjectFlushArgs()
Call oGenericNAICS.Init( '', '', '' ) Set bGetNAICSByIDResult=FALSE Call oGenericNAICS.GetNAICSByID( dfCode, bGetNAICSByIDResult, vNAICSData )
If vNAICSData.GetObject( oDOMNodeList ) If oDOMNodeList.IsDispatchValid( ) Call oDOMNodeList.PropGetitem( 0,oDOMNode )
Call oDOMNode.PropGetparentNode( oDOMNode ) Call oDOMNode.PropGetxml( ml1 )
Page 32
Copyright © 2006 Gupta Technologies, LLC
Below is an example of a generated COM Proxy class for a local Team Developer service using arrays:
COM Proxy Class: GuptaWebServiceTest Function: AddArrays Description:
Returns Boolean: Parameters
Class: Variant FunctionalVar: Result
Boolean: tmpret Actions Call __ObjectPushVariantByRef(Array1)
Call __ObjectPushVariantByRef(Array2) Set tmpret = __ObjectInvoke("AddArrays", INVOKE_FUNCTION) Call __ObjectPopVariant(0,Array1)
Call __ObjectPopVariant(1,Array2) Call __ObjectPopVariant(-1,Result) Call __ObjectFlushArgs()
Return tmpret Below is the initialization of the COM Proxy class and the invocation of the AddArray method.
Call oGuptaWebServiceTest.Create( )
Call vResult.GetSafeArray( sfR ) ! ! Extract the returned array and display results....
Call sfR.GetNumber( df7, 0 ) Call sfR.GetNumber( df8, 1 ) Call sfR.GetNumber( df9, 2 )
Call SalWaitCursor(FALSE) To install WSAnalyserTool as a Team Developer tool, copy WSAnalyserTool.exe, WSDLAnalyser.dll, Microsoft Office Soap Type Library v3.0.apl, Microsoft Soap Type Library v3.0.apl to your Gupta Team Developer root directory. Install it as a user tool in Team Developer as shown below. The -MTX parameter is required for Team Developer 3.10 and above.
Page 33
Copyright © 2006 Gupta Technologies, LLC
Conclusion Consuming Web Services at a low level using the HTTPREQUEST object
can be simple or quite complex depending on the type of Web Service to be used and its complexity. A few solutions attempt to make the invocation of Web Services simpler in Team Developer, like COM WS from Lubos Vnuk, but it currently only supports MSXML (although a port to Gupta XML should be relatively easy).
The use of the HTTPREQUEST object to consume Web Services should be compatible with any future version of Team Developer, since it involves XMLLIB.APL library. This might not be the case when using the MS SOAP Toolkit to consume Web Services and certainly not to create Web Services since the MS SOAP toolkit is deprecated in favor of .NET.
Because Web Services are such an important technology, there is no
doubt that future versions of Team Developer will seamlessly allow the creation and consumption of Web Services.
Copyright © 2006 Gupta Technologies LLC. Gupta, the Gupta logo, and
all Gupta products are licensed or registered trademarks of Gupta Technologies, LLC., All other products are trademarks or registered trademarks of their respective owners. All rights reserved.
Page 34
HTTP GET
HTTP POST
Anatomy of a WSDL file
types
messages
portType
bindings
Service
Gupta HTTPREQUEST interface
Consuming web services via HTTPREQUESTER
Soap Envelope
Invoking a Team Developer Web Service
Creating a Simple Web Service with .NET
Team Developer Web Services creation
Consuming Web Services via the MS SOAP toolkit
Conclusion