One of my projects at work is to write a semi-public web service.  One of the requirements is that the service is actually callable from other languages (instead of just .NET->.NET).

So, in order to make sure my web service was accessible, I decided I'd write some tests using Java, Perl, Python and VB6.  These seem like a pretty good selection of general-use languages that our customers may use.  One of the things I really wanted to test was how these other languages would handle complex data types coming back from my web service.

I'm a big fan of returning structs (or classes) from web services (especially in a .NET->.NET environment) because IMO, it's intuitive from both the web service and the consumer.  I also prefer it over something like Xml because it's less work from the consumer standpoint.  With Xml, not only does the consumer need to know the structure of the Xml, they also have to deal with manually loading and parsing the data using whatever library they have available.

My test web service is written in C# and has a single method:
[WebMethod]
public ReturnInformation TestMethod(string data);

ReturnInformation is a public struct found inside my web service.  It looks like this:
public struct ReturnInformation {
    public string ReturnCode;
    public string ReturnMessage;
}

So, from .NET, I would call the web service like this:
// make the web reference and then create the object
TestService test = new TestService();
ReturnInformation ri = test.TestMethod(”blah”);
if (ri.ReturnCode == “success”) {
        Console.WriteLine(”This test worked”);
} else {
    Console.WriteLine(”the test failed.”);
}

My Perl test went pretty smoothly.  Perl rocks because there are thousands of well-written modules that take care of the nitty-gritty details for you.  In this case, I used the SOAP::Lite module:
#!/usr/bin/perl -w
use strict;
use SOAP::Lite;
my $service = SOAP::Lite->service('http://localhost/TestWS/TestService.asmx?WSDL');
my $results = $service->TestMethod("mjeaton");
if($results->{'returnCode'} eq "success") {
 print "The test worked!";
} else {
 print "The test failed!";
}

That was pretty damn simple!

On to the Python example.  The cool thing about Python (and I hate to admit it, but I was impressed) was that I could interactively develop the test program.  Once I knew it was working, I simply copied my good code into a stand-alone script.

from SOAPpy import WSDL
from xml.dom import minidom
from xml.dom.minidom import parse, parseString

proxy = WSDL.Proxy('http://localhost/TestWS/TestService.asmx?WSDL')
result = proxy.TestMethod('test')
if result.returnCode == 'success':
    print 'the test worked!'
else:
    print 'the test failed!'


Again, that was pretty damn easy!

I had my fingers crossed that the Java version would be just as simple, but boy, was I wrong!  After searching for over an hour to find out if there was a “standard” way of calling a web service.  I emailed one of my former students who uses Java pretty regularly.  He didn't know, so after more searching, I eventually settled on 'Axis'.  Before I tried installing the full version, I found the runtimes (several .jar files)!  This was great because I wanted to get things working quickly.

Ok, so the Java version ended up being quite complicated.  Luckily I found an Axis sample which really helped.  I created proxy classes with the help of Axis.  Once these proxies were created, I could actually write the test code:
import org.apache.axis.client.Call;
import org.apache.axis.client.Service;
import javax.xml.namespace.QName;
import java.net.URL;
import org.tempuri.TestServiceLocator;
import org.tempuri.TestService;
import org.tempuri.TestServiceSoap;
import org.tempuri.ReturnInformation;

public class WSTest {
  /**
   * Use strongly types stubs created by WSDL2Java generator.
   */
    public static void doTest() {
        try {
            TestService service = new TestServiceLocator();
            String endpoint = "
http://localhost/TestWS/TestService.asmx";
            TestServiceSoap dx = service.getTestServiceSoap(new URL(endpoint));
            ReturnInformation ret = dx.testMethod("test");

            System.out.println("Results (useStub):");
            System.out.println("   return          = " + ret.getReturnCode());
            System.out.println("   message         = " + ret.getReturnMessage());
        } catch (Exception e) {
               System.err.println(e.toString());
        }
  }

  public static void main(String[] args) {
      doTest();
  }
}

The VB6 version was pretty simple since I used the SOAP Toolkit 3.0.  The one difference is that I actually had to put the return value into an XMLNodeList and access it in a rather non-intuitive way:
Dim oSoapClient As MSSOAPLib30.SoapClient30
Set oSoapClient = New MSSOAPLib30.SoapClient30
Call oSoapClient.MSSoapInit("
http://localhost/TestWS/TestService.asmx?WSDL")

Dim vXMLNodeList As MSXML2.IXMLDOMNodeList

Set vXMLNodeList = oSoapClient.TestMethod("mjeaton")
    
Dim strResult As String
    
strResult = vXMLNodeList.Item(0).Text
If (strResult = "success") Then
    MsgBox "It worked!"
Else
    MsgBox "it failed!"
End If

My experience writing these tests has a) given me a different view of Python and b) made me glad I'm not using Java on a regular basis!