Introduction
The Simple Object Access Protocol (SOAP) is gathering a lot of
momentum - it forms the baseline protocol for BizTalk (http://www.biztalk.org/?WROXEMPTOKEN=365433ZwwvvVQ81hbeQTnInzTN).
Indeed, discussions are in place to use SOAP as the protocol for
ebXML (http://www.ebxml.org/?WROXEMPTOKEN=365433ZwwvvVQ81hbeQTnInzTN);
ebXML itself is to be integrated in RosettaNet's (http://www.rosettanet.org/?WROXEMPTOKEN=365433ZwwvvVQ81hbeQTnInzTN)
eBusiness framework. Couple that with the fact that SOAP is
omnipresent in the .NET platform, and you can be assured that
learning to use SOAP today will put you in good stead for the coming
months. To help us get there, Microsoft (amongst others) has
provided free-of-charge SOAP Toolkits.
The Microsoft SOAP Toolkits go some way to removing the amount of
code we have to write - in particular the amount of server-side code
we have to write is dramatically reduced. Client-side, we still have
to write some ourselves, however much of the complexity of type
checking and fault handling is taken care of by the client-side
Toolkit support. This article will provide an overview of the
Microsoft SOAP Toolkit Version 2.0; sample code will be provided in
Visual Basic and VBScript.
The SOAP Toolkits
.NET is an attractive platform for developers - Microsoft is keen
to attract as many existing and new developers to the .NET platform
as they can. However they realize that we simply cannot rewrite all
our existing applications - after all, the cost would be enormous.
Thus, to bridge the gap they have released SOAP Toolkits. Whilst the
Toolkits are targeted at the many Visual Studio 6 developers, they
can be used quite satisfactorily in other environments such as
Delphi, C++Builder and other environments that support COM.
Microsoft has been feverishly busy - since January 2001 there
have been no less than four releases of the SOAP Toolkit Version 2.
During that period, the Web Service Description Language (WSDL) went
from version 1.0 to version 1.1. The Microsoft SOAP Toolkit
implemented WSDL 1.0, however it now implements WSDL 1.1 - hence one
of the releases encompassed the WSDL upgrade. At the time of
writing, the current version is V2.0 Gold Release. So, for the
remainder of this article, the term "SOAP Toolkit" will mean
Microsoft SOAP Toolkit Gold Release.
The Microsoft SOAP Toolkit 2.0 Gold Release is available here: http://msdn.microsoft.com/downloads/default.asp?URL=/code/sample.asp?url=/msdn-files/027/001/580/msdncompositedoc.xml&WROXEMPTOKEN=365433ZwwvvVQ81hbeQTnInzTNhttp://msdn.microsoft.com/downloads/default.asp?URL=/code/sample.asp?url=/msdn-files/027/001/580/msdncompositedoc.xml.
Over the course of this article I will explain how I have used
the SOAP Toolkit to build an Internet-enabled "time and expense
management" application. Rather than discuss the entire application,
I have chosen to explain one module - the expense module. In
reality, I may have to cope with a large number of users, so I have
used Microsoft SQL Server in my test environment. However, since SQL
Server might be considered a luxury, the examples presented in this
article will work with Microsoft Access (although I have not tested
it, there is no reason why it would not work with MSDE too). In
addition to an examination of the SOAP Toolkit, I will also discuss
some of the periphery topics, such as WSDL.
Prerequisites
I will assume that you have some familiarity with SOAP - as
provided by my previous articles (there are links to these articles
at the bottom of this document). I will take this opportunity to
correct an oversight in my first article: SOAP is considered
"element-centric", thus the contents of the SOAP body (our data)
should not contain XML elements with attributes. So the following is
actually invalid: <SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope">
<SOAP-ENV:Body>
<m:getEmployeeDetailResponse xmlns:m="http://www.craigmurphy.com/hrweb">
<employee emp_no="5"></employee>
</m:getEmployeeDetailResponse>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
The correct SOAP response would be: <SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope">
<SOAP-ENV:Body>
<m:getEmployeeDetailResponse xmlns:m="http://www.craigmurphy.com/hrweb">
<employee>
<emp_no>5</emp_no>
</employee>
</m:getEmployeeDetailResponse>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
Whilst you might get away with using attributes in this fashion,
it is considered "bad soap", so do not be too surprised if SOAP
listeners reject your SOAP messages!
Familiarity with the first version of the Microsoft SOAP Toolkit
is not required. The SOAP Toolkit Version 2 is a complete rewrite of
version 1.0. The SOAP Toolkit Version 1.0 was frozen at the last
release (December 2000) - Microsoft does not encourage you to
start/continue developing web services with that version! However,
if you would like an understanding of the V1.0 toolkit, an article
can be found here: http://www.asptoday.com/content.asp?id=473&WROXEMPTOKEN=365433ZwwvvVQ81hbeQTnInzTNhttp://www.asptoday.com/content.asp?id=473.
That having been said, there is some overlap in the design and
implementation of certain aspects, notably the WSDL Wizard found the
V2.0 toolkit shares a similar user interface to that of the SDL
Wizard in the V1.0 Toolkit.
Application Background
Traditionally, my company's timesheet & expenses data
collection was a paper-based process - a few years ago I automated
it using a standalone Delphi application and Microsoft Word. Having
seen the efficiencies of electronic data entry, our management asked
that we move the data entry "one step closer to the billing system",
i.e. [probably] centralized billing. We liked the standalone nature
of the Delphi application, so for us, this entailed the creation of
either a web browser solution or an Internet application (built
using either Delphi or Visual Basic). At the end of the day we chose
to use Visual Basic and the SOAP Toolkit - partly because we are
gearing up for a move to the .NET platform where we plan to use
VB.NET. We did have one stipulation however: the user interface
should remain faithful to the original Delphi version.
For the purposes of this article, the database implementation is
minimal, but it does reflect the fields found in the Delphi version.
Ultimately, a "user" has a collection of "service providers";
expenses are incurred against a service provider, e.g. an airline
ticket provider. The last sentence infers that a user also has a
collection of "expenses". Expenses are allocated against a "job
number" - jobs are assigned to clients, therefore we can bill a
client based on the expenses our employees submit. Thus, we will
have tables that manage each of these entities: users, services,
expenses and job numbers. The relationship between these entities is
shown below:

Architecturally, we adopted a 3-tier approach: there is a
presentation tier, a business logic tier and a data tier.
Theoretically, each of these tiers may reside on their own machine.
In reality, we have implemented the business logic and data services
on the same machine; we can always adjust our implementation later.
This is no bad thing as testing is simplified - we can actually test
our application using just one machine. The candidate architecture
is best described graphically:

Whilst the architecture depicts a number of DLLs, the complete
implementation necessitates many more DLLs - for the purposes of
this article we will just be looking at those associated with
"expense" management. Connectivity between the business services and
the data services is provided by means of ADO. The login logic is
provided to complete the picture - the code download uses a
hard-coded "test" login mechanism.
We have got a picture of what our application needs to do; now we
will examine the SOAP Toolkit architecture.
Toolkit Architecture
WSDL is at the heart of the SOAP Toolkit. WSDL, like SOAP, is
encoded using XML; therefore it can be used on any platform that
supports XML parsing. WSDL is similar to the Interface Definition
Language (IDL). In essence, a WSDL document provides the "interface"
to the methods that an object wishes to expose as web services.
Both the client and server objects (SOAP Client and SOAP Server)
use WSDL documents. However, the SOAP Server object makes use of a
WSML document - the Web Services Meta Language. I should point out
that WSML documents are specific to the Microsoft SOAP Toolkit;
because they are used server-side this extension should not present
too many problems. WSML documents are used by the SOAP Toolkit to
determine the PROGID of the DLL that can provide the concrete
implementation of the SOAP method being requested. WSML documents
are also encoded using XML.
I have refrained from presenting example WSDL and WSML documents
- there are examples of both documents later in this article.
The SOAP Toolkit comprises of two application programmer
interfaces (APIs) - a high level API and a low level API. The
high-level API allows us to treat remote DLLs as if they were on the
local machine - the API handles all the SOAP message creation, XML
parsing, HTTP transport and WSDL parsing. The low-level API is just
the opposite - it provides us with much more control over the SOAP
message creation. Conveniently, it's possible to work with either
API, or even a mix of the two.
There are seven steps required to execute a SOAP method using the
high-level API. The diagram below details these seven steps (some
the code has been simplified for the sake of clarity):

- 1. The client application creates an instance of the
SOAP Client object (as provided by the SOAP Toolkit) and then it
loads the server-side WSDL for the services dll.
- 2. Using late binding we execute the Get_ServiceList method; the SOAP Client
will perform some type checking on our parameters too. Under these
circumstances we have little choice - we have to use late binding.
This brings with it a run-time performance hit, the need for
additional error checking and the loss of type safety (although
SOAP helps us with type safety).
- 3. The SOAP Client creates a SOAP request that gets
passed to the server-side ASP script services.asp . The SOAP Client uses
elements in the WSDL document to create the SOAP Request; the WSDL
document also specifies address of the server-side SOAP listener (
services.asp ).
- 4. service.asp creates an
instance of the SOAP Server object (as provided by the SOAP
Toolkit).
- 5. SOAP Server then loads the WSDL and the WSML
documents.
- 6. The SOAP Server object exposes a SoapInvoke method that takes the ASP Request and Response objects as parameters. SOAPInvoke actually instantiates the DLL
that implements the Get_ServiceList
method - the WSML provides enough information to allow this to
occur.
- 7. The SOAP response is passed back to the SOAP Client,
which is capable of converting the SOAP response in to the correct
data type, in this case, a string (which happens to contain some
XML).
During step 6, the SOAPInvoke
method simplifies the server-side processing. It is capable of
taking an ASP Request object (one that contains a SOAP request) and
with minimal configuration it will:
- parse the Request (it's XML after all)
- create an instance of the appropriate DLL
- execute the method (passing parameters as required)
- create a SOAP Response
- return the SOAP Response through the ASP Response object
Step 7 performs some similar magic - the SOAP Client deciphers
the SOAP Request and converts it into data types and return values
that the client can understand.
Now that we have an understanding of the SOAP Toolkit
architecture, let's move on to look at how we can apply the SOAP
Toolkit to a specific problem.
Client-side implementation
Referring back to the diagram depicting our candidate
architecture, it's probably best that we go through the presentation
and business logic tiers.
Presentation Tier
The client-side web application is a Visual Basic standalone
executable. The user interface is fairly easy to use. A user
allocates expenses against jobs, marking the expense items with the
date when the expense was incurred and who the payment was made to
(service providers). To facilitate these requirements, the user
interface requires mechanisms for:
- Selecting a date
- Selecting a job number
- Selecting/Entering a service provider
- Entering an amount
The screen shot below provides controls that offer such
mechanisms:

Business Logic Tier
The Login.dll manages user
authentication, albeit in this example the authentication is
somewhat trivial.
The Service.dll provides
functionality that obtains an XML formatted list of "services
providers" for a particular user. A service provider has an
associated "service provided" and an optional "VAT No" (sales tax) -
having to reenter the same details from month to month would be
tiresome. Therefore the expense module maintains a list of
frequently used service providers - simply clicking on a service
provider fills in the service provided and VAT (tax) Number controls
based on previous inputs.
The Post.dll provides two
functions:
- Post_Expense - takes an "expense" record and inserts it into
tblExpense
- Delete_Expense - takes an "expense" record and removes it from
tblExpense
The Job.dll provides just one
function: Get_JobList . In reality,
each user may have different job numbers, even some that are unique
to them - for the sake of this example, the implementation has been
simplified.
The Get.dll provides two functions:
- Get_Expenses - obtains a list of
expenses belonging to a given user for a given month
- Get_ExpenseTotals - obtains a list of
expenses, totaled by job number
Each of these DLLs comprise of functions (web services) that we
would like to invoke using SOAP. We'll now take a look at how we can
use the SOAP Toolkit to help us create Web Service Description
Language files for our DLLs.
Now that we are familiar with the client-side user interface, the
server-side code should make sense. I will return to the client-side
explanation after we've seen what the server-side code has to
achieve. We'll also get an understanding of the SOAP Toolkit that
will help us when we look at the client-side SOAP Toolkit usage.
Server-side implementation
Rather than explain each element of the business logic, I will
concentrate on the " services.dll "
logic - we will see how the Visual Basic and ADO code is used to
build WSDL and WSML files (or documents if you prefer) and how these
files are used in some server-side ASP script.
The server-side Visual Basic required to obtain an XML-formatted
string of service providers is shown below: Function Get_ServiceList(ByVal sUser As String, ByVal sPassword As String) As String
Dim sSource As String
Dim sConnect As String
Dim sXML As String
Dim rsService As New ADODB.Recordset
' We're only interested in the service providers for this user...
sSource = "SELECT ServiceProvider,ServiceProvided,VATNo,ExpenseType FROM [tblService]"
sSource = sSource + "WHERE LoginID = " + "'" + sUser + "'"
sConnect = "DSN=WROXTEA;UID=;PWD=;"
rsService.Open sSource, sConnect, adOpenStatic
If rsService.RecordCount > 0 Then
sXML = sXML + "<services>"
While Not rsService.EOF
sXML = sXML + "<service>"
sXML = sXML + "<prov>" + rsService("ServiceProvider") + "</prov>"
sXML = sXML + "<desc>" + rsService("ServiceProvided") + "</desc>"
sXML = sXML + "<vat>" + rsService("VATNo") + "</vat>"
sXML = sXML + "<expensetype>" + rsService("ExpenseType") + "</expensetype>"
sXML = sXML + "</service>"
rsService.MoveNext
Wend
sXML = sXML + "</services>"
Else
sXML = ""
End If
rsService.Close
Set rsService = Nothing
Get_ServiceList = sXML
End Function
The code above does little more than extract list of service
providers from tblService and return them as an XML string: <services>
<service>
<prov>Airlines Ltd</prov>
<desc>Flights</desc>
<vat>123 456 789</vat>
<expensetype>Travel</expensetype>
</service>
<service>
<prov>Parking Ltd</prov>
<desc>Parking</desc>
<vat>789 456 123</vat>
<expensetype>Car</expensetype>
</service>
<service>
<prov>Burgers Ltd</prov>
<desc>Meals</desc>
<vat>456 123 789</vat>
<expensetype>Travel</expensetype>
</service>
</services>
Perhaps obviously, the client application must be able to parse
and understand the XML string that it receives. Given that the SOAP
Toolkit requires the Microsoft XML Parser version 3 (SP1), we are
able to make use of it. By sending XML strings to the client
application we are ensuring that we can create browser-based
implementations of the same application at a later date.
So, we have a server-side DLL that provides a method that we
would like to expose as a web service The web service must be
addressable using SOAP, so our next step is to create a WSDL
document for this DLL. The SOAP Toolkit provides a simple wizard to
create the WSDL and the WSML for a DLL. However, before we look at
the wizard, it is best that I explain WSDL and WSML.
An Introduction to WSDL
WSDL is key to the world of web services. WSDL documents contain
enough information for an external process (such as the SOAP
Toolkit) to be able to construct valid SOAP requests. I use the
phrase "valid SOAP requests" because the SOAP Toolkit will also
perform data type checking too. A WSDL document also contains
information that allows the SOAP Toolkit to decipher SOAP
responses.
For the remainder of this examination of WSDL we will be using
WSDL that represents the method Get_ServiceList (from services.dll).
A typical WSDL document comprises of a root <definitions> element - this is simply
a container element that provides an entry point via the name attribute: <definitions name ='service' targetNamespace = 'http://tempuri.org/wsdl/'
xmlns:wsdlns='http://tempuri.org/wsdl/'
xmlns:typens='http://tempuri.org/type'
xmlns:soap='http://schemas.xmlsoap.org/wsdl/soap/'
xmlns:xsd='http://www.w3.org/2000/10/XMLSchema'
xmlns:stk='http://schemas.microsoft.com/soap-toolkit/wsdl-extension'
xmlns='http://schemas.xmlsoap.org/wsdl/'>
...
</definitions>
The SOAP Server object actually uses XSLT to address WSDL and
WSML documents - thus you can expect to see considerable "linking"
via attributes such as name .
The diagrams below present the WSDL for the services.dll (we'll see how to create WSDL
later in this article):

The <types> section is a
container element for the data types that may be part of the SOAP
requests and responses. Our examples will see the data types
specified in the <message>
element.

The <message> elements
provide the input (request) and output (response) SOAP message
templates. They are used to build and validate SOAP requests and
responses.

The <portType> element is
essentially a means of grouping related operations.
The <operation> element
defines the <input> and <output> elements that point
back to the <message> element in
section 2.

The <bindings> element is
used to specify the protocol (the transport) for each of the <operations> defined in the <portType> element defined in section
3.

The <service> element name
attribute relates to the name attribute in the <definitions> root element. Inside the
<service> element, the <port> element specifies the [SOAP]
endpoint/listener for each <binding> element as specified in
section 4.
Using WSDLGen.exe to create WSDL and WSML
The SOAP Toolkit provides us with WSDLGen.exe - this is a wizard-like
application that takes a DLL and produces WSDL and WSML as output.
WSDLGen.exe is a server-side task.
Essentially, we have four steps:
- Selecting the source DLL
- Selecting the methods that we would like to expose as web
services
- Specifying the URI of the SOAP listener
- Specifying a location where the WSDL and WSML files can be
saved
Selecting the source DLL for the wizard to
analyze
The diagram below represents the first decision-making step. We
must provide the path to the DLL that provides the methods we wish
to create WSDL for. The 'name' that you provide will become the name
attribute of the <definitions>
and <service> elements of
the WSDL output.

When you have selected the DLL and provided a service name,
clicking on the Next button moves to
the next step.
Selecting the services you would like to
expose
We are able to selectively choose which methods we wish to expose
- albeit in this example there is only one method.

When you have selected the methods you wish to expose, clicking
on the Next button moves to the next
step.
Specifying the SOAP listener details
The SOAP Toolkit Wizard will create a SOAP listener
automatically. However, because the URI of the SOAP listener forms
part of the WSDL <service>
element, we need to present it to the Wizard. The Wizard can create
two types of SOAP listener: ASP or ISAPI. The Toolkit documentation
recommends the ISAPI listener - this provides for better
performance, but does require that you configure IIS beforehand. For
simplicity, we'll create an ASP listener.

When you have specified the listener URI, clicking on the Next button moves to the next step.
And finally, specifying a location for the WSDL
and WSML files
The Wizard has to save the WSDL and WSML files - given that the
WSDL file has to be accessed from a client-side application/web
browser, you should choose to save them in a directory that is
reachable via HTTP. The screenshot below reflects my preference to
save the WSDL, WSML and ASP script in the same directory as the
development DLL - I then copy the files into a directory that is
reachable via HTTP, in this case the ' wroxtea ' directory on my web server.
We also have to specify which method encoding method we would
like to use. Choose UTF-8 if most of the characters you'll need are
English (they take up one byte) or choose UTF-16 if you require
Asian or Arabic characters (they take up three bytes).

When you have specified the location for the WSDL, WSML and ASP
script files, clicking completes the process.
The Wizard creates the following WSDL ( services.wsdl ): <?xml version='1.0' encoding='UTF-8' ?>
<!-- Generated 05/21/01 by Microsoft SOAP Toolkit WSDL File Generator, Version 1.00.623.1 -->
<definitions name ='service' targetNamespace = 'http://tempuri.org/wsdl/'
xmlns:wsdlns='http://tempuri.org/wsdl/'
xmlns:typens='http://tempuri.org/type'
xmlns:soap='http://schemas.xmlsoap.org/wsdl/soap/'
xmlns:xsd='http://www.w3.org/2001/XMLSchema'
xmlns:stk='http://schemas.microsoft.com/soap-toolkit/wsdl-extension'
xmlns='http://schemas.xmlsoap.org/wsdl/'>
<types>
<schema targetNamespace='http://tempuri.org/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'>
</schema>
</types>
<message name='clsService.Get_ServiceList'>
<part name='sUser' type='xsd:string'/>
<part name='sPassword' type='xsd:string'/>
</message>
<message name='clsService.Get_ServiceListResponse'>
<part name='Result' type='xsd:string'/>
</message>
<portType name='clsServiceSoapPort'>
<operation name='Get_ServiceList' parameterOrder='sUser sPassword'>
<input message='wsdlns:clsService.Get_ServiceList' />
<output message='wsdlns:clsService.Get_ServiceListResponse' />
</operation>
</portType>
<binding name='clsServiceSoapBinding' type='wsdlns:clsServiceSoapPort' >
<stk:binding preferredEncoding='UTF-8'/>
<soap:binding style='rpc' transport='http://schemas.xmlsoap.org/soap/http' />
<operation name='Get_ServiceList' >
<soap:operation soapAction='http://tempuri.org/action/clsService.Get_ServiceList' />
<input>
<soap:body use='encoded' namespace='http://tempuri.org/message/'
encodingStyle='http://schemas.xmlsoap.org/soap/encoding/' />
</input>
<output>
<soap:body use='encoded' namespace='http://tempuri.org/message/'
encodingStyle='http://schemas.xmlsoap.org/soap/encoding/' />
</output>
</operation>
</binding>
<service name='service' >
<port name='clsServiceSoapPort' binding='wsdlns:clsServiceSoapBinding' >
<soap:address location='http://localhost/wroxtea/service.ASP' />
</port>
</service>
</definitions>
The WSDL generator also creates WSML from the DLL. As I mentioned
earlier, WSML provides a server-side mechanism for instantiating the
DLL an invoking the method. Services.wsml looks like this: <?xml version='1.0' encoding='UTF-8' ?>
<!-- Generated 05/21/01 by Microsoft SOAP Toolkit WSDL File Generator, Version 1.00.623.1 -->
<servicemapping name='service'>
<service name='service'>
<using PROGID='teaService.clsService' cachable='0' ID='clsServiceObject' />
<port name='clsServiceSoapPort'>
<operation name='Get_ServiceList'>
<execute uses='clsServiceObject' method='Get_ServiceList' dispID='1610809344'>
<parameter callIndex='1' name='sUser' elementName='sUser' />
<parameter callIndex='2' name='sPassword' elementName='sPassword' />
<parameter callIndex='-1' name='retval' elementName='Result' />
</execute>
</operation>
</port>
</service>
</servicemapping>
In essence, the WSML document provides the SOAP Toolkit with
enough information to be able to write the following server-side
Visual Basic: Dim objService As New teaService.clsService
Dim sServiceXML As String
sServiceXML = objService.Get_ServiceList("CraigM", "Password")
The WSDL generator does not stop there - it creates an ASP script
as well. Clearly the designers of the SOAP Toolkit wanted to reduce
the amount of code we have to write, manage, debug, test, etc. All
we have had to write is a server-side DLL that implements the
methods that solve our problem and the client-side code that calls
those methods. The ASP script below handles the SOAP request and
handles any SOAP faults that may occur: <%@ LANGUAGE=VBScript %>
<%
Option Explicit
On Error Resume Next
Response.ContentType = "text/xml"
Dim SoapServer
If IsEmpty(Application("SoapServer"))Not Application("SoapServerInitialized") Then
Application.Lock
If IsEmpty(Application("SoapServer")) Then
Dim SoapServerNot Application("SoapServerInitialized") Then
Dim WSDLFilePath
Dim WSMLFilePath
WSDLFilePath = Server.MapPath("service.wsdl")
WSMLFilePath = Server.MapPath("service.wsml")
Set SoapServer = Server.CreateObject("MSSOAP.SoapServer")
If Err Then SendFault "Cannot create SoapServer object. " & Err.Description
SoapServer.Init WSDLFilePath, WSMLFilePath
If Err Then SendFault "SoapServer.Init failed. " & Err.Description
Set Application("serviceServer") = SoapServer
Application("SoapServerInitialized") = True
End If
Application.UnLock
End If
Set SoapServer = Application("serviceServer")
SoapServer.SoapInvoke Request, Response, ""
If Err Then SendFault "SoapServer.SoapInvoke failed. " & Err.Description
Sub SendFault(ByVal LogMessage)
Dim Serializer
On Error Resume Next
' "URI Query" logging must be enabled for AppendToLog to work
Response.AppendToLog " SOAP ERROR: " & LogMessage
Set Serializer = Server.CreateObject("MSSOAP.SoapSerializer")
If Err Then
Response.AppendToLog "Could not create SoapSerializer object. " & Err.Description
Response.Status = "500 Internal Server Error"
Else
Serializer.Init Response
If Err Then
Response.AppendToLog "SoapSerializer.Init failed. " & Err.Description
Response.Status = "500 Internal Server Error"
Else
Serializer.startEnvelope
Serializer.startBody
Serializer.startFault "Server", & _
"The request could not be processed due to a problem in the server. " & _
"Please contact the system admistrator. " & LogMessage
Serializer.endFault
Serializer.endBody
Serializer.endEnvelope
If Err Then
Response.AppendToLog "SoapSerializer failed. " & Err.Description
Response.Status = "500 Internal Server Error"
End If
End If
End If
Response.End
End Sub
%>
If you read through the ASP script above, it becomes clear that
the server-side SOAP Toolkit implementation is nothing more than a
few lines of code; here is that code without optimization and
error-checking: Dim SoapServer
Dim WSDLFilePath
Dim WSMLFilePath
WSDLFilePath = Server.MapPath("service.wsdl")
WSMLFilePath = Server.MapPath("service.wsml")
Set SoapServer = Server.CreateObject("MSSOAP.SoapServer")
SoapServer.Init WSDLFilePath, WSMLFilePath
SoapServer.SoapInvoke Request, Response, ""
As can bee seen, the server-side ASP handles SOAP faults. SOAP
faults occur for a variety of reasons (there is more about SOAP
faults here: http://www.asptoday.com/content.asp?id=407&WROXEMPTOKEN=365433ZwwvvVQ81hbeQTnInzTN).
As a short aside, the SOAP Toolkit (beta 1 onwards) returns an
HTTP server 500 error should a fault occur. Whilst this is in
keeping with the SOAP 1.1 specification, it goes against some
popular belief. I myself have preached that Response.Status is for HTTP status messages
only - indeed I have read many articles that lend some weight to
this statement. I admit that I may have been mistaken, however now
that the SOAP Toolkit has implemented this part of SOAP, I will
happily update my applications accordingly.
Why use the Toolkit?
Understanding SOAP might seem like an obvious prerequisite,
however this is one of the advantages of using not just the
Microsoft SOAP toolkit, but is a benefit that may be realized by
using any SOAP toolkit - we do not have to learn "everything" about
SOAP before we can start creating applications. Similarly, you don't
have to know everything there is to know about XML - this is the
real beauty of most SOAP toolkits; they shield us from complexity
that is often unnecessary. Implementing low-level "wire" transport
(HTTP & TCP/IP) and providing code to manage the creation and
analysis of SOAP messages is time consuming and may prove to be a
bug creation scheme. Being free of complexity brings with it a time
saving benefit: we are free to concentrate on solving the original
problem.
Creating WSDL by hand would be a laborious process - and we would
have to understand some XML Schema too! The Toolkit lets us work in
our native development language - it will create the WSDL document
(complete with XML Schema data types) for us.
In a nutshell, the toolkit reduces the amount of periphery work
that we often find ourselves doing in order to build an application
- the SOAP Toolkit allows us to be more productive, quickly.
Back to the client-side implementation
Now that we've seen all the component parts of the SOAP Toolkit,
the server-side implementation, and the client-side architecture,
it's time we looked at the client-side code.
Continuing the "service provider" theme, the code that follows
demonstrates how we can use the Get_ServiceList method that we have exposed
as a web service.
First of all, the following code presents our global
declarations: Option Explicit
Const WSDL_SERVICE = "http://localhost/wroxtea/service.wsdl"
' Keep a list of all the services for this user...
Private xdService As New DOMDocument
Private g_SOAPClient As New SoapClient
The last line is key - it gives us access to the SOAP Toolkit
SOAPClient object. Remember to add a
"Reference" to the SOAP Type Library:

During the OnLoad event we execute
the remote Get_ServiceList web
service. The XML that Get_ServiceList
returns is then loaded into an XML DOM (as provided by the Microsoft
XML Parser, MSXML3.DLL). We then iterate over each element, adding
the <prov> element value to the
service provider list box: Set g_SOAPClient = Nothing
' Populate services listbox
g_SOAPClient.mssoapinit WSDL_SERVICE
sServiceList = g_SOAPClient.Get_ServiceList("CraigM", "Password")
xdService.async = False
xdService.loadXML (sServiceList)
For i = 0 To xdService.documentElement.childNodes.length - 1
Set Node = xdService.documentElement.childNodes(i)
Set serviceNode = Node.selectSingleNode("prov")
sService = serviceNode.Text
lbServices.AddItem sService, i
Next
lbServices.Selected(0) = True
Building DLLs for use on IIS
If you are using Visual Basic to build your server-side DLLs, the
SOAP Toolkit recommends that you build the DLLs using the following
project options:

Registering DLLs
The WSDL Wizard ( WSDLGen.exe )
expects that your DLLs be registered beforehand. Registering a DLL
is the simple matter of choosing the Run. option from the Start menu. In the " Open: " edit control, enter " regsvr32 " followed by the path and filename
of your DLL, as shown below:

If you find using the Browse button
a tiresome process, try dragging the DLL from an Explorer window on
to the " Open :" edit control - this
will have the effect of inserting the full path and filename of the
DLL.
If you need to rebuild the DLL, it is best to unregister it
first. A DLL can be unregistered using the " /U " option, as shown below:

Where do we go from here?
Over the course of this article you have seen the high-level API
in use. The SOAP Toolkit provides a low-level API too. You have
actually seen some of the low-level API already - the server-side
ASP script that is created by the WSDL generator uses the low-level
API to handle SOAP faults.
You may think that using a client-side XMLDOM is inefficient,
from both a memory and a type-safe perspective. However, 3 years
usage of the original Delphi application has led to files of less
than 100K being created, so memory is not such an issue. Also,
because we are in total control over the data that is posted to the
database, we can control the validation - we are able to ensure that
the XML that is returned is of a suitable data type. Granted we
would encounter problems should the database become corrupt, however
that is a hazard with most applications.
As an interesting aside, we (my colleagues and I) developed a
human resource management system that ran over our corporate
Intranet - client/server messaging was conducted using an elementary
JavaScript implementation of a SOAP client and a SOAP server. After
the proof-of-concept prototype had been demonstrated, the first
question our network team asked us was: "What about performance?".
They were worried about the amount of data that our 'application'
was going to add to the existing network chatter. So we conducted
more tests - we worked out the "weakest link" (slowest and least
direct route between endpoints) and began stress testing between
those locations. The average message (XML fragment/HTML page) that
was transmitted was about 10K; the largest was 63K. We obtained
single-figure response times, we were happy, and our user base was
happy. However, our human resource application is only accessible by
selected personnel, so in reality we only ever have a few users at
any one time - how performance is influenced by a larger number of
users is a topic worthy of an article itself!
If you are interested in looking at other SOAP toolkits you may
find the following links useful:
Summary
I have spent much of this article discussing part of my
implementation of a trivial expense logging system - this is one of
the benefits of the SOAP Toolkit: using it leaves us free to
concentrate on building our application. No longer do we have to
write our own SOAP listeners, HTTP transport code or custom fault
handlers. The SOAP Toolkit starts to make invoking a SOAP method
closer to what the 'S' of SOAP is all about: Simple.
Finally, between the betas, RC0 and the Gold release, the SOAP
type mapping was improved to bring the SOAP Toolkit in line with the
most recent XML Schema specifications. A discussion about XML Schema
is beyond the scope of this article, however you can find out more
about XML Schema here:
- W3C Schema Primer: http://www.w3.org/TR/xmlschema-0/
- XML Schema Part 1: Structures:
http://www.w3.org/TR/xmlschema-1/
- XML Schema Part 2: Datatypes:
http://www.w3.org/TR/xmlschema-2/
|