I have been struggling with this issue for almost a month now, and I read everything I could find online, with no solution. Here’s my problem: I’m implementing a client for a RESTful API service that has to send an XML file through a POST call, in vb.net. I am able to make it working when it comes to GET some data, in xml format, but when it comes to send this Xml file, I always get the “400 bad request error”.
I already figured it out that it has to be a matter of the key that has to be passed to the server (that apparently accepts only file uploading for POST, I cannot send it as a string).
Basically this call works with cURL, but I am struggling for implementing my own call in vb.net, passing the right value.
Working cURL call: (that successfully transmits the XML)
c:>curl -u username:password -F "file=@filename.xml" -X POST http://hostname.com/URI?parameters
Not working Vb.net code: (that gives me 400 Bad Request)
Dim ss As String = "" 'server says...
Dim S As String = txb_username.Text & ":" & txb_password.Text
Dim EncodedString As String = System.Convert.ToBase64String(System.Text.Encoding.UTF8.GetBytes(S))
Dim req As HttpWebRequest = Nothing
Dim res As HttpWebResponse = Nothing
Try
Dim xmlDoc As System.Xml.XmlDocument = New System.Xml.XmlDocument
xmlDoc.XmlResolver = Nothing
xmlDoc.Load("c:\path\file4.xml")
Dim sXML As String = "file" & xmlDoc.InnerXml '<- This is where I try to put the "KEY"
Dim url As String = "http:/host.com+URI"
req = CType(WebRequest.Create(url), Net.HttpWebRequest) 'or Directcast ...
req.Method = "POST"
req.Headers.Add("Authorization: Basic " & EncodedString)
req.ContentType = "multipart/form-data"
req.ContentLength = sXML.Length
req.Accept = "*/*"
System.Windows.Forms.Application.DoEvents()
Dim sw As System.IO.StreamWriter = New System.IO.StreamWriter(req.GetRequestStream)
StatusUpdate(sXML)
sw.Write(sXML)
sw.Close()
ss = "server says: "
res = CType(req.GetResponse, HttpWebResponse)
StatusUpdate(req.ToString)
Catch ex As Exception
StatusUpdate(ss & ex.Message)
Finally
End Try
Is it because I am trying to send it as a string? (but how else can I send it as a file?)
For this I made another procedure that sends the bytes of data, but this one also gives me “400” because (I assume) I did not put the “file” key.
Dim requestStream As Stream = Nothing
Dim fileStream As FileStream = Nothing
Dim uploadResponse As Net.HttpWebResponse = Nothing
Try
Dim uploadRequest As Net.HttpWebRequest = CType(Net.HttpWebRequest.Create(URI.Text & Uri_part2.text), Net.HttpWebRequest)
uploadRequest.Method = Net.WebRequestMethods.Http.Post
uploadRequest.ContentType = "text/xml; charset=utf-8"
uploadRequest.Credentials = New NetworkCredential("user", "pass")
uploadRequest.KeepAlive = True
uploadRequest.UserAgent = "User-Agent: Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.9.0.10) Gecko/2009042316 Firefox/3.0.10"
uploadRequest.Accept = ("text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8")
uploadRequest.Headers.Add("Accept-Language: en-us,en;q=0.5")
uploadRequest.Headers.Add("Accept-Encoding: gzip,deflate")
uploadRequest.Headers.Add("Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7")
uploadRequest.Headers.Add("Content-Disposition: form-data; name=""file"";")
uploadRequest.ContentType = "application/xml; charset=utf-8"
requestStream = uploadRequest.GetRequestStream()
fileStream = File.Open("C:\example.xml", FileMode.Open)
Dim a As Integer
Dim buffer(1024) As Byte
Dim bytesRead As Integer
While True
a = a + 1
bytesRead = fileStream.Read(buffer, 0, buffer.Length)
StatusUpdate(buffer(a))
If bytesRead = 0 Then
Exit While
End If
requestStream.Write(buffer, 0, bytesRead)
End While
requestStream.Close()
uploadResponse = uploadRequest.GetResponse()
Dim responseReader As StreamReader = New StreamReader(uploadRequest.GetResponse.GetResponseStream())
Dim x As String = responseReader.ReadToEnd()
responseReader.Close()
StatusUpdate(x)
Catch ex As UriFormatException
StatusUpdate("UriFormatException: " & ex.Message)
Catch ex As IOException
StatusUpdate("IOException: " & ex.Message)
Catch ex As Net.WebException
StatusUpdate("Net.WebException: " & ex.Message)
Finally
If uploadResponse IsNot Nothing Then
uploadResponse.Close()
End If
If fileStream IsNot Nothing Then
fileStream.Close()
End If
If requestStream IsNot Nothing Then
requestStream.Close()
End If
End Try
In any case, I tried also other 2 clients (POSTMAN and REST Console, 2 extensions for Google Chrome) and I can get it working only if I add the value “file” into the “key” field. I have to insert the specific 4 chars “file” to get it working. So, the question is: how do I add the same value in a Vb.net call? How can I translate the code of the cURL call in working Vb.net code? Thank you very much for your time and help!!!
find image of the thing I want to add here,
P.S. I cannot use PUT, I have to use POST (server restriction)
I also add HTML code that is working for my purpose, with the server from my pc (see the “file” key, again)
<html>
<body>
<form enctype="multipart/form-data" action="http://URI" method="POST">
<table border=0>
<tr>
<td align="right">File </td>
<td><input type="FILE" name="file"></td>
</tr>
<tr>
<td> </td>
<td><input type="submit"></td>
</tr>
</table>
</form>
</body>
</html>
Also I paste a script in PERL that is working, too, with the server, from my computer.
#!perl
use strict;
use LWP; # Loads all important LWP classes
my $client_id = 1234;
my $filename = "new_file.xml";
### Prepare to make a request
my $browser = LWP::UserAgent->new;
my $url = "http://uri.com?&xx=$client_id";
my @post_pairs = (
#'client_id_in' => $client_id,
'file' => [$filename],
);
my @ns_headers = (
'User-Agent' => 'Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.9.0.10) Gecko/2009042316 Firefox/3.0.10',
'Accept' => 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
'Accept-Language' => 'en-us,en;q=0.5',
'Accept-Encoding' => 'gzip,deflate',
'Accept-Charset' => 'ISO-8859-1,utf-8;q=0.7,*;q=0.7',
'Authorization' => 'Basic base64EncodedCredentialsHere',
'Content_Type' => 'form-data',
);
### Make a request
my $response = $browser->post($url, \@post_pairs, @ns_headers);
die "Can't get $url -- ", $response->status_line
unless $response->is_success;
### Display the response
print STDOUT $response->content;
I think your problem is that you don’t really know how the request should look like, please use fiddler to take a look to the request sent by cURL and try to implement the same using vb.net. In my opinion your secons piece of code (with the buffer, not with the xml serializers) should work… but only if this structure can be understood at the server side.