Wrox Press
ASPToday
       979 Articles
  in the Solutions Library
  Log off
 
 
 
Wrox Press Programming Books!  
 
ASPToday Subscriber's Article Craig Murphy
The Microsoft SOAP Toolkit Version 2 - The High Level API
by Craig Murphy
Categories: XML/Data Transfer
Article Rating: 4.5
Published on June 13, 2001
 
Content Related Links Discussion Comments Index Entries Downloads
 
Abstract
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. In this article, Craig Murphy provides an overview of the Microsoft SOAP Toolkit Version 2.0; the sample application code will be provided in Visual Basic and VBScript.
 
 
Article

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/
 
 
 
Rate this Article
How useful was this article?
Not useful Very useful
Brief Reader Comments: Read Comments
Your name (optional):
 
 
Content Related Links Discussion Comments Index Entries Downloads
 
Back to top