1

I'm having trouble uploading some form data to an API endpoint in vb.net.

Example From Vendor:

curl -X POST -H 'Authorization: Token token=sfg999666t673t7t82'
  -H 'Content-Type: multipart/form-data' -H 'content-type: multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW' 
  -F file=@/Users/user1/Downloads/download.jpeg -F file_name=nameForFile 
  -F is_shared=true -F targetable_id=1 -F targetable_type=Lead -X POST "https://domain.freshsales.io/api/documents"

VB.NET CODE

Shameless pulled from (Upload files with HTTPWebrequest (multipart/form-data))

        Private Sub HttpUploadFile(ByVal filePath As String, ByVal fileParameterName As String, ByVal contentType As String, ByVal otherParameters As Specialized.NameValueCollection)
        Dim boundary As String = "---------------------------" & DateTime.Now.Ticks.ToString("x")
        Dim newLine As String = System.Environment.NewLine
        Dim boundaryBytes As Byte() = Text.Encoding.ASCII.GetBytes(newLine & "--" & boundary & newLine)
        Dim request As Net.HttpWebRequest = Net.WebRequest.Create("https://domain.freshsales.io/api/documents")
        request.ContentType = "multipart/form-data; boundary=" & boundary
        request.Method = "POST"
        request.KeepAlive = True

        Using requestStream As IO.Stream = request.GetRequestStream()
            Dim formDataTemplate As String = "Content-Disposition: form-data; name=""{0}""{1}{1}{2}"
            For Each key As String In otherParameters.Keys
                requestStream.Write(boundaryBytes, 0, boundaryBytes.Length)
                Dim formItem As String = String.Format(formDataTemplate, key, newLine, otherParameters(key))
                Dim formItemBytes As Byte() = Text.Encoding.UTF8.GetBytes(formItem)
                requestStream.Write(formItemBytes, 0, formItemBytes.Length)
            Next key
            requestStream.Write(boundaryBytes, 0, boundaryBytes.Length)
            Dim headerTemplate As String = "Content-Disposition: form-data; name=""{0}""; filename=""{1}""{2}Content-Type: {3}{2}{2}"
            Dim header As String = String.Format(headerTemplate, fileParameterName, filePath, newLine, contentType)

            Dim headerBytes As Byte() = Text.Encoding.UTF8.GetBytes(header)
            requestStream.Write(headerBytes, 0, headerBytes.Length)
            Using fileStream As New IO.FileStream(filePath, IO.FileMode.Open, IO.FileAccess.Read)
                Dim buffer(4096) As Byte
                Dim bytesRead As Int32 = fileStream.Read(buffer, 0, buffer.Length)
                Do While (bytesRead > 0)
                    requestStream.Write(buffer, 0, bytesRead)
                    bytesRead = fileStream.Read(buffer, 0, buffer.Length)
                Loop
            End Using
            Dim trailer As Byte() = Text.Encoding.ASCII.GetBytes(newLine & "--" + boundary + "--" & newLine)
            requestStream.Write(trailer, 0, trailer.Length)
        End Using

        Dim response As Net.WebResponse = Nothing
        Try
            response = request.GetResponse()
            Using responseStream As IO.Stream = response.GetResponseStream()
                Using responseReader As New IO.StreamReader(responseStream)
                    Dim responseText = responseReader.ReadToEnd()
                    Diagnostics.Debug.Write(responseText)
                End Using
            End Using
        Catch exception As Net.WebException
            response = exception.Response
            If (response IsNot Nothing) Then
                Using reader As New IO.StreamReader(response.GetResponseStream())
                    Dim responseText = reader.ReadToEnd()
                    Diagnostics.Debug.Write(responseText)
                End Using
                response.Close()
            End If
        Finally
            request = Nothing
        End Try
    End Sub

Calling The Function

Here is my call:

Dim headers As NameValueCollection = New NameValueCollection()
headers.Add("Token", "token=youguessedit;")
Dim nvc As NameValueCollection = New NameValueCollection()
nvc.Add("is_shared", true)
nvc.Add("targetable_id", 1)
nvc.Add("targetable_type", "Lead")

HttpUploadFile("c:\test\file.pdf", "file", "application/pdf", nvc, headers);

I think part of my issue is in the way the headers are attached here:

  Dim headerTemplate As String = "Content-Disposition: form-data; name=""{0}""; filename=""{1}""{2}Content-Type: {3}{2}{2}"

In that the API endpoint is expecting file= and file_name= how can I correct the headers?

Can anyone point out where else I have gone wrong? Is there an easier way of doing this?

DDulla
  • 659
  • 9
  • 20

1 Answers1

2

Here's a simple Console app example using HttpClient with a MultipartFormDataContent which takes care of all the headers and streaming the file, this example also works as-is thanks to Postman-Echo, if there's a requirement for additional headers (only Token is shown here) be sure to add them to the HttpClient.DefaultRequestHeaders

Dim response As New HttpResponseMessage
Dim path As String = "C:\\Temp\\upload.pdf"
Dim uri As New Uri("https://postman-echo.com/post")

Using form As New MultipartFormDataContent,
    fs As New FileStream(path, FileMode.Open),
    content As New StreamContent(fs),
    httpClient As New HttpClient
    form.Add(content)
    httpClient.DefaultRequestHeaders.Add("Token", "Super Secret")
    response = httpClient.PostAsync(uri, form).GetAwaiter.GetResult()
    Console.WriteLine("Is Successfull: " & response.IsSuccessStatusCode)
End Using

EDIT: Cleaned up nested Using statements

kshkarin
  • 574
  • 4
  • 9