Wrox Press
ASPToday
       979 Articles
  in the Solutions Library
  Log off
 
 
 
BrowserHawk!  
 
ASPToday Subscriber's Article
Working with the Microsoft SOAP Toolkit
by
Categories: XML/Data Transfer
Article Rating: 3.5
Published on October 30, 2000
 
Content Related Links Discussion Comments Index Entries Downloads
 
Abstract
In Craig Murphy's previous articles, he demonstrated how we can create SOAP clients and listeners from scratch. Whilst this was a good way to learn about SOAP, it's a fairly labor–intensive process. The SOAP Toolkit alleviates some pressure – not only is there a wizard that creates a SOAP listener from a COM object, but Client–side support is also simplified by the provision of an object that can manage SOAP requests and responses. Read on to learn how to use this, and other advantages of working with the SOAP Toolkit.
 
Article
Working with the Microsoft SOAP Toolkit

The Simple Object Access Protocol continues to gather more and more keen supporters. As more developers embrace SOAP, the greater the need for common libraries and tools – this is especially important, as different SOAP implementations must be able to co–exist in harmony. The Microsoft SOAP Toolkit bridges the gap between current development strategies and the .NET approach. The Toolkit breathes life into your legacy COM objects, allowing them to be used as part of your .NET solutions.

Introduction

In my previous articles, I demonstrated how we could create SOAP clients and listeners from scratch. Whilst this was a good way to learn about SOAP, it's a fairly labor–intensive process. The SOAP Toolkit alleviates some of pressure – notably there's a wizard that creates a SOAP listener from a COM object. Client–side support is also simplified by the provision of an object that can manage SOAP requests and responses.

The Toolkit maintains the ethos behind SOAP – interoperability. Whilst the Toolkit offers client–side support, it doesn't insist that you use it – you're free to implement your own SOAP Request/Response handlers on the client if you so desire. This means, for example, that non–Windows 2000 clients that support HTTP are able to take advantage of the server–side Toolkit implementation. After all, the client isn't interested in how the server processes a SOAP request, only that it does what is asked of it.

Getting Started

I will assume that you have downloaded and installed the Toolkit in default directory ( C:\Program Files\SOAP Toolkit ). Familiarity with the SOAP architecture, and why it's useful to us is also beneficial. The Toolkit is available for download: http://msdn.microsoft.com/xml/general/toolkit_intro.asp?WROXEMPTOKEN=365433ZwwvvVQ81hbeQTnInzTN. The current version of the Toolkit requires that you have Visual Studio 6 SP3 installed.

There will be a database involved, currency.mdb – it's part of the download associated with this article. Access to the database will be via a DSN – you'll need to create one called ASPToday and point it to currency.mdb on your system.

I've built and tested my Toolkit applications using Windows 2000 Server. Microsoft has tested the Toolkit using Windows 2000 Server and Professional. The Toolkit has been through basic testing with Windows NT 4.0 SP6a and Internet Explorer 5.0. At the moment, there is no Windows 9x release – although if you look through the newsgroups mentioned at the end of this article, there are a couple of third parties who have ported a version to Windows 9x.

The SOAP Toolkit Explained

The Toolkit comprises of three major parts:

  • A Remote Object Proxy Engine (ROPE) – this is supplied as a DLL. ROPE offers methods capable of packaging a SOAP Request, and also "unscrambling" a SOAP Response.
  • An SDL Wizard – this is an EXE that offers a step–by–step means of gathering the information that is required to create an SDL file and an ASP. SDL stands for Service Description Language. SDL is used to allow SOAP clients the opportunity to find out which methods are available from a given SOAP provider. The Toolkit includes an early draft of the SDL specification. We'll see an example SDL file later in this article.
  • A SOAP client and the associated SOAP server – the client is implemented as a Visual Basic application; the server is implemented using ASP.

A Worked Example

To demonstrate the Toolkit, we'll need to understand what's required on the server and what's required on the client. As soon as we've covered the server and client requirements, we'll take a look at the SDL Wizard.

Server–side Requirements

To demonstrate the server–side aspects of the Toolkit I will use a simple COM object created using Visual Basic 6. The COM object is called ASPToday.dll and offers three methods:

  • GetCurrencyList – creates an XML fragment that contains a list of countries and currencies
  • GetCurrency – return a currency rate based on the specified currency identifier
  • SetCurrency – update the currency rate for a specified currency identifier

You'll need to register the COM object ASPToday.dll . To register ASPToday.dll , click on the Start menu, choose Run – enter RegSvr32 C:\ASPToday.dll then click on OK . To unregister ASPToday.dll , use the command RegSvr32 /u C:\ASPToday.dll . In both cases I've assumed that the DLL is in the root of your C: – you may need to change this to suit your system. ROPE.DLL will also need to be registered on the server.

The SDL Wizard

The SDL Wizard accepts as input the path to an existing COM object (a DLL or EXE). We're able to select which methods we would like to expose to our SOAP clients/consumers – thus we're not committed to exposing every single method that the COM object provides. The wizard also allows us to select the type of SOAP listener we would like – there are two choices: ISAPI and ASP. The ISAPI listener benefits from slightly better performance than the ASP listener, however the latter benefits from greater degrees of customization – after all, the ASP listener is VBScript. There's more about the ASP listener later in this article.

The SDL Wizard creates two files based on the COM object:

  • An XML file that provides the SDL for the methods that we selected. The SDL file contains not only the methods, but their data types also – we'll see how this can be of use to us when we look at the client–side implementation.
  • An ASP file that contains 'wrapper' functions for the methods that we selected.

Client–side Requirements

ROPE.DLL (part of the Toolkit) also needs to be installed and registered on the client system – you can do this by using RegSvr32, as detailed above.

To demonstrate the Toolkit, I'll be creating a web page that performs simple currency conversion – the page will send and receive SOAP requests and responses.

Now that we know what we're trying to achieve, let's go through the steps required to get it all to work.

Using the SDL Wizard

The SDL Wizard is a server–side task. Running SDLWizard.exe starts the wizard. There are six steps; the first is a Welcome screen, the last is a Finish screen. We'll take a look at the remaining four steps.

Selecting the source for wizard's output

The wizard needs to know whether you are asking it to create source files from an existing COM object or from an existing SDL file. We'll be creating source files for ASPToday.dll , so click on the Select COM object button then locate your copy of ASPToday.dll .

As we'll see shortly, creating an SDL file by hand is a daunting task, so it's likely that you'll be creating source for an existing COM object. However it's feasible that another tool has created some SDL for you – in which case the wizard is here to create the ASP wrapper functions for you.

If all went well, the screenshot below should look familiar:

After you've selected your copy of ASPToday.dll , click on the Next button to move to the next step.

Selecting the services you would like to expose

The wizard uses the phrase services synonymously with methods . We're now being asked to specify which methods from ASPToday.dll that we would like to make available to our SOAP clients. The wizard doesn't force us to expose "all or nothing" – we can select just those methods we need to expose. In our case, we're going to expose them all – click on the ASPToday entry to select all the methods, as per the screenshot below:

After you've made sure there's a tick beside the three methods that we wish to expose to our SOAP clients, click on the Next button to continue.

SOAP listener information

The wizard now requires the URI for the SOAP listener. I've got my web server (IIS) configured such that localhost points to a directory called soaptk . Inside soaptk there is a directory called asptoday – this is where I am storing the SOAP listener.

Specify the location for the new source files

The new source files the wizard talks about are in fact the SDL file and the ASP file that contains the VBScript wrapper functions. In order to get this example to work "out of the box", the location that these files are stored in should be in the same place as the SOAP listener – the screenshot below reflects this:

Clicking on Next completes the process. In the ASPToday directory there should be two new files – Currency.xml and Currency.asp .

Here's the SDL for ASPToday.dll ( Currency.xml ):

<?xml version='1.0' ?>
<!–– Generated 04/10/2000 21:33:39 by Microsoft SOAP Toolkit Wizard, Version 205.0.3 ––>
<serviceDescription name='ASPToday' 
  xmlns='urn:schemas–xmlsoap–org:sdl.2000–01–25' 
  xmlns:dt='http://www.w3.org/1999/XMLSchema' 
  xmlns:Currency='Currency' 
>
<import namespace='Currency' location='#Currency'/>

  <soap xmlns='urn:schemas–xmlsoap–org:soap–sdl–2000–01–25'>
    <interface name='Currency'>
      <requestResponse name='GetCurrencyList'>
        <request ref='Currency:GetCurrencyList'/>
        <response ref='Currency:GetCurrencyListResponse'/>
      </requestResponse>
      <requestResponse name='GetCurrency'>
        <request ref='Currency:GetCurrency'/>
        <response ref='Currency:GetCurrencyResponse'/>
        <parameterorder>CurrID</parameterorder>
      </requestResponse>
      <requestResponse name='SetCurrency'>
        <request ref='Currency:SetCurrency'/>
        <response ref='Currency:SetCurrencyResponse'/>
        <parameterorder>CurrID fRate</parameterorder>
      </requestResponse>
    </interface>
    <service>
      <addresses>
        <address uri='http://localhost/asptoday/Currency.asp'/>
      </addresses>
      <implements name='Currency'/>
    </service>
  </soap>


  <Currency:schema id='Currency' targetNamespace='Currency' xmlns='http://www.w3.org/1999/XMLSchema'>
    <element name='GetCurrencyList'>
    </element>
    <element name='GetCurrencyListResponse'>
      <type>
        <element name='return' type='dt:string'/>
      </type>
    </element>
    <element name='GetCurrency'>
      <type>
        <element name='CurrID' type='dt:string'/>
      </type>
    </element>
    <element name='GetCurrencyResponse'>
      <type>
        <element name='return' type='dt:double'/>
      </type>
    </element>
    <element name='SetCurrency'>
      <type>
        <element name='CurrID' type='dt:short'/>
        <element name='fRate' type='dt:double'/>
      </type>
    </element>
    <element name='SetCurrencyResponse'>
      <type>
        <element name='return' type='dt:boolean'/>
      </type>
    </element>
  </Currency:schema>

</serviceDescription>

As you can see, it's not the kind of file we would like to create by hand!

The SDL file comprises of three sections:

  • <interface> – this element records the methods that the listener supports.
  • <service> – this element specifies the location of the ASP SOAP Listener that is able to process SOAP requests.
  • <schema> – this element is prefixed with a namespace to uniquely identify it as being part of the Currency interface. This means that there can be more than one <schema> element – one for each interface. The <schema> element identifies the parameters and data–types that each method expects when called via a SOAP request. It also identifies the return parameters and data–types. For example, we can see that the SetCurrency SOAP Request should be packaged up with two parameters – CurrID and fRate . CurrID is of type short and fRate is a double . After the SetCurrency method has executed, the SOAP Response has one parameter – return . It has a type of boolean .

Currency.asp , the ASP VBScript wrapper functions are shown below:

<%@ Language=VBScript %>

<% Option Explicit

Response.Expires = 0

'––––––––––––––––––––––––––––––––––––––––––––
' SOAP ASP Interface file Currency.asp
' Generated 04/10/2000 21:33:39
' By Microsoft SOAP Toolkit Wizard, Version 205.0.3
'––––––––––––––––––––––––––––––––––––––––––––

Const SOAP_SDLURI = "http://localhost/asptoday/Currency.xml" 'URI of service description file 
%>
<!––#include file="listener.asp"––>

<%

Public Function GetCurrencyList ()
  Dim objGetCurrencyList
  Set objGetCurrencyList = Server.CreateObject("ASPToday.Currency")

  GetCurrencyList = objGetCurrencyList.GetCurrencyList()
  'Insert additional code here

  Set objGetCurrencyList = NOTHING
End Function


Public Function GetCurrency (ByVal CurrID)
  Dim objGetCurrency
  Set objGetCurrency = Server.CreateObject("ASPToday.Currency")

  GetCurrency = objGetCurrency.GetCurrency(CurrID)
  'Insert additional code here

  Set objGetCurrency = NOTHING
End Function


Public Function SetCurrency (ByVal CurrID, ByVal fRate)
  Dim objSetCurrency
  Set objSetCurrency = Server.CreateObject("ASPToday.Currency")

  SetCurrency = objSetCurrency.SetCurrency(CurrID, fRate)
  'Insert additional code here

  Set objSetCurrency = NOTHING
End Function

%>

There's not much to these functions, they offer an ASP front–end to the methods that our COM object provides. It's possible to include additional code in the ASP functions – thus we're able to amend the input parameters prior to the COM object methods being called. Likewise, we can amend the outputs after the methods have been called. This is perhaps useful if the source code for that essential COM object has gone missing!

The Toolkit is supplied with a generic listener.asp – reading through the code above, it becomes clear that we need to copy this file in to the ASPToday folder. You'll find a copy of listener.asp in the C:\Program Files\SOAP_Toolkit\ASP_Listener directory – assuming that's where you installed the Toolkit.

Inside the Remote Object Proxy Engine

ROPE is primarily used client–side, however listener.asp actually uses it too – ROPE.DLL provides methods that can process SOAP requests and SOAP responses.

ROPE Objects

ROPE.DLL exposes seven objects:

  • Proxy is considered by Microsoft to be the primary client–side interface for accessing SOAP endpoints. We'll see an example of the Proxy object later in this article.
  • SOAPPackager is able to package SOAP requests; it's also able to "unpack" SOAP responses.
  • WireTransfer is responsible for sending the SOAP Request over "the wire". Essentially, it provides all the HTTP GET and POST interactions that are required.
  • ServiceDescriptors , SDMethodInfo , SDParameterInfo , and SDEndPointInfo provide a means of iterating over the SDL file examining the methods and parameters on the way. An examination of these objects is beyond the scope of this article.

ROPE provides two mechanisms for a client to send a SOAP request. The first method involves using the Proxy object; the second involves a combination of the SOAPPackager and WireTransfer objects.

I'll be demonstrating these objects using an example web page with some VBScript; the screenshot below depicts the web page:

Using the Proxy object

The proxy object allows us to treat our SOAP methods as if they were in a COM object that is installed on the local machine, i.e. we can bind to the SOAP method at run–time.

The code behind the Update Rate button demonstrates the Proxy object in action:

function update(sCurrency, sRate)
  dim objProxy 
  Set objProxy = CreateObject("ROPE.Proxy")

  objProxy.LoadServicesDescription icURI, "http://localhost/asptoday/currency.xml", ""

  objProxy.SetCurrency sCurrency, sRate 

  Set objProxy = Nothing
end function

Unfortunately, ROPE.DLL is not "marked as safe", therefore Internet Explorer will take the action specified by the "Initialize and script ActiveX controls not marked as safe" security option. Depending upon your settings, you may experience difficulty getting the example to work. To amend the security option in Internet Explorer, choose the Tools menu, then Internet Options . Locate the ActiveX controls and plug–ins item – then change the Initialize and Script ActiveX controls not marked as safe option to enable or prompt . Alternatively, you can change the overall security settings to Low . If you experience further problems it may be because of the XML Parser type you are running. To solve this and ensure the parser is in Replace mode, run xmlinst.exe which is found at C:\WINNT\System32 .

Using the SOAPPackager and WireTransfer Objects

The proxy object gave us an easy means of executing our SOAP methods – however, what if the SOAP methods no longer exist? The proxy object has no means of helping us. The SOAPPackager object, however, can help us – it offers a method IsMethodAvailable that allows us to check for the existence of a method before we create a SOAP Request.

The code behind the Convert button demonstrates the greater power offered by the SOAPPackager and WireTransfer objects:

function convert(sCurrency, sAmount)
  dim objSP
  dim objWT
  Set objSP = CreateObject("ROPE.SoapPackager")
  Set objWT = CreateObject("ROPE.WireTransfer")

  objSP.LoadServicesDescription icURI, "http://localhost/asptoday/currency.xml", ""

  ' check to see that we can execute the method
  if objSP.IsMethodAvailable("GetCurrency") then

   ' Prepare the SOAP Request for the getCurrency method...
   sRequestStruct = objSP.GetMethodStruct("GetCurrency", icINPUT)
   objSP.SetPayloadData icREQUEST, "", "GetCurrency", sRequestStruct

   objSP.SetParameter icREQUEST, "CurrID", sCurrency
   
   sRequestPayload = objSP.GetPayload(icREQUEST)

   ' Add the usual SOAP Headers to SOAP Request
   objWT.AddStdSOAPHeaders "http://localhost/asptoday/currency.asp", "GetCurrency", Len(sRequestPayload)

   ' Send the SOAP Request over "the wire" using HTTP...
   sResponsePayload = objWT.PostDataToURI("http://localhost/asptoday/currency.asp", sRequestPayload)
   
   ' Format the payload to be a SOAP Response
   objSP.SetPayload icRESPONSE, sResponsePayload

   ' Extract the 'return' element
   sRate = objSP.GetParameter(icRESPONSE, "return")

   ' perform the calculation
   txt_converted_amount.value = sRate * sAmount
   end if

  Set objSP = Nothing
  Set objWT = Nothing
end function

The call to objSP.GetMethodStruct retrieves an XML fragment that matches the GetCurrency method:

<GetCurrency>
<CurrID></CurrID>
</GetCurrency>

The XML fragment is built from the entry in the SDL file:

<element name='GetCurrency'>
    <type>
      <element name='CurrID' type='dt:string'/>
    </type>
</element>

At this point, CurrID is empty. The call to objSP.SetParameter sets the CurrID parameter accordingly:

objSP.SetParameter icREQUEST, "CurrID", sCurrency

However, it's not until we examine the whole SOAP Request payload that we can confirm that CurrID was set. Calling objSP.GetPayload returns the SOAP message (formatted as a request or a response – in this case we're dealing with a request):

sRequestPayload = objSP.GetPayload(icREQUEST)

The final SOAP Request payload looks like this:

<?xml version="1.0"?>
<SOAP:Envelope xmlns:SOAP="http://schemas.xmlsoap.org/soap/envelope/" SOAP:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<SOAP:Body>
<GetCurrency>
<CurrID>1</CurrID>
</GetCurrency>
</SOAP:Body>
</SOAP:Envelope>

All that's required now, is the addition of SOAP headers, and our request is ready to post to the listener:

' Add the usual SOAP Headers to SOAP Request
objWT.AddStdSOAPHeaders "http://localhost/asptoday/currency.asp", "GetCurrency", Len(sRequestPayload)

' Send the SOAP Request over "the wire" using HTTP...
sResponsePayload = objWT.PostDataToURI("http://localhost/asptoday/currency.asp", sRequestPayload)

PostDataToURI performs an asynchronous post to the SOAP listener – i.e. it will block until a timeout or a response is received. Assuming a response is received, PostDataToURI returns a formatted SOAP Response.

We can then call GetParameter to extract the XML element return – this holds the actual exchange rate value.

' Format the payload to be a SOAP Response
objSP.SetPayload icRESPONSE, sResponsePayload

' Extract the 'return' element
sRate = objSP.GetParameter(icRESPONSE, "return")

' perform the calculation
txt_converted_amount.value = sRate * sAmount

Type Safety

As developers we're used to the benefits that type–safety can offer us. The SDL doesn't just specify the methods that a SOAP consumer may use, but also specifies the data–types that method uses. The data–type is specified by the addition of the data–type attribute to an SDL schema element:

<element name='SetCurrency'>
    <type>
       <element name='CurrID' type='dt:short'/>
       <element name='fRate' type='dt:double'/>
     </type>
</element>

Whilst our web page example can't take advantage of type safety, your favorite typed language can. If you get the types of your parameters wrong, server–side ROPE will respond with a SOAP fault – indicating a type mismatch.

Passing XML as Parameters

The GetParameter method in the current version of ROPE will remove XML element tags. This is peculiar because the SOAP Request Payload actually contains the XML element tags. The current solution to this problem is to enclose any XML in a <![CDATA[…]] section. There's an example of how to do this in the ASPToday.dll source code.

Using <!CDATA[ returns a single string that contains an <id> , <country> and a <currency_name> . Thus we have lost the notion of type–safety. It's possible to modify the SDL file to allow the data types to be specified. There's a good discussion about the merits of this technique and the <![CDATA[ technique at http://msdn.microsoft.com/xml/articles/soapguide_ado.asp?WROXEMPTOKEN=365433ZwwvvVQ81hbeQTnInzTN.

Summary

This article has proven that there is a place for the SOAP Toolkit in your development portfolio. The .NET approach offers C# as the language for choice for web services, rewriting your existing COM objects in C# is time–consuming and would introduce new bugs. Thus, the Toolkit is a great way of extending the life of the COM objects you can't afford to be without. There is, fortunately, considerable overlap between the SOAP Toolkit and the .NET approach – both use the SDL.

Finally, if you're keen to stay abreast with what's happening in the world of SOAP there are two newsgroups that I can recommend. Both are located on the msnews.microsoft.com server: microsoft.public.xml.soap and microsoft.public.mdsn.soaptoolkit

 
 
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