This is just an illustration just how badly designed the SOAP Toolkit was. I was working on my samples for Southwest Fox for my .NET Web Services Interop session from VFP. One of my samples demonstrates going out to my West Wind Web Store downloading a complex array of order business objects and then importing this data on the client.
I decided to use the SOAP Toolkit for demonstration purposes rather than my proprietary wwSOAP class, because in this case the data retrieved was actually in dataset format and the parsing wouldn’t be any easier with wwSOAP.
The code is straight forward if a little verbose, and it works just fine against my local machine. But when I tried to download orders off the Web from my live site the SOAP Toolkit choked. The live site uses authentication and sure enough I had to set authentication on the client. Setting authentication with the SOAP Toolkit involves setting a couple of connector properties which looks something like this:
PROTECTED FUNCTION SetMSSOAPConnectionProperties(lcUrl)
THIS.oSOAP = CREATEOBJECT(MSSOAP_PROGID)
THIS.oSOAP.mssoapinit(lcUrl)
IF !EMPTY(THIS.cUserName)
THIS.oSOAP.ConnectorProperty("AuthUser") = this.cUserName
THIS.oSOAP.ConnectorProperty("AuthPassword") = this.cPassword
ENDIF
this.oSOAP.ConnectorProperty("ConnectTimeout") = this.nTimeout * 1000
this.oSOAP.ConnectorProperty("Timeout") = this.nTimeout * 1000
IF !EMPTY(THIS.cProxy)
this.oSOAP.ConnectorProperty("ProxyServer") = this.cProxy
ELSE
this.oSOAP.ConnectorProperty("ProxyServer") = ""
ENDIF
ENDFUNC
Note the ever so intuitive use of Connector Properties, which are a lazy persons way of building a half assed tool kit.
But this still failed on the Web Service. Note that the ConnectorProperties can be set only AFTER the call to MsSoapInit(). See the problem here?
MsSoapInit() actually goes out and reads the WSDL file from the URL provided, but if the WSDL URL is also protected via Authentication, the MsSoapInit() call fails. Since in most applications – especially .NET Web Services – the Service Url and WSDL URL are one and the same physical page reference this is not going to work.
The workaround is a laughable one – you have to modify the WSDL URL by injecting the username and password into it in this format:
http://username:password@west-wind.com/webstore/service/AdminService.asmx?Wsdl
The code to inject this looks like this:
lcUrl = TRIM(this.cWSDLUrl)
*** Fix up Url to include username and password
*** How freaking lame is this???
IF !EMPTY(this.cUsername)
lcUrl = STRTRAN(lcUrl,"http://","http://" + this.cUsername + ;
":" + this.cPassword + "@",1,1,1)
IF lcUrl = this.cWsdlUrl
lcUrl = STRTRAN(this.cWSDLUrl,"https://","https://" + ;
this.cUsername + ":" + this.cPassword + "@",1,1,1)
ENDIF
ENDIF
THIS.oSOAP.mssoapinit(lcUrl)
Note that this URL isn’t a valid URL any longer as IE doesn’t allow username and password on the Address line in the browser. Why? Huge security risk to pass the username and password over the wire like this and the SOAP Toolkit happily goes ahead and sends it.
If you need proxy configuration on the WSDL URL – good luck. That feature cannot be embedded into the URL. I couldn’t find any info on getting that to work.
It’s a good thing that the SOAP Toolkit was a short lived thing for Microsoft with .NET Web Service clients superceding the functionality. The .NET client is much better but it too doesn’t have a lot of configurability. For example, native .NET does not have support for dynamically creating SOAP envelopes. That functionality was added only recently with WSE Service support and I presume Indigo (WCF) too will have that support buried somewhere in its bowels.
But SOAP for non-.NET clients is a pain in the ass. MSSOAP is full of holes, can’t deal with complex types. My own wwSOAP class (VFP based SOAP client) works for many things, but it doesn’t do nearly everything defined in the SOAP spec and it too chokes on off the wall SOAP implementations – it’s optimized for .NET and SOAP Toolkit Web Services. And even there, there are limitations.
Other Posts you might also like