Visual Basic Developer's Guide to SOAP
Author: Darshan Singh (darshan@perfectxml.com)
Last updated: Mar 01, 2002
Introduction
XML Web
services are probably the hottest topic being talked so much! Atleast four
conferences completely dedicated to Web services are scheduled for coming weeks;
more than 20 books that focus entirely on Web services are already available
and about dozen more are soon to be published; various newsgroups (hosted on
develop.com, Yahoo groups, Microsoft, etc.) get hundreds of posts everyday on
discussions related to SOAP and Web services! So, what are XML Web services?
And what problem really they solve?
In simple
words, XML Web services enable the distributed RPC (Remote Procedure Call) over
the Internet. XML Web services facilitate invocation of an object over HTTP (or
SMTP, etc.) from any platform, any language. For example, if you have a COM
DLL, you can now very easily expose its methods over the Internet, so that any
client, running on any platform, using any language would be able to invoke
these methods. To summarize, when it comes to exposing objects over the
Internet, today XML Web services are the excellent (and a lot simpler, extensible
and manageable) alternative to DCOM or CORBA.
Web Services, however logically are different than traditional RPC because of Web services' loosely coupled characterstics. With RPC, it is absolutely fine to call a series of methods, passing parameters and getting results one after another; however, this approach is not feasible when the method invocation is over the Internet, as it is generally with Web Services. And hence, instead of calling a series of methods, it is recommended to reduce the method invocations and pass combined large pieces of input data parameters, when working with Web Services.
Many
companies are rapidly adopting (using and exposing) XML Web services to enable
the application integration, provide new services to the external world, or to
seamlessly use the services from the outside world. One other area where XML
Web services can be very useful is the Department-to-Department integration. Let's
say you are the in-charge of building Intranet Web sites, you can now expose
the common data requirements (employee details, product details, financial
details, and so on) as XML Web services; you can then use these Web services
yourself while building the intranet Web site or anybody else can use them, no
matter what platform they are running on or what language they are using.
The three
technologies that are at the heart of XML Web services include XML (of
course!), HTTP, and SOAP (Simple Object Access Protocol). The plain text is portable
across all platforms and hence XML can travel on all platforms without any
issues; HTTP is the widely adopted transport and the core to the Internet;
SOAP, a W3C specification defines a messaging scheme on how the remote method
would be called and how the results would be returned. SOAP uses the XML to
define the request and response documents.
In this
article, we'll use Microsoft®
SOAP Toolkit 2.0 SP 2 in Visual Basic 6.0 to write Web service clients, and
then later on to enable existing COM objects as Web services. We assume you
have little familiarity with XML and SOAP. Check PerfectXML XML, SOAP and Web Services focus section to
learn more about these technologies.
Microsoft SOAP Toolkit
In order to invoke a
Web service method using SOAP, it's required to build a request payload (an XML
string) and send (post) it to the Web service. On the other side, the Web
service then processes the input SOAP request payload, determines the method
and parameters, calls the appropriate object method, receives the result from
the method, builds the response payload (an XML string) and
sends it to the caller. The caller can then parse the response text to get the
method invocation results.
Example SOAP request payload:
|
POST /WebServices/SalesRankNPrice/BookService.asmx
HTTP/1.1
Host: www.perfectxml.net
Content-Type: text/xml; charset=utf-8
Content-Length: length
SOAPAction:
"http://www.perfectxml.com/NETWebSvcs/BookService/GetAmazonSalesRank"
<?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>
<GetAmazonSalesRank
xmlns="http://www.perfectxml.com/NETWebSvcs/BookService">
<ISBN>string</ISBN>
</GetAmazonSalesRank>
</soap:Body>
</soap:Envelope>
|
The above text
defines a POST request to host www.perfectxml.net hosting Web
service at /WebServices/SalesRankNPrice/BookService.asmx and the method call
(GetAmazonSalesRank)
that takes a string parameter (ISBN).
Example SOAP response payload:
|
HTTP/1.1 200 OK
Content-Type:
text/xml; charset=utf-8
Content-Length:
length
<?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>
<GetAmazonSalesRankResponse
xmlns="http://www.perfectxml.com/NETWebSvcs/BookService">
<GetAmazonSalesRankResult>string</GetAmazonSalesRankResult>
</GetAmazonSalesRankResponse>
</soap:Body>
</soap:Envelope>
|
If the call to Web
service method succeeds, we'll get the response back as outlined above. The
status of 200 indicates that our HTTP request succeeded; the returned content
type text/xml indicates that SOAP response is returned as a XML string.
This string once again contains SOAP Envelope and Body tags and the tag GetAmazonSalesRankResponse that encloses the results string (the Amazon.com sales rank
for the book whose ISBN number was passed as part of SOAP request payload).
It's very important to understand the XML Namespaces (http://www.w3.org/TR/REC-xml-names/)
and XML Schema (http://www.w3.org/TR/xmlschema-0/)
standards in order to understand SOAP and Web services better.
The Microsoft SOAP
Toolkit hides us from all these details and supports a simple object model that
we can use to call the XML Web services and not worry about
packaging/un-packaging SOAP request/response payloads. In addition it provides
a Web service Wizard that allows "SOAP-enabling" any COM object DLL.
Using this wizard, the methods inside any COM DLL can be turned into Web
service methods that can be called from any platform over the internet. The
Toolkit also provides a great debugging tool (Trace Utility, MsSoapT.exe) that
allows intercepting SOAP request and response payloads. Go ahead and download
this (free) great toolkit from the MSDN download area at http://msdn.microsoft.com/soap and
let's begin writing some code!
Writing Web Service Clients Using SOAP Toolkit
Let's start with a
simplest SOAP client. Start Visual Basic 6.0 (preferably SP5), and create a
standard EXE project. Add reference (Project |
References) to Microsoft SOAP
Type Library (MSSOAP1.dll). Double click on the form and write the following code
under the Form_Load method:
|
Dim objSOAPClient
As New SoapClient
objSOAPClient.mssoapinit
_
"http://services.xmethods.net/soap/urn:xmethods-delayed-quotes.wsdl"
MsgBox
objSOAPClient.getQuote("MSFT")
|
How simple is that? Not
much different than writing a COM client, right? That's really is the idea
behind it. The above high-level API provided by the SOAP Toolkit hides us from
the internals and allows using Web services as like any other COM object.
What's going on under the hood is the following:
- The mssoapinit method call accepts the WSDL (Web
Service Description Language) URL. Based on the provided URL, it
initializes the SoapClient instance so that we can call the
Web service methods directly on this SoapClient
instance. If you study the Delayed Stock Quotes WSDL (http://services.xmethods.net/soap/urn:xmethods-delayed-quotes.wsdl),
you'll notice that it exposes just one method named getQuote that accepts a string parameter
and returns a float value. This is the method we call next using the SoapClient instance.
- We pass the "MSFT"
(ticker symbol for Microsoft) as a string parameter to getQuote Web
service method and it returns a float number, which we display using an
MsgBox statement. When this method is called, the toolkit builds a SOAP request payload similar to as
shown below:
|
<se:Envelope
xmlns:se="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsi="http://www.w3.org/1999/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/1999/XMLSchema">
<se:Body>
<xns:getQuote
xmlns:xns="urn:xmethods-delayed-quotes"
se:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<symbol
xsi:type="xsd:string">MSFT</symbol>
</xns:getQuote>
</se:Body>
</se:Envelope>
|
On
the successful execution of the method call, the toolkit receives the response payload similar to as shown
below:
|
<se:Envelope
xmlns:se="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsi="http://www.w3.org/1999/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/1999/XMLSchema">
<se:Body>
<xns:getQuoteResponse
xmlns:xns="urn:xmethods-delayed-quotes"
se:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<return xsi:type="xsd:float">63.63</return>
</xns:getQuoteResponse>
</se:Body>
</se:Envelope>
|
In
summary, once the SoapClient instance is initialized using the WSDL URL, the Web service
methods can directly be called on the SoapClient instance, which takes care of building and posting SOAP
request, receiving the SOAP response and exposing the returned result value. Depending
on the returned data type/value, you can directly access the value (such as in
this case the float value) or use the MSXML DOM object model or SOAP Toolkit
provided SOAP Message Object to process the returned message.
Let's
look at one more example of writing SOAP client application using the toolkit.
This
time we'll call the SalesRankNPrice Web service available at http://www.PerfectXML.net/WebServices/SalesRankNPrice/BookService.asmx.
This Web service can be used to get the sales rank and/or price for any book available
on Amazon and/or B&N Web sites.
Create a standard EXE project in Visual Basic 6.0. Add
reference to SOAP type library and Microsoft XML Core Services (MSXML) 4.0. Write the following code in the Form_Load
method.
|
Dim objSOAPClient As New SoapClient
Dim objXMLResultNodes As IXMLDOMNodeList
objSOAPClient.mssoapinit _
"http://www.PerfectXML.net/WebServices/SalesRankNPrice/BookService.asmx?wsdl"
Set objXMLResultNodes =
objSOAPClient.GetAll("186100589X")
MsgBox "Amazon Sales Rank: " & _
objXMLResultNodes.Item(0).nodeTypedValue
MsgBox "Amazon Price: " & _
objXMLResultNodes.Item(1).nodeTypedValue
MsgBox "B&N Sales Rank: " & _
objXMLResultNodes.Item(2).nodeTypedValue
MsgBox "B&N Price: " &
objXMLResultNodes.Item(3).nodeTypedValue
|
The above code is very similar to the first example, except
how the returned results are processed. The mssoapinit call initializes the SoapClient instance with the WSDL URL for the SalesRankNPrice Web
service. This Web service has a method called GetAll that returns the Amazon.com sales rank and price, and
B&N sales rank and price, hence four values returned as four XML nodes, for
the input ISBN. This method hence returns an IXMLDOMNodeList that contains four nodes. We save the GetAll
method result into a variable of type IXMLDOMNodeList and then access the individual node values to get the
actual sales ranks and prices.
Before we end this section, let's look at an ASP example of
using the SOAP Toolkit. Create a new IIS virtual directory or use some existing
IIS virtual directory, and create and save the following ASP page under this
virtual directory:
|
<%
Option Explicit
Dim objSOAPClient
Dim objResultNodes
Dim objDetailsNodes
Dim objNode
Dim iRestrict
Dim iTotal
'Create the SOAPClient object using the version-dependent
ProgID
Set objSOAPClient =
Server.CreateObject("MSSOAP.SoapClient.1")
'See http://msdn.microsoft.com/library/en-us/dnsoap/html/soap_faq.asp?frame=true#soap_faq_topic0111a
for details on this
objSOAPClient.ClientProperty("ServerHTTPRequest")
= True
'Initialize the SoapClient instance with the WSDL URL
objSOAPClient.mssoapinit _
"http://www.perfectxml.net/WebServices/MusicTeachers/MusicTeachers.asmx?wsdl"
'Invoke the Web service method
'It returns a DataSet (two nodes list; one containing
schema
' and other containing actual results)
Set objResultNodes = _
objSOAPClient.FindMusicTeachers ("60195", "0",
"0", "0", 10, 2)
'Get values of ResultsCount and RestrictResultCount from
the Results node (node 1)
iTotal =
objResultNodes.item(1).selectSingleNode("//ResultsCount").nodeTypedValue
iRestrict = _
objResultNodes.item(1).selectSingleNode("//RestrictResultCount").nodeTypedValue
Response.Write ("Total " & iTotal & _
" teachers
found! Restricting the results to " & iRestrict &
"<br><br>")
Set objDetailsNodes =
objResultNodes.item(1).selectNodes("//Details")
'For each Music Teacher Detail node…
For Each objNode in objDetailsNodes
Response.Write
(objNode.selectSingleNode("Name").nodeTypedValue)
Response.Write
(": " &
objNode.selectSingleNode("Phone").nodeTypedValue)
Response.Write
("<br><hr size=1 color=gray width=99% align=center>")
Next
Set objSOAPClient = Nothing
%>
|
The
above ASP code uses the Microsoft SOAP Toolkit to access the
SearchMusicTeachers Web service available at (http://www.PerfectXML.net/WebServices/MusicTeachers/MusicTeachers.asmx).
The only important points to note in the above code are the use of
version-dependent ProgID and setting the ServerHTTPRequest property to true. See the SOAP
Toolkit FAQ for more details on this.
Writing SOAP Server Using the Toolkit
As mentioned earlier,
the SOAP Toolkit enables any COM object to be used as a Web service. The
methods exposed via the COM object can readily be extended to Web service
methods using the WSDL Generator Wizard (also known as SOAP Toolkit Wizard).
This wizard essentially does three things:
- Creates a WSDL document for the
provided COM DLL. The WSDL document describes the Web methods exposed, the
parameter details and the SOAP port where the request should be posted.
- Creates the SOAP Handler (either
an ASP page or an ISAPI listener) based on the choice you make in the
final step in this wizard. In the generated WSDL the SOAP port location
points to either to the ASP page or the .wsdl file itself based on if ASP
handler or ISAPI listener is chose respectively. While ASP page is simple
to work with and easy to understand, the ISAPI listener provides the best
performance and is the better choice when building production grade SOAP
servers using the toolkit. When ISAPI listener is chosen, the SOAP
requests are posted to .wsdl file, on which the ISAPI listener (soapisap.dll)
listens to and processes the incoming SOAP requests.
- Creates the WSML (Web Services
Meta Language) file. WSML is Microsoft-specific file and is only used
while working with the Microsoft SOAP Toolkit. The WSML file defines the
mapping of Web service methods with the methods in the COM objects. Like
WSDL, it also uses the XML syntax.
Let's now first build
a COM object DLL and then we'll enable this COM DLL as a Web service using the
SOAP Toolkit.
The COM DLL that
we'll build here contains one method named "GetAddress" that uses the
NetBIOS API call to get the network adapter addresses and returns that to the
caller. See Microsoft KB article HOWTO:
Get Network Adapter Address from Visual Basic (Q175472) for more
information on this.
Start Microsoft
Visual Basic 6.0, create a new ActiveX DLL project. Rename the project to NetAdapterAddr and Class1 to clsDetails. Copy the first part (step 3) code from the above KB
article (Q175472) at the beginning of the clsDetails class. Add a new function
(Tools | Add Procedure)
and name it GetAddress. Copy the second part (step 4) code from the above KB
article under the GetAddress function. Make two small changes: first change Exit Sub
to Exit Function; and second instead of MsgBox, assign the network address value to the function name (GetAddress), so that the network adapter address is returned as the
function return value. Build the DLL (NetAdapterAddr.dll). As an optional step, quickly write a COM client for this
DLL to make sure the GetAddress method is working. Let's now enable this COM DLL as a Web
service using the SOAP Toolkit.
The first step in
creating a SOAP server using the Wizard is to create a physical directory and
then create an IIS virtual directory that maps to this newly created directory.
So go ahead and create a folder name TestSOAP somewhere on the hard drive and map a new IIS virtual name
(also named TestSOAP) to this folder.
Click Start |
Programs | Microsoft SOAP Toolkit | WSDL Generator, which brings up a screen as shown below:

Click on Next button, and in the following screen provide the name of the
Web service (NetAdapterAddress) and the path where the COM DLL resides:

After clicking Next,
the following screen allows you to select the classes and methods that you wish
to "Web-service enable":

Check the clsDetails
class and click on Next button. The following screen is the place where you
decide if you wish the ASP SOAP listener or ISAPI listener. For simplicity,
we'll choose the ASP listener type. This screen also allows you to choose XSD
schema namespace that would be used in the request and response payloads.

Provide the virtual
directory name that you created earlier (TestSOAP), select ASP listener type
and 2001 Schema Namespace and then click on the Next button. In the next screen,
keep the default encoding type (UTF-8) and change the path where you want the
Wizard to create WSDL, WSML and ASP files:

This is the final
screen, when you click next on this screen, the wizard looks at the COM DLL,
creates WSDL, WSML and ASP file and saves them into the specified folder.

Our SOAP server is
ready. The NetAdapterAddress COM DLL is now a Web service. If you browse to the
generated WSDL file (http://localhost/TestSOAP/NetAdapterAddress.WSDL) you'll
notice that the service port points to the generated ASP page and the Web
service exposes one method named GetAddress that does not take any parameters and returns a string
value:

Let's build a SOAP
client for the above service.
Start Visual Basic 6,
create a new standard EXE project, add reference to Microsoft SOAP Type
Library, double click on the form and write the following code in the Form_Load
method:
|
Dim
objSOAPClient As New SoapClient
objSOAPClient.mssoapinit
_
"http://localhost/TestSOAP/NetAdapterAddress.WSDL"
MsgBox
objSOAPClient.GetAddress()
Set
objSOAPClient = Nothing
|
By now it should be
clear as to what we are doing above. The mssoapinit call initializes the SoapClient object and then we call the Web service method (GetAddress)
directly using the SoapClient object.
As an exercise, spend
some time reviewing the generated ASP page (NetAdapterAddress.asp) and see how it makes use of the SOAP Toolkit (MSSOAP.SoapServer class) to accept the request, call the respective COM
method, build and serialize the response.
Using MSXML 4.0 to Call Web Services
We saw how the SOAP
toolkit hides the details from us and provides the simple high-level API and
wizards to write SOAP client and server applications. It also provides the
low-level API that provides the maximum flexibility and control over the SOAP
messaging, but requires more code. Check SOAP Toolkit documentation for more
information on the low-level API.
It is also possible
to use MSXML 4.0 as a Web service client (or server). But this surely evolves a
lot of work as you'll have to do all the work of packaging and un-packaging the
SOAP request/response messages. MSXML 4.0 supports the IXMLHTTPRequest interface that you can use to send HTTP requests and get
the response. Check out perfectxml.com MSXML Focus section for more
help on XMLHTTP and ServerXMLHTTP, the built-in classes that implement the IXMLHTTPRequest
interface.
The benefit of
creating Web services using ASP.NET is that apart from using SOAP, these Web
services can also be accessed by sending just the GET or POST HTTP requests
(without actually sending the SOAP request payload). If you don't want to use
the SOAP Toolkit, you can use MSXML 4.0 to send a GET/POST request to a Web
service method and get the response. Let's take a look at an example of this.
In this example,
we'll send a GET request to the NewsNArticles Web service available at http://www.PerfectXML.net/WebServices/NewsNArticles/Updates.asmx.
We'll use ServerXMLHTTP40 to send the GET request, if it succeeds we'll use the XPath
expressions and MSXML selectNodes and selectSingleNode methods to access the returned XML data. Save the following
code as PXMLNews.asp under some IIS virtual directory and browse to the page to
see the latest XML News powered by the PerfectXML NewsNArticles Web service!
|
<%
Option
Explicit
Dim objSXH3
Dim
NewsItemNodes
Dim
ItemNode
Set objSXH3
= Server.CreateObject("Msxml2.ServerXMLHTTP.4.0")
objSXH3.open
_
"GET", _
"http://www.PerfectXML.net/WebServices/NewsNArticles/Updates.asmx/GetNews",
_
False
objSXH3.send
If
objSXH3.status = 200 Then
Set NewsItemNodes =
objSXH3.responseXML.selectNodes("//NewDataSet/Table")
For Each ItemNode In NewsItemNodes
Response.Write ("<a
class=defaultitem_link href=" & _
ItemNode.selectSingleNode("Link").nodeTypedValue
& _
" target=parent>"
& ItemNode.selectSingleNode("Title").nodeTypedValue & _
"</a>
<font color=gray>(" & _
ItemNode.selectSingleNode("NewsDate").nodeTypedValue
& ")</font><br>")
Response.Write
(ItemNode.selectSingleNode("Description").nodeTypedValue)
Response.Write
("<br><hr size='1' color='#999999' width='99%' " & _
align='left'
><br>")
Next
End If
Set objSXH3
= Nothing
%>
|
Instead of using
Response.Write, if you wish, you can also write an XSLT transformation that
converts the returned XML data into HTML.
Summary
The main aim of this
article was to give you, the Visual Basic programmers, a brief introduction to
SOAP and Web services. We saw how SOAP toolkit can be used to easily create the
SOAP client and server applications in Visual Basic. At the end, we learned
about using MSXML to quickly build a Web service client. We hope you enjoyed
this article and also learned something new. There is a lot more to learn in
the SOAP and Web services world, be sure to check out links and resources at
the bottom of this article for some more references.
Do not hesitate to
send an email to mailto:comments@perfectxml.com
and ask any questions that you might have and we (perfectxml.com Team) would be
very happy to provide answers to them.
Links and Resources
-
perfectxml.com SOAP
Focus section (http://www.perfectxml.com/soap.asp)
-
perfectxml.com Web
services Focus Section (http://www.perfectxml.com/WebSvc1.asp)
-
W3C Links
-
http://www.w3.org/2002/ws/
-
http://www.w3.org/TR/SOAP
-
http://www.w3.org/TR/soap12-part0/
-
http://www.w3.org/TR/soap12-part1/
-
http://www.w3.org/TR/soap12-part2/
-
http://www.w3.org/TR/SOAP-attachments
-
http://www.w3.org/TR/SOAP-dsig/
-
Microsoft
Links
o
http://msdn.microsoft.com/soap
o
Microsoft
SOAP Toolkit Knowledgebase articles
-
SOAP
Discussions
o
http://discuss.develop.com/soap.html
o
http://groups.yahoo.com/group/soapbuilders/
o
http://groups.yahoo.com/group/soaplite
o
http://msdn.microsoft.com/newsgroups/loadframes.asp?ICP=msdn&sLCID=us&NewsGroup=microsoft.public.xml.soap
o
http://msdn.microsoft.com/newsgroups/loadframes.asp?ICP=msdn&sLCID=us&NewsGroup=microsoft.public.xml.soapsdk
o
http://p2p.wrox.com/list.asp?list=xml_web_services