function readOnly(count){ }
Starting November 20, the site will be set to read-only. On December 4, 2023,
forum discussions will move to the Trailblazer Community.
+ Start a Discussion
Rich.ax131Rich.ax131 

SOAP and VB6

I'm trying to make a SOAP Login function call in VB6 using v4 of the API.  This same technique worked fine with v1 of the API, but the code below produces a "Premature end of file" error message.  I can't find any documentation on that particular error.  Any suggestions?

Dim objHTTP As New MSXML2.XMLHTTP
    Dim strUsername As String
    Dim strPassword As String
    Dim sforceSoapServer As String
    Dim strSoapBody As String
    Dim strResponse As String
   
    strUsername = [username]
    strPassword = [password]
    sforceSoapServer = "https://na1-api.salesforce.com/servlet/servlet.SoapApi"
   
    strSoapBody = strSoapBody & ""
    strSoapBody = strSoapBody & "   http://schemas.xmlsoap.org/soap/envelope/"""
    strSoapBody = strSoapBody & "xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance"" xmlns:xsd=""http://"
    strSoapBody = strSoapBody & "www.w3.org/2001/XMLSchema"">"
    strSoapBody = strSoapBody & "      "
    strSoapBody = strSoapBody & "         "
    strSoapBody = strSoapBody & "            " & strUsername & ""
    strSoapBody = strSoapBody & "            " & strPassword & ""
    strSoapBody = strSoapBody & "         "
    strSoapBody = strSoapBody & "      "
    strSoapBody = strSoapBody & "   "
       
    'Build the SOAP header
    Set XMLHTTP = CreateObject("Msxml2.ServerXMLHTTP")
    XMLHTTP.Open "POST", sforceSoapServer, False   'False = do not respond immediately
    XMLHTTP.setRequestHeader "Man", POST & " " & sforceSoapServer & " HTTP/1.1"
    XMLHTTP.setRequestHeader "Content-Type", "text/xml"
       
    'Send the SOAP request
    XMLHTTP.send (strSoapRequest)
    strResponse = XMLHTTP.responseText
    Debug.Print strResponse
    Set XMLHTTP = Nothing

SuperfellSuperfell
Seem to have lost of the tags in posting, but the first thing i spotted it that you're sending the request to the wrong Url for the 4.0 api, it should be https://www.salesforce.com/services/Soap/c/4.0

Cheers
Simon
Rich.ax131Rich.ax131

Ok.  Not sure where I got that URL.  I changed to that URL and now it's producing a new error:

UNKNOWN_EXCEPTION
Destination URL not reset. The URL returned from login must be set in the SforceService

I'm using the SOAP Login function call from the sForce documentation provided in the link below. 

http://www.sforce.com/us/docs/sforce40/wwhelp/wwhimpl/js/html/wwhelp.htm

SuperfellSuperfell
The response to login includes a serverUrl which is the Url you use on subsequent calls after login. you get this error when you try and call methods other than login at the original url.

Rather than doing everything by hand, you might want to try using a soap toolkit, .NET, our office toolkit and PocketSOAP can all be used from ASP.
Rich.ax131Rich.ax131

I'm not quite sure I follow, since "Login" is the only call I'm attempting to make right now.  I haven't gotten to the point yet where I'm making subsequent calls.

I see references on this board to "COM" and "Office" toolkits, but I haven't been able to find links to them anywhere on this site.  I'd love an alternative to doing SOAP by hand, but we are not .NET yet.  If you can direct me where I can find such toolkits I would be appreciative.

SuperfellSuperfell
The Office toolkit is installed as part of Office Edition which is available by logging into the app and clicking setup then office edition.

If you can get .NET installed on your web server, you can use its web services stack from ASP (there are articiles on MSDN about this)

PocketSOAP is available from www.pocketsoap.com/pocketsoap

If you're calling login, and getting that error, then your probably not specifying the correct namespace and/or localname for the login element. Can you repost your code (or a capture of the generated request) with the xml elements showing?
Rich.ax131Rich.ax131

I'll explore the other options you mention. 

Here's a the request I'm generating that returns the error (with "[username]" and "[password]" replaced by literal values:

  
<?xml version="1.0" encoding="utf-8"?>  
 <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">     
  <soap:Body>        
   <login xmlns="urn:enterprise.soap.sforce.com">           
    <username>[username]</username>           
    <password>[password]</password>        
   </login>     
  </soap:Body>  
 </soap:Envelope>

Rich.ax131Rich.ax131

Still no luck in my efforts to transition to v4 of the API.  .NET is currently not an option for the application I need to integrate.  Actions taken so far:

1. Hand-code my SOAP messages.  I was getting multiple errors with this approach and was advised on this board to try PocketSoap or some other SOAP wrapper.

2. The sForce wrapper around PocketSoap downloaded here (http://www.pocketsoap.com/weblog/stories/2004/05/0026.html).  I was able to log in using this approach, but I'm having problems executing queries.  In any case, I'm not crazy about this technique because if fields are added or removed, the interface breaks.

3. Straight PocketSoap.  The following code (modified from a working sample) produces the following error: "Error opening CertificateStore"

dim e
set e = server.CreateObject("PocketSOAP.Envelope.2")
e.methodName = "login"
e.URI = "urn:enterprise.soap.sforce.com"
e.Parameters.Create "username", [username]
e.Parameters.Create "password", [password]
dim t
set t = server.CreateObject("PocketSOAP.HTTPTransport.2")
't.SOAPAction = ""
t.Send "https://www.salesforce.com/services/Soap/c/4.0", e.serialize
e.parse t
response.write "Return value = " & e.parameters.item(0).Value

Any suggestions?  I'm desperately looking for options to access v4 of the API NOT using .NET.

Thanks.

SuperfellSuperfell
The PocketSOAP error is because the ASP user can't open its own keystore, search on the msdn kb for the fix for this.

Can you post a capture of your hand coded request xml along with all the http headers, there's nothing obviously wrong with that XML. can you also post the error you're getting to that request.
Rich.ax131Rich.ax131

1. Could you possibly point me to the MSDN fix?  I'm not coming up with anything relevant looking using the keyword "keystore."

2. The hand-coded SOAP request and resulting error are detailed in the first couple posts of this thread.

 

Thank you.

SuperfellSuperfell
For the hand coded request, can you capture the HTTP headers that are being sent, thanks.
Rich.ax131Rich.ax131

Here's the request:

<?xml version="1.0" encoding="utf-8"?>
 <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"   xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <soap:Body>
   <login xmlns="urn:enterprise.soap.sforce.com">
    <username>[username]</username>
    <password>[password]</password>
   </login>
  </soap:Body>
 </soap:Envelope>

Here's the response:

<?xml version="1.0" encoding="UTF-8"?>
 <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema"     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <soapenv:Body>
   <soapenv:Fault>
    <faultcode>soapenv:Server</faultcode>
    <faultstring>Destination URL not reset. The URL returned from login must be set in the SforceService</faultstring>
    <detail>
     <sf:fault xsi:type="sf:UnexpectedErrorFault" xmlns:sf="urn:fault.enterprise.soap.sforce.com">            <sf:exceptionCode>UNKNOWN_EXCEPTION</sf:exceptionCode> 
      <sf:exceptionMessage>Destination URL not reset. The URL returned from login must be set in the          SforceService</sf:exceptionMessage>
     </sf:fault>
    </detail>
   </soapenv:Fault>
  </soapenv:Body>
 </soapenv:Envelope>

I'm also still interested in the fix so PocketSoap will work via ASP, if you have it available.

Thanks.

SuperfellSuperfell
I need to see the HTTP headers, not the request body. You can capture the HTTP traffic by using a tool such as soapscope, proxyTrace or YATT, and by changing the URL to be http:// instead of https://

They've moved and renamed all the KB article links i had on the SSL issue, i'll try and track something down.
Rich.ax131Rich.ax131
I've tried all three of those tools, and I must not be configuring something properly because I'm not getting any trace results.
SuperfellSuperfell
I suspect that either you're send the request to the wrong URL, or not including the required SOAPAction HTTP header.
Rich.ax131Rich.ax131

1. URL = http://www.salesforce.com/services/Soap/c/4.0

2. I don't know what you mean by "required SOAPAction HTTP header."  I'm currently neither a SOAP nor a sForce API expert.

SuperfellSuperfell

SOAPAction is a mandatory HTTP header for SOAP requests over HTTP, see the SOAP 1.1 spec for more info.

Here's a working login call, complete with HTTP headers generated by .NET

POST http://www.salesforce.com/services/Soap/c/4.0 HTTP/1.1
User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; MS Web Services Client Protocol 1.1.4322.573)
Content-Type: text/xml; charset=utf-8
SOAPAction: ""
Content-Length: 373
Expect: 100-continue
Proxy-Connection: Keep-Alive
Host: www.salesforce.com

<?xml version="1.0" encoding="utf-8"?><soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"><soap:Body>

<login xmlns="urn:enterprise.soap.sforce.com">

<username>sforce@test</username>

<password>somepassword</password>

</login></soap:Body></soap:Envelope>

 

For your manually generated request, you should ensure that you're sending a SOAPAction header and that the Content-Type header is correct. I think you'll really need to get one of the HTTP tracing tools working to get this going. (you could also try tcpTrace www.pocketsoap.com/tcpTrace configure it to listen on port 8080 and forward to www.salesforce.com port 80, then change your test code to send its request to http://localhost:8080/services/Soap/c/4.0 )

Rich.ax131Rich.ax131

Here are the complete results of a trace I just ran using proxyTrace, directed to http://localhost:8080/services/Soap/c/4.0.

 

POST /services/Soap/c/4.0 HTTP/1.1
Man: http://localhost:8080/services/Soap/c/4.0 HTTP/1.1
Content-Type: text/xml
Accept-Language: en-us
Content-Length: 741
Accept: */*
User-Agent: Mozilla/4.0 (compatible; Win32; WinHttp.WinHttpRequest.5)
Host: localhost:8080
Connection: Keep-Alive

POST http://www.salesforce.com/services/Soap/c/4.0 HTTP/1.1 User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; MS Web Services Client Protocol 1.1.4322.573) Content-Type: text/xml; charset=utf-8 SOAPAction: " Content-Length: 373 Expect: 100-continue Proxy-Connection: Keep-Alive Host: www.salesforce.com <?xml version="1.0" encoding="utf-8"?>  <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">      <soap:Body>          <login xmlns="urn:enterprise.soap.sforce.com">              <username>[username]</username>              <password>[password]</password>          </login>      </soap:Body>  </soap:Envelope>

SuperfellSuperfell
Is that just a cut'n'paste error, or are those http headers really in the request body ? if so that'll be the problem.
Rich.ax131Rich.ax131

My bad.  Still learning.  The code I'm working with now is below.  I'm getting an error when it tries to set the SOAPAction header ("The parameter is incorrect.")  All the API documentation I've seen for sForce has this header being set to an empty string, but something is not working correctly.  I'm currently unable to put a trace on the request due to this.

'Build the request
    sEnv = sEnv & "<?xml version=""1.0"" encoding=""utf-8""?> "
    sEnv = sEnv & " <soap:Envelope xmlns:soap=""http://schemas.xmlsoap.org/soap/envelope/"" xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance"" xmlns:xsd=""http://www.w3.org/2001/XMLSchema""> "
    sEnv = sEnv & "     <soap:Body> "
    sEnv = sEnv & "         <login xmlns=""urn:enterprise.soap.sforce.com""> "
    sEnv = sEnv & "             <username>[username]</username> "
    sEnv = sEnv & "             <password>[password]</password> "
    sEnv = sEnv & "         </login> "
    sEnv = sEnv & "     </soap:Body> "
    sEnv = sEnv & " </soap:Envelope> "
       
    'Build the SOAP header
    Dim XMLHTTP As MSXML2.ServerXMLHTTP
    Set XMLHTTP = New MSXML2.ServerXMLHTTP
    XMLHTTP.Open "POST", sforceSoapServer, False   'False = do not respond immediately   
    XMLHTTP.setRequestHeader "User-Agent", "Mozilla/4.0 (compatible; MSIE 6.0; MS Web Services Client Protocol 1.1.4322.573)"
    XMLHTTP.setRequestHeader "Content-Type", "text/xml; charset=utf-8"
    XMLHTTP.setRequestHeader "SOAPAction", ""
    XMLHTTP.setRequestHeader "Content-Length", "373"
    XMLHTTP.setRequestHeader "Expect", "100-continue"
    XMLHTTP.setRequestHeader "Proxy-Connection", "Keep-Alive"
    XMLHTTP.setRequestHeader "Host", "www.salesforce.com"
       
    'Send the SOAP request
    XMLHTTP.Send (sEnv)
    strResponse = XMLHTTP.responseText
    Debug.Print strResponse
    Set XMLHTTP = Nothing

 

SuperfellSuperfell
SOAPACtion is kinda strange, it actually should be a pair of quotes, so (taking into account VB escaping of quotes)

XMLHTTP.setRequestHeader "SOAPAction", """"""

also, you don't want to be manually setting the User-Agent, Content-Length, Expect, Proxy-Connection, Host headers, those will be automatically handled for you by ServerXMLHTTP
Rich.ax131Rich.ax131
Thank you for your help.  I'm now logging in and querying using the SOAP approach.  I'm still interested in the PocketSoap technique, however - hand-coding the SOAP requests is a pain in the arse.  Were you able to find the MSDN article that details the fix so PocketSoap will work with classic ASP ("Unable to open CertificateStore")?