VBA TalentLMS API Post Request with multipart/form-data throwing error when passing Request Body with boundaries in as a string parameter - vba

I am creating a Module in MS Access to make API calls to different endpoints in the TalentLMS API. I am creating functions to minimize the code needed for each endpoint. So far all of my GET requests are working. I have a POST request to add a user account working as well. The problem that I am running into is that I have a POST request to delete a user account that works if I generate the multipart/form-data (Request Body) in the API Call function but does not work if I pass the mutlipart/form-data (Request Body) in as a parameter to the API Call function.
This is Working I generate the request body with boundaries within the API call function as a string.
Function talentAPICall_3(ByVal intUserid As Integer, ByVal strPermanent As String) As String
Dim request As New MSXML2.XMLHTTP30
Dim apiURL, boundary, postData, strRequest, strResponse As String
Dim contentLen As Long
apiURL = "https://<<myDomain>>.talentlms.com/api/v1/"
strRequest = apiURL & "deleteuser/"
boundary = "----------------------------" & Format(Now, "ddmmyyyyhhmmss")
postData = "--" & boundary & vbCrLf & _
"Content-Disposition: form-data; name=""user_id""" & vbCrLf & _
"Content-Type: text/plain; charset=UTF-8" & vbCrLf & vbCrLf & _
intUserid & vbCrLf & _
"--" & boundary & vbCrLf & _
"Content-Disposition: form-data; name=""permanent""" & vbCrLf & _
"Content-Type: text/plain; charset=UTF-8" & vbCrLf & vbCrLf & _
strPermanent & vbCrLf & _
"--" & boundary & "--"
contentLen = Len(postData)
With request
.Open "POST", (strRequest), False
.setRequestHeader "Authorization", "Basic <<MyAPIKey>>=="
.setRequestHeader "Host", "<<myDomain>>.talentlms.com"
.setRequestHeader "Content-Type", "multipart/form-data; boundary=" & boundary
.setRequestHeader "content-Length", contentLen
.send (postData)
While request.ReadyState <> 4
DoEvents
Wend
strResponse = .responseText
End With
Debug.Print "Server responded with status " & request.statusText & " - code: "; request.status
Debug.Print postData
talentAPICall_3 = strResponse
End Function
This is NOT Working Where I use a getBoundaries() function to pass the body request with boundaries as a string to the API call function.
Function DelUser(ByVal intUserid As Integer, ByVal strPermanent As String) As String
Dim postData, strResponse As String
Dim boundaries() As Variant
boundaries = Array("user_id", intUserid, "permanent", strPermanent)
postData = getBoundaries(boundaries)
strResponse = talentAPICall_4(postData)
DelUser = strResponse
End Function
Which calls the following.
Function getBoundaries(params() As Variant) As String
Dim boundary, boundaries As String
boundary = "----------------------------" & Format(Now, "ddmmyyyyhhmmss")
Dim i As Long
boundaries = ""
For i = LBound(params) To UBound(params)
boundaries = boundaries & "--" & boundary & vbCrLf & _
"Content-Disposition: form-data; name=""" & params(i) & """" & vbCrLf & _
"Content-Type: text/plain; charset=UTF-8" & vbCrLf & vbCrLf
i = i + 1
boundaries = boundaries & params(i) & vbCrLf
Next i
boundaries = boundaries & "--" & boundary & "--"
getBoundaries = boundaries
End Function
When the Request Body is generated with boundaries and returned as a string, it is then passed as a parameter to the next function.
Function talentAPICall_4(ByVal postData As String) As String
Dim request As New MSXML2.XMLHTTP30
Dim apiURL, boundary, strRequest, strResponse As String
Dim contentLen As Long
apiURL = "https://<<myDomain>>.talentlms.com/api/v1/"
strRequest = apiURL & "deleteuser/"
boundary = Left(postData, 44)
contentLen = Len(postData)
With request
.Open "POST", (strRequest), False
.setRequestHeader "Authorization", "Basic <<MyAPIKey>>=="
.setRequestHeader "Host", "<<myDomain>>.talentlms.com"
.setRequestHeader "Content-Type", "multipart/form-data; boundary=" & boundary
.setRequestHeader "content-Length", contentLen
.send (postData)
While request.ReadyState <> 4
DoEvents
Wend
strResponse = .responseText
End With
Debug.Print "Server responded with status " & request.statusText & " - code: "; request.status
Debug.Print postData
talentAPICall_4 = strResponse
End Function
Here are the results of both methods used:
Working:
call talentAPICall_3(3314, "yes")
Server responded with status OK - code: 200
Posted Data:
------------------------------15022023131313
Content-Disposition: form-data; name="user_id"
Content-Type: text/plain; charset=UTF-8
3314
------------------------------15022023131313
Content-Disposition: form-data; name="permanent"
Content-Type: text/plain; charset=UTF-8
yes
------------------------------15022023131313--
Not Working:
call delUser(3314, "yes")
Server responded with status Bad Request - code: 400
Posted Data:
------------------------------15022023131246
Content-Disposition: form-data; name="user_id"
Content-Type: text/plain; charset=UTF-8
3314
------------------------------15022023131246
Content-Disposition: form-data; name="permanent"
Content-Type: text/plain; charset=UTF-8
yes
------------------------------15022023131246--
As you can see, except for the variation of the time stamp used to create the boundary, the postData from Debug.Print for both functions is the same. The TalentLMS API states that the following for the 400 error code "A required parameter is missing or an invalid type (e.g. a string) was supplied instead of an integer." In both cases postData is a String and they have the same parameters.
Anyone see what I am missing?

In your "working" code the boundary header length is 42, and in the non-working code it's 44?
You need to remove the leading "--"...
boundary = Mid(postData, 3, 42)
Might be safer to pass the boundary in to getBoundaries rather than try to extract it from the output.

Related

VBA XMLHTTP POST Upload text/xml File to API Service

I need to send XML file to API service with use of Excel/VBA.
Instructions available in documentation state that the only required field is:
file: string($binary) - file to upload. The name can be specified in the filename parameter of the Content-Disposition header.
This is the equivalent of CURL based on documentation:
curl -X 'POST' \
'api_service_url' \
-H 'accept: */*' \
-H 'Authorization: Bearer XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX=' \
-H 'Content-Type: multipart/form-data' \
-F 'file=#VPRT9000004726.xml;type=text/xml'
I have searched the web and cannot find a working solution. I am wondering, if this is something possible to do with Excel VBA XMLHTTP library at all?
Available documentation of API service can be found on this link under the UPLOAD section:
https://testapi.valenciaportpcs.net/messaging/swagger/index.html
Any help or direction appreciated.
Code that is working for uploading the file, but having issues with UTF-8 special characters:
Option Explicit
Sub UploadFile()
Dim sFile As String
Dim sUrl As String
Dim sAccessToken As String
Dim sBoundary As String
Dim sResponse As String
sFile = "D:\VPRT9000004726.xml"
sUrl = "https://testapi.valenciaportpcs.net/messaging/messages/upload/default"
sBoundary = "---------------------------166096475834725259111917034354"
sAccessToken = "myaccesstoken"
sResponse = pvPostFile(sUrl, sFile, sBoundary, sAccessToken)
'Debug.Print sResponse
End Sub
Private Function pvPostFile(sUrl As String, sFileName As String, sBoundary As String, sAccessToken As String) As String
Dim xmlReq As MSXML2.ServerXMLHTTP60
Dim nFile As Integer
Dim baBuffer() As Byte
Dim sPostData As String
'--- read file
nFile = FreeFile
Open sFileName For Binary Access Read As nFile
If LOF(nFile) > 0 Then
ReDim baBuffer(0 To LOF(nFile) - 1) As Byte
Get nFile, , baBuffer
sPostData = StrConv(baBuffer, vbUnicode)
End If
Close nFile
'--- prepare body
sPostData = "--" & sBoundary & vbCrLf & _
"Content-Disposition: form-data; name=""file""; filename=""" & Mid$(sFileName, InStrRev(sFileName, "\") + 1) & """" & vbCrLf & _
"Content-Type: text/xml" & vbCrLf & vbCrLf & _
sPostData & vbCrLf & _
"--" & sBoundary & "--"
'Debug.Print sPostData
'--- post
Set xmlReq = New MSXML2.ServerXMLHTTP60
With xmlReq
.Open "POST", sUrl, False
.setRequestHeader "Authorization", "Bearer " & sAccessToken
.setRequestHeader "Content-Type", "multipart/form-data; boundary=" & sBoundary
.setRequestHeader "Accept-Charset", "UTF-8"
.send pvToByteArray(sPostData)
pvPostFile = .Status
End With
Set xmlReq = Nothing
End Function
Private Function pvToByteArray(sText As String) As Byte()
pvToByteArray = StrConv(sText, vbFromUnicode)
End Function

How to use ServerXMLHTTP60 and a client SSL certificate in Excel using VBA?

I cannot get it to work in VBA - Excel. I use the same header and XML-body in Postman - fine! Good response. I need to use a client certificate to identify myself, but I cannot get it done in VBA. The code needs to post some data (the XMLPostMessage) and then it receives some data from the server (a XML message as well).
The response I get from the server is a message in XML that has something to do with "Unidentified user". So, I do have communication, but it is not recognised as 'from a trusted party'. But using this certificate in Postman does give a good response.
== My VBA code: ==
Public Sub server()
Dim O As New ServerXMLHTTP60
Dim xmlDoc As New MSXML2.DOMDocument60
Dim XMLPostMessage As String
XMLPostMessage = "<WEB-UAS-AANVR>" & _
"<ALG-GEG>" & _
"<PROC-IDENT>3637</PROC-IDENT>" & _
"<PROC-FUNC>1</PROC-FUNC>" & _
"<INFO-GEBR>DITISEENTEST</INFO-GEBR>" & _
"</ALG-GEG>" & _
"<WEB-UAS-GEG>" & _
"<UAS-VRR-EXAMEN-GEG>" & _
"<UAS-VRR-EX-INST></UAS-VRR-EX-INST>" & _
"<UAS-VRR-EX-SRT>A2</UAS-VRR-EX-SRT>" & _
"<UAS-VRR-EX-DAT>20211210</UAS-VRR-EX-DAT>" & _
"<GEB-DAT-UAS-VRR>19840726</GEB-DAT-UAS-VRR>" & _
"<UAS-VRR-EX-REF>#12345</UAS-VRR-EX-REF>" & _
"</UAS-VRR-EXAMEN-GEG>" & _
"</WEB-UAS-GEG>" & _
"</WEB-UAS-AANVR>"
With O
.Open "POST", "https://<the serverpath goes here>", False
.setRequestHeader "Content-type", "application/xml"
.setRequestHeader "Content-type", "text/xml"
.setRequestHeader "Charset", "UTF-8"
.setOption 3, "<The Friendly Name of the certificate goes here>"
' .setOption 3, "CURRENT_USER\My\<The Friendly Name of the certificate goes here>"
.send XMLPostMessage
xmlDoc.LoadXML (O.responseXML.XML)
Debug.Print xmlDoc.XML
If Not .Status = 200 Then
MsgBox "UnAuthorized. Message: " & .Status & " - " & .statusText
Exit Sub
End If
End With
Set O = Nothing
End Sub

HTTP request (Stripe) VBA send DATA - getting error after days of working

I have created a project in Ms Access which creates customer accounts on Stripe. Credit card stuff is via elements in a secure manner.
The situation:
It is running on my test (home) environment fine.
It was running at my business for 2 days
Today I used it and am now getting:
The Connection with the server was terminated abnormally
Code:
reqBody = "description=" & desc & _
"&name=" & pName & _
"&phone=" & pPhone & _
"&address[line1=" & pAdd & _
"&address[city=" & pSuburb & _
"&address[country=AU" & _
"&address[postal_code=" & pPCode & _
"&address[state=Western Australia"
Set httpReq = CreateObject("MSXML2.ServerXMLHTTP")
httpReq.Open "POST", "https://api.stripe.com/v1/customers", False
httpReq.setRequestHeader "Authorization", "Bearer " & api_key
httpReq.send reqBody
strResponse = httpReq.responseText
Set parsed = JsonConverter.ParseJson(strResponse)
'Debug.Print strResponse
StripeCustID = parsed("id")
Now I read some other posts and tried using:
httpReq.setRequestHeader "Content-Type", "application/x-www-form-urlencoded"
and still no luck,
I ahve also tried:
Dim HTTPRequest As WinHttp.WinHttpRequest
Set HTTPRequest = New WinHttp.WinHttpRequest
With HTTPRequest
.Open "POST", "https://api.stripe.com/v1/customers", True
.setRequestHeader "Authorization", "Bearer " & api_key
.setRequestHeader "Content-Type", "application/x-www-form-urlencoded"
.Option(WinHttpRequestOption_SecureProtocols) = SecureProtocol_TLS1_2
'.Option(WinHttpRequestOption_EnableRedirects) = True
.send reqBody
If .waitForResponse(3) Then
strResponse = .responseText
Debug.Print .responseText
Else
MsgBox "Timed out after 3 seconds."
Exit Sub
End If
End With
But with this it is coming up as [SecureProtocol_TLS1_2] not defined (I have the reference to WinHttp)
My test environment is Windows 10, my work on is Windows 7, both are 64x.
But the fact remains, this was working for two days on the work computers and now giving me this error.

VBA HTTP Request POST returning empty string

I am working on a procedure, in MS-Access VBA, to POST an XML text string to a web service and process the XML text string that is returned from the service.
The issue I am having is that the responseText property is always empty when it should contain a XML text string. No errors are returned and the .status = "OK".
I have tried the WinHttp.WinHttpRequest, MSXML2.XMLHTTP, and MSXML2.ServerXMLHTTP objects and consistently have the same issue.
Here is a code example:
Public Function Send() As Boolean
Dim oXHR As MSXML2.XMLHTTP60
Dim sURL, sCred As String
Dim sRequest, sResult, sStatus, sHeader As String
Dim bRtn As Boolean
BuildReqXML
sRequest = Me.RequestXML_String
With orsValues
sURL = .Fields("WebServiceURL").Value
sCred = Base64Encode(Trim(.Fields("User").Value) & ":" & Trim(.Fields("Password").Value))
End With
Set oXHR = New MSXML2.XMLHTTP60
With oXHR
.Open "POST", sURL, False
.SetRequestHeader "Authorization", "Basic " & sCred & """"
.SetRequestHeader "User-Agent", "Mozilla/4.0"
.SetRequestHeader "Content-Type", "text/xml"
.Send sRequest
sStatus = .StatusText
sResult = .ResponseText
sHeader = .GetAllResponseHeaders
If sResult <> "" Then
If Contains(sResult, "<") Then ReadXML sResult, "Response"
Debug.Print sResult
Else
Debug.Print sHeader
Debug.Print sRequest
End If
End With
Set oXHR = Nothing
End Function
I have verified that the web service is working correctly by building a similar call in a HTML document, sending the XML string, and receiving the response XML string.
Can someone please help me fix my issue?
I found the problem, with help from Fiddler.
The line setting the authorization header
.SetRequestHeader "Authorization", "Basic " & sCred & """"
Was adding a (") to the header line. The corrected line is
.SetRequestHeader "Authorization", "Basic " & sCred
Thank you for your help

POST a Multi-Part Form to Bamboo API

I'm having a lot of difficulty submitting a multi-part form through a VB.NET console application to BambooHR API. I've posted my current code as well as a sample request from the documentation below, when I run this code I get (400) Bad Request. I know the code is messy, but I've just been trying to get it to work.
I was able to make a GET request work by using their sample code, but they didn't have any code to do this specific API call (upload an employee file).
ANY help would be appreciated.
Here is my code:
Sub Main()
upload(id, "https://api.bamboohr.com/api/gateway.php/company")
Console.WriteLine()
Console.WriteLine("Press ENTER to quit")
Console.ReadLine()
End Sub
Function upload(ByVal employeeId As Integer, ByVal baseUrl As String)
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12 Or SecurityProtocolType.Ssl3
Dim boundary = "----BambooHR-MultiPart-Mime-Boundary----"
Dim url = String.Format("{0}/v1/employees/{1}/files/", baseUrl, employeeId)
Dim request As HttpWebRequest = WebRequest.Create(url)
request.KeepAlive = True
request.Method = "POST"
request.ContentType = "multipart/form-data; boundary=" + boundary
'Authorization is just the api key and a random string, in this case is x
'
Dim authInfo As String = api_key + ":" + "x"
authInfo = Convert.ToBase64String(Encoding.Default.GetBytes(authInfo))
request.Headers("Authorization") = "Basic " + authInfo
Dim memStream As New MemoryStream()
WriteMPF(memStream)
request.ContentLength = memStream.Length
Using requestStream = request.GetRequestStream()
memStream.Position = 0
Dim tempBuffer As Byte() = New Byte(memStream.Length - 1) {}
memStream.Read(tempBuffer, 0, tempBuffer.Length)
memStream.Close()
requestStream.Write(tempBuffer, 0, tempBuffer.Length)
End Using
Dim webresponse As HttpWebResponse = request.GetResponse()
Return webresponse
End Function
Private Sub WriteMPF(s As Stream)
WriteToStream(s, "POST /api/gateway.php/company/v1/employees/id/files/ HTTP/1.0")
WriteToStream(s, vbCr & vbLf)
WriteToStream(s, "Host: api.bamboohr.com")
WriteToStream(s, vbCr & vbLf)
WriteToStream(s, "Content-Type: multipart/form-data; boundary=----BambooHR-MultiPart-Mime-Boundary----")
WriteToStream(s, vbCr & vbLf)
WriteToStream(s, "Content-Length: 520")
WriteToStream(s, vbCr & vbLf)
WriteToStream(s, vbCr & vbLf)
WriteToStream(s, "------BambooHR-MultiPart-Mime-Boundary----")
WriteToStream(s, vbCr & vbLf)
WriteToStream(s, "Content-Disposition: form-data; name=""category""")
WriteToStream(s, vbCr & vbLf)
WriteToStream(s, vbCr & vbLf)
WriteToStream(s, "14")
WriteToStream(s, vbCr & vbLf)
WriteToStream(s, "------BambooHR-MultiPart-Mime-Boundary----")
WriteToStream(s, vbCr & vbLf)
WriteToStream(s, "Content-Disposition: form-data; name=""fileName""")
WriteToStream(s, vbCr & vbLf)
WriteToStream(s, vbCr & vbLf)
WriteToStream(s, "test.txt")
WriteToStream(s, vbCr & vbLf)
WriteToStream(s, "------BambooHR-MultiPart-Mime-Boundary----")
WriteToStream(s, vbCr & vbLf)
WriteToStream(s, "Content-Disposition: form-data; name=""share""")
WriteToStream(s, vbCr & vbLf)
WriteToStream(s, vbCr & vbLf)
WriteToStream(s, "no")
WriteToStream(s, vbCr & vbLf)
WriteToStream(s, "------BambooHR-MultiPart-Mime-Boundary----")
WriteToStream(s, vbCr & vbLf)
WriteToStream(s, "Content-Disposition: form-data; name=""file""; filename = ""test.txt""")
WriteToStream(s, vbCr & vbLf)
WriteToStream(s, "Content-Type: text/plain")
WriteToStream(s, vbCr & vbLf)
WriteToStream(s, vbCr & vbLf)
WriteToStream(s, "this is a test!")
WriteToStream(s, vbCr & vbLf)
WriteToStream(s, vbCr & vbLf)
WriteToStream(s, "------BambooHR-MultiPart-Mime-Boundary------")
WriteToStream(s, vbCr & vbLf)
End Sub
Private Sub WriteToStream(s As Stream, txt As String)
Dim bytes As Byte() = Encoding.UTF8.GetBytes(txt)
s.Write(bytes, 0, bytes.Length)
End Sub
Here is a sample request from the documentation: (link: https://www.bamboohr.com/api/documentation/employees.php scroll down to "Upload an Employee File")
POST /api/gateway.php/sample/v1/employees/1/files/ HTTP/1.0
Host: api.bamboohr.com
Content-Type: multipart/form-data; boundary=----BambooHR-MultiPart-Mime-Boundary----
Content-Length: 520
------BambooHR-MultiPart-Mime-Boundary----
Content-Disposition: form-data; name="category"
112
------BambooHR-MultiPart-Mime-Boundary----
Content-Disposition: form-data; name="fileName"
readme.txt
------BambooHR-MultiPart-Mime-Boundary----
Content-Disposition: form-data; name="share"
yes
------BambooHR-MultiPart-Mime-Boundary----
Content-Disposition: form-data; name="file"; filename="readme.txt"
Content-Type: text/plain
This is a sample text file.
------BambooHR-MultiPart-Mime-Boundary------
Used the php example on their GitHub and copied it over to VB.NET. It's a little messy, but it works. Here is the relevant code:
Public Function sendRequestMPF(ByVal req As BambooHTTPRequest, ByVal fileLocation As String) As BambooHTTPResponse
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12 Or SecurityProtocolType.Ssl3
Dim request As HttpWebRequest = WebRequest.Create(req.url)
request.Method = req.method
request.Host = "api.bamboohr.com"
Dim boundary = "----BambooHR-MultiPart-Mime-Boundary----"
Try
request.ContentType = "multipart/form-data; boundary=" + boundary
request.ContentLength = req.contents.Length
Catch ex As Exception
End Try
Dim iCount As Integer = req.headers.Count
Dim key As String
Dim keyvalue As String
Dim i As Integer
For i = 0 To iCount - 1
key = req.headers.Keys(i)
keyvalue = req.headers(i)
request.Headers.Add(key, keyvalue)
Next
Dim enc As System.Text.UTF8Encoding = New System.Text.UTF8Encoding()
Dim bytes() As Byte = {}
Dim pdfBytes() As Byte = {}
Dim lBytes() As Byte = {}
Dim fBytes() As Byte = {}
Dim s As New MemoryStream()
If (req.contents.Length > 0) Then
bytes = enc.GetBytes(req.contents)
s.Write(bytes, 0, bytes.Length)
pdfBytes = File.ReadAllBytes(fileLocation)
s.Write(pdfBytes, 0, pdfBytes.Length)
Dim postHeader = vbCrLf + vbCrLf + "--" + boundary + "--" + vbCrLf
Dim postHeaderBytes() As Byte = enc.GetBytes(postHeader)
lBytes = enc.GetBytes(postHeader)
s.Write(postHeaderBytes, 0, postHeaderBytes.Length)
fBytes = s.ToArray()
request.ContentLength = fBytes.Length
End If
request.AllowAutoRedirect = False
If Not basicAuthUsername.Equals("") Then
Dim authInfo As String = basicAuthUsername + ":" + basicAuthPassword
authInfo = Convert.ToBase64String(Encoding.Default.GetBytes(authInfo))
request.Headers("Authorization") = "Basic " + authInfo
End If
If req.contents.Length > 0 Then
Dim outBound As Stream = request.GetRequestStream()
outBound.Write(fBytes, 0, fBytes.Length)
End If
Dim resp As BambooHTTPResponse
Try
Dim webresponse As HttpWebResponse = request.GetResponse()
resp = New BambooHTTPResponse(webresponse)
resp.responseCode = webresponse.StatusCode
resp.headers = webresponse.Headers
Catch e As WebException
Console.WriteLine(e.Message)
If (e.Status = WebExceptionStatus.ProtocolError) Then
resp = New BambooHTTPResponse(DirectCast(e.Response, HttpWebResponse).StatusCode)
Else
resp = New BambooHTTPResponse(0)
End If
End Try
Return resp
End Function
Public Function buildMultiPart(ByVal params As NameValueCollection, ByVal boundary As String, ByVal contentType As String, ByVal name As String, ByVal fileName As String)
Dim data = ""
For Each key In params.AllKeys
data += "--" + boundary + vbCrLf
data += "Content-Disposition: form-data; name=""" + key + """"
data += vbCrLf + vbCrLf
data += params(key) + vbCrLf
Next
data += "--" + boundary + vbCr + vbLf
data += "Content-Disposition: form-data; name=""" + name + """;" + " filename=""" + fileName + """" + vbCrLf
data += "Content-Type: " + contentType + vbCrLf
data += vbCrLf
'data += fileData + vbCrLf + vbCrLf
'data += "--" + boundary + "--" + vbCrLf
Return data
End Function
Public Function uploadEmployeeFile(ByVal employeeId As Integer, ByVal fileName As String, ByVal fileLocation As String)
Dim request As New BambooHTTPRequest()
request.url = String.Format("{0}/v1/employees/{1}/files/", Me.baseUrl, employeeId)
request.method = "POST"
Dim boundary = "----BambooHR-MultiPart-Mime-Boundary----"
Dim params = New NameValueCollection
params.Add("category", "13")
params.Add("fileName", fileName)
params.Add("share", "no")
request.contents = buildMultiPart(params, boundary, "application/pdf", "file", fileName)
Return http.sendRequestMPF(request, fileLocation)
End Function
The rest of the code needed can be found on their GitHub https://github.com/BambooHR
I suspect that at the very least your Content-Length: 520 will be wrong. That content length was only applicable to their example.
Anyway, I haven't written VB.Net in a long, long time, but from a quick test a modified version of this code works against one of my REST services, so it should work in your case, with perhaps some minor tweaking.
My test console project used .Net 4.6.1, but will likely run with some of the earlier .Net Frameworks.
Imports System.IO
Imports System.Net.Http
Module Module1
Sub Main()
Call UploadFileToWebsite(14, "no", "D:\Temp\file.pdf")
Console.WriteLine("Please wait for a response from the server and then press a key to continue.")
Console.ReadKey()
End Sub
Public Sub UploadFileToWebsite(category As Integer, share As String, file As String)
Dim message = New HttpRequestMessage()
Dim content = New MultipartFormDataContent()
content.Add(New StringContent(category.ToString()), "category")
content.Add(New StringContent(share), "share")
Dim filestream = New FileStream(file, FileMode.Open)
Dim fileName = System.IO.Path.GetFileName(file)
content.Add(New StreamContent(filestream), "file", fileName)
message.Method = HttpMethod.Post
message.Content = content
message.RequestUri = New Uri("https://api.bamboohr.com/api/gateway.php/company")
Dim client = New HttpClient()
client.SendAsync(message).ContinueWith(
Sub(task)
'do something with response
If task.Result.IsSuccessStatusCode Then
Console.WriteLine("Uploaded OK.")
Else
Console.WriteLine("Upload Failed.")
End If
End Sub)
End Sub
End Module
On an unrelated note, you can also use vbCrLf instead of vbCr & vbLf.