It doesn't matter if you are "post"ing or "GET"ing. There are few things you need to understand before making this happen.
- MS Access vba is single threadded, so parallel execution or threadded execution is not possible except using external DLLs or little available hacks.
- In order to achieve "Asynchronous HTTP Requests" or in other words, to tell the VBA not to wait for HTTP reply, you need a little hack on the callback class.
The process flow is as this:
- Create your HTTP request
- add all parameters and everything else
- assign a callback function
- Send/Open the MSXML2.XMLHTTP with [varAsyn]=True
- let the vba continue work on the other code, once http reply is received, the callback class will fire an event.
Important: The callback function will be a class and that class needs the hack.
[STEP1: Preparing the callback class]
Create new Class module in your VBA, call it HTTP_HANDLER_CLASS with following code:
Option Compare Database
Option Explicit
Dim m_xmlHttp As MSXML2.XMLHTTP
Public Sub Initialize(ByRef xmlHttpRequest As MSXML2.XMLHTTP)
Set m_xmlHttp = xmlHttpRequest
End Sub
Sub OnReadyStateChange()
If m_xmlHttp.ReadyState = 4 Then
If m_xmlHttp.status = 200 Then
Debug.Print m_xmlHttp.responseText
Else
'Error happened
End If
End If
End Sub
[STEP2: modifying/hacking the call-back class]
- Now export the class and save it in your desktop as HTTP_HANDLER_CLASS.cls
- Open the exported class in any text editing tool
- Add: "Attribute OnReadyStateChange.VB_UserMemId = 0" just below the sub "Sub OnReadyStateChange()"
- Go back to VBA and import the class (overwrite or delete existing)
This will make the OnReadyStateChange() as the default function which is what we wanted to have and so far, you've done the most important part:
[Step 3: sending requests this example uses SOAP action]
Assume a web-service "CallingServiceName" is available to you which takes two parameters iEmail, iPassword and returns a string if the login was success or not.
Module level variable:
Public xmlHttpRequest As MSXML2.XMLHTTP
Public Function HTTP_TEST()
On Error GoTo FailedState
If Not xmlHttpRequest Is Nothing Then Set xmlHttpRequest = Nothing
Dim MyXmlHttpHandler As HTTP_HANDLER_CLASS 'our hacked call back class
Set xmlHttpRequest = New MSXML2.XMLHTTP
Dim sURL As String
Dim sEnv As String
sURL = "http://mydomain.co.uk/mywebsite/myservices.asmx?op=CallingServiceName"
sEnv = "<?xml version=""1.0"" encoding=""utf-8""?>"
sEnv = sEnv & "<soap:Envelope xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance"" xmlns:xsd=""http://www.w3.org/2001/XMLSchema"" xmlns:soap=""http://schemas.xmlsoap.org/soap/envelope/"">"
sEnv = sEnv & " <soap:Body>"
sEnv = sEnv & " <CallingServiceName xmlns=""http://mydomain.co.uk/"">"
sEnv = sEnv & " <iEmail>username</iEmail>"
sEnv = sEnv & " <iPassword>mypassword</iPassword>"
sEnv = sEnv & " </CallingServiceName>"
sEnv = sEnv & " </soap:Body>"
sEnv = sEnv & "</soap:Envelope>"
' Now create an instance of our call-back class
Set MyXmlHttpHandler = New HTTP_HANDLER_CLASS
MyXmlHttpHandler.Initialize xmlHttpRequest
' Now attach the call-back class to our request, so whenever the request's state changes, callback classs default function will fire.
xmlHttpRequest.OnReadyStateChange = MyXmlHttpHandler
' seal the envelop and send it
xmlHttpRequest.Open "Post", sURL, True ' here set varAsyn=true
xmlHttpRequest.setRequestHeader "Host", "mydomain.co.uk"
xmlHttpRequest.setRequestHeader "Content-Type", "text/xml; charset=utf-8"
xmlHttpRequest.setRequestHeader "soapAction", "http://mydomain.co.uk/CallingServiceName"
xmlHttpRequest.Send sEnv
Debug.Print "Controller finished job" ' this is for you to realize vba will continue to work, the http result will be fired whenever the onstateChanges.
Exit Function
FailedState:
'MsgBox err.Number & ": " & err.description
End Function
[Result]
oh btw, Microsoft XML v3 is enough for this.
Above example uses SOAP version but you can use any method. Please let me know if this has helped.
Server.CreateObject("MSXML2.ServerXMLHTTP.6.0")
. Have added Screenshot of references in my question – HeterogenousCreateObject
instead ofServer.CreateObject
. – Resurrectionism