400 Bad Request on HttpWebRequest in VB.Net with Twitter Developer API - vb.net

I just started using the Twitter dev API and I got some issues with it.
Without going into any details about my code, I know the problem lies within the HttpWebRequest:
...
'create WebRequest
Dim request As WebRequest = HttpWebRequest.Create(urlFinal)
request.PreAuthenticate = True
request.Method = URL_METHOD
request.Headers.add("authorization", authString)
request.ContentType = "application/json"
'execute it and open reader
Dim response As WebResponse = request.GetResponse()
Dim reader As StreamReader = New StreamReader(response.GetResponseStream())
'parse WebResponse into String to use it...
Dim rawresp As String
rawresp = reader.ReadToEnd()
...
URL_METHOD is "GET" and I'll explain my authString below. The URL is variable but could be something like https://api.twitter.com/1.1/search/tweets.json?q=abc.
Whenever this is executed, I receive a "400 - Bad Request" error on the line
Dim response As WebResponse = request.GetResponse()
I did some research on it and found that it either is a problem with the URL or with the authentication.
The URL is fine, I can check this quite easily with breakpoints in debug mode. When I open the URL in a browser I receive the error:
{"errors":[{"code":215,"message":"Bad Authentication data."}]}
So it must be the authentication.
Here is how my authString looks like:
Dim authString As String = "OAuth"
authString += " oauth_consumer_key=""" & OAUTH_KEY & """"
authString += ", oauth_nonce=""" & OAUTH_NONCE & """"
authString += ", oauth_signature=""" & OAUTH_SIGN & """"
authString += ", oauth_signature_method=""" & OAUTH_SIGN_METHOD & """"
authString += ", oauth_timestamp=""" & OAUTH_TIMESTAMP & """"
authString += ", oauth_token=""" & OAUTH_TOKEN & """"
authString += ", oauth_version=""" & OAUTH_VERSION & """"
I also checked this during runtime and I get this:
OAuth oauth_consumer_key="xxx", oauth_nonce="xxx", oauth_signature="xxx", oauth_signature_method="HMAC-SHA1", oauth_timestamp="1571760986", oauth_token="xxx", oauth_version="1.0"
OAUTH_TOKEN (Access token) and OAUTH_KEY (API key) come from here:
OAUTH_NONCE (Nonce) and OAUTH_TIMESTAMP (timestamp) are calculated like this:
OAUTH_NONCE = Convert.ToBase64String(New ASCIIEncoding().GetBytes(DateTime.Now.Ticks.ToString()))
OAUTH_TIMESTAMP = Convert.ToInt64((DateTime.UtcNow - New DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc)).TotalSeconds).ToString()
OAUTH_SIGN (signature) like this:
Dim baseFormat = "oauth_consumer_key={0}&oauth_nonce={1}&oauth_signature_method={2}&oauth_timestamp={3}&oauth_token={4}&oauth_version={5}&status={6}"
Dim baseString = String.Format(baseFormat, OAUTH_KEY, OAUTH_NONCE, OAUTH_SIGN_METHOD, OAUTH_TIMESTAMP, OAUTH_TOKEN, OAUTH_VERSION, Uri.EscapeDataString(URL_METHOD))
baseString = String.Concat(URL_METHOD & "&", Uri.EscapeDataString(URL_BASE), "&", Uri.EscapeDataString(baseString))
Dim compositeKey = String.Concat(Uri.EscapeDataString(OAUTH_KEY_SECRET), "&", Uri.EscapeDataString(OAUTH_TOKEN_SECRET))
Using hasher As New HMACSHA1(ASCIIEncoding.ASCII.GetBytes(compositeKey))
OAUTH_SIGN = Convert.ToBase64String(hasher.ComputeHash(ASCIIEncoding.ASCII.GetBytes(baseString)))
End Using
Signature method and OAuth version are hard coded (see above, you might need to scroll to the right).
Can anyone please explain to me where the error is?
I appreciate every answer and am keen to try it all out, I just don't have any other idea anymore.
Thank you very much in advance.
Ben

Related

Can we call JSON POST API from VB.NET Windows App?

Here I am always getting "The remote server returned an error: (500) Internal Server Error.". Even the API is correct and working nicely through POSTMAN and in other languages also. Please guide me so solve this issue. I am attaching the function which is calling the API directly.
Private Function SendRequest() As String
Dim response As String
Dim request As WebRequest
Dim encoding As New System.Text.ASCIIEncoding
Dim uri = ""
Dim Tran = "15"
Dim Amount As Integer = 1000
Dim ReferenceID = "015bfa15-15ec-4dc7-903c-053ffacb6688"
Dim POS = "57290070"
Dim Store = "RESTSIM00000001"
Dim Chain = "J#P-Reg"
Dim JSONString = "{""tran"":""" & Tran & """,""amount"":""" & Amount & """,""reference"":""" & ReferenceID & """,""pos"":""" & POS & """,""store"":""" & Store & """,""chain"":""" & Chain & """}"
Dim jsonDataBytes() As Byte = encoding.GetBytes(JsonConvert.SerializeObject(JSONString))
request = WebRequest.Create(uri)
request.ContentLength = jsonDataBytes.Length
request.ContentType = "application/json"
request.Method = "POST"
Using requestStream = request.GetRequestStream
requestStream.Write(jsonDataBytes, 0, jsonDataBytes.Length)
requestStream.Close()
Using responseStream = request.GetResponse.GetResponseStream
Using reader As New StreamReader(responseStream)
response = reader.ReadToEnd()
End Using
End Using
End Using
Return response
End Function

Prestashop - Unable to upload a new image product with the prestashop 1.6 webservice

I'm trying to upload a new image for a product with the prestashop webservice through a vb .net application, but I get the following error message:
"Unable to save this image".
The URL used to upload the image is this: http://localhost/prestashop/api/images/products/1
And the source code of the function that make the request is this:
Public Sub executeAddImage(ByVal resource As String, ByVal id As String, ByVal imageToAdd As Image)
Dim response As String = Nothing
Try
Dim ms As New MemoryStream()
imageToAdd.Save(ms, System.Drawing.Imaging.ImageFormat.Jpeg)
Dim byteArray As Byte() = ms.ToArray()
Dim requestUrl As String = Me.WebServiceURL & "/" & resource & "/" & id
MsgBox(requestUrl)
Dim webRequest As HttpWebRequest = DirectCast(System.Net.WebRequest.Create(requestUrl), HttpWebRequest)
webRequest.Method = WebServicePrestashop.CRUDMethod.Create
'webRequest.ContentType = "image/jpeg"
webRequest.ContentType = "application/x-www-form-urlencoded"
webRequest.Credentials = New NetworkCredential(Me.LoginName, WebServicePrestashop._password)
webRequest.ContentLength = byteArray.Length
MsgBox(byteArray.Length)
' Get the request stream
Using dataStream As Stream = webRequest.GetRequestStream()
dataStream.Write(byteArray, 0, byteArray.Length)
End Using
' Get the response
Using webResponse As HttpWebResponse = DirectCast(webRequest.GetResponse(), HttpWebResponse)
If webResponse.StatusCode = HttpStatusCode.OK Then
Using reader As New StreamReader(webResponse.GetResponseStream(), Encoding.UTF8)
Dim imageNew As Image = Image.FromStream(webResponse.GetResponseStream())
End Using
End If
End Using
Catch ex As WebException
MsgBox(ex.Message.ToString())
Dim reader As New StreamReader(ex.Response.GetResponseStream)
MsgBox(reader.ReadToEnd)
End Try
End Sub
I'm using the HTTP POST method, and the POST content is the bynary content of the new image.
How can I fix it?.
Here the solution.
I think the key is that I must write the body of the webrequest programatically adding to the stream of the webrequest the boundary (in binary array format), the Content-Type chain (in binary array format) and the content of the image to upload (in binary array format).
Public Sub executeAddImage(ByVal resource As String, ByVal id As String, ByVal imageToAdd As Byte())
Dim response As String = Nothing
Try
Dim requestUrl As String = "urlShop" & "/api/" & resource & "/" & id
MsgBox(requestUrl)
Dim webRequest As HttpWebRequest = DirectCast(System.Net.WebRequest.Create(requestUrl), HttpWebRequest)
webRequest.KeepAlive = True
webRequest.Credentials = New NetworkCredential(Me.LoginName, WebServicePrestashop._password)
webRequest.ContentLength = imageToAdd.Length
webRequest.Method = "POST"
webRequest.ContentType = "image/jpeg"
Dim boundary As String = "----" & DateTime.Now.Ticks.ToString("x", CultureInfo.InvariantCulture)
webRequest.ContentType = "multipart/form-data; boundary=" & boundary
Dim beginPostData = "--" & boundary & vbCrLf & "Content-Disposition: form-data; name=""image""; filename=""torrente.jpg""" & _
vbCrLf & "Content-Type: image/jpeg" & vbCrLf & vbCrLf
Dim boundaryBytes = System.Text.Encoding.ASCII.GetBytes(vbCrLf & "--" & boundary & "--" & vbCrLf)
Dim beginPostDataBytes = System.Text.Encoding.ASCII.GetBytes(beginPostData)
webRequest.ContentLength = beginPostData.Length + imageToAdd.Length + boundaryBytes.Length
' Get the request stream
Using dataStream As Stream = webRequest.GetRequestStream()
dataStream.Write(beginPostDataBytes, 0, beginPostDataBytes.Length)
dataStream.Write(imageToAdd, 0, imageToAdd.Length)
dataStream.Write(boundaryBytes, 0, boundaryBytes.Length)
End Using
' Get the response
Using webResponse As HttpWebResponse = DirectCast(webRequest.GetResponse(), HttpWebResponse)
If webResponse.StatusCode = HttpStatusCode.OK Then
Using reader As New StreamReader(webResponse.GetResponseStream())
response = reader.ReadToEnd()
MsgBox(response)
End Using
End If
End Using
Catch ex As WebException
MsgBox(ex.Message.ToString())
Dim reader As New StreamReader(ex.Response.GetResponseStream)
MsgBox(reader.ReadToEnd)
End Try
End Sub

VB.NET - How To Get Raw Image Data To String

How would I get raw image data to a String in VB.NET similar to the following:
J©õݨe‚Lnž¿Ëã/ǧúÐ5ý¼C÷Cý>ß’t;fm—=Äw:�/E±ËÙÏ$á#%Pc>× Šgw.²Ab“:ÅÓù:ϯÌh6à€Z§Ó‚g£®hÚD6¨Ø^Ú2ô`ä¨L�YÆÄÅCX#I“ÈÌãj¦L˜•’|¥�Eb¡ëQ–¤Ú, 3\UzL öÔoj4�•±’u«c¼#„oÕ`îF>·o—ŠûÅ«ÎÑ™¶Ç˜ýº*i°œÈVŒ�Qû”Ñ[.�ÔmçE•ì¦eNCh�Ù
é§�É$m¿ôš"»ÌNæ(VÌmp›F¹XÈ88™ªüµ…d•XµÔÜ#�ˆŠv‘º‚F‚§Yûb
My current code is:
Dim FileName As String = "Image.jpg"
Dim ImageData() As Byte = File.ReadAllBytes(ProfileImagePath)
Dim NewImageData As String = Convert.ToBase64String(ImageData)
This returns the Base64 code but I am trying to get the actual raw data like in the example above so that I can POST to a multipart upload form which also posts in this way.
My full code for the upload being:
Dim boundary As String = "-----------------------------" & DateTime.Now.Ticks.ToString("x")
Dim req As HttpWebRequest = DirectCast(WebRequest.Create("http://www.mysite.com/upload.php"), HttpWebRequest)
req.Method = "POST"
req.ContentType = "multipart/form-data; boundary=" & "---------------------------" & DateTime.Now.Ticks.ToString("x")
req.KeepAlive = False
Dim builder As New StringBuilder()
builder.Append(boundary & vbCrLf & "Content-Disposition: form-data; name=""variable1""" & vbCrLf & vbCrLf & "1" & vbCrLf)
builder.Append(boundary & vbCrLf & "Content-Disposition: form-data; name=""file""; filename=""" & FileName & """" & vbCrLf)
builder.Append("Content-Type: application/octet-stream")
builder.Append(vbCrLf & vbCrLf)
' Add Photo Here
If UpdateImage = True Then
' Load Image
Dim ImageData() As Byte = File.ReadAllBytes(ProfileImagePath)
Dim NewImageData As String = Convert.ToBase64String(ImageData)
' Add Image To Header
builder.Append(NewImageData)
builder.Append(vbCrLf)
Else
builder.Append(vbCrLf)
End If
builder.Append(boundary & vbCrLf & "Content-Disposition: form-data; name=""save""" & vbCrLf & vbCrLf & "save")
' Footer Bytes
Dim close As Byte() = Encoding.UTF8.GetBytes("--")
Dim postHeader As String = builder.ToString()
Dim postHeaderBytes As Byte() = Encoding.UTF8.GetBytes(postHeader)
Dim boundaryBytes As Byte() = Encoding.ASCII.GetBytes(vbCrLf & boundary & "--" & vbCrLf)
Dim length As Long = postHeaderBytes.Length + boundaryBytes.Length
req.ContentLength = length
Dim requestStream As Stream = req.GetRequestStream()
Dim fulllength As Integer = postHeaderBytes.Length + boundaryBytes.Length
' Write out our post header
requestStream.Write(postHeaderBytes, 0, postHeaderBytes.Length)
' Write out the trailing boundary
requestStream.Write(boundaryBytes, 0, boundaryBytes.Length)
Dim responce As WebResponse
responce = req.GetResponse()
requestStream.Close()
Dim s As Stream = responce.GetResponseStream()
Dim sr As New StreamReader(s)
Dim Content As String = sr.ReadToEnd()
This returns the Base64 code but I am trying to get the actual raw data like in the example above
The "actual raw data" isn't text data so you shouldn't put it in a string at all; at least not without something like base64.
If you want to post binary data, then either use base64 or post it as raw bytes, but not as text. Your data is not UTF-8-encoded text, so don't try to use it as if it were.
(I can't remember the details of multi-part form data; if you can specify a part length before the part itself, then you should be fine to include the binary data directly. If it's always just delimited by some separator, then you may want to use base64 instead.)

Attachments using REST WebService and VB.NET

I am currently developing an application using VB.NET in which I am using the REST WebServices. I have been able to do the basics with REST, however, I have not been able to add an attachment (more specifically upload a file, using REST which gets attached). I have done extensive research online, but so far I have not been able to find any working examples in VB.NET. To actually upload the data I use System.Net.WebClient. The following VB.NET code does the important work:
Dim Client As New System.Net.WebClient
Dim postBytes As Byte() = System.Text.Encoding.ASCII.GetBytes(postString)
Client.UploadData(URL, "POST", postBytes)
A simplified version of my URL is as follows:
"../REST/1.0/ticket/" + ticketNumber + "/comment?user=" + userName + "&pass=" + password
Finally, an example of the content that I post is:
postString = "content=Text: RT Test" + vbLf + "Action: Comment" + vbLf + "Attachment: examplefile.jpg" + vbLf + "attachment_1="
As you can see, the postString is converted to bytes and then uploaded to the server. However, I do not know where or how I should be posting the raw attachment itself. The documentation for the service we are specifically using states to use a variable "attachment_1," which I added to the postString variable, but I am not sure what the next step should be. Should the file be converted into bytes and appended to the postBytes variable? I attempted something like this but I received an error saying that no attachment was found for examplefile.jpg.
Thanks for your help!
We could not use Client.UploadData(...) and had to convert the entire post to bytes, starting with the POST fields before the attachment, then the attachment itself, and finally the remainder of the POST fields.
Public Sub AddAttachmentToRT(ByVal url As String, ByVal fileName As String, ByVal filePath As String)
Dim dataBoundary As String = "--xYzZY"
Dim request As HttpWebRequest
Dim fileType As String = "image/jpeg" 'Will want to extract this to make it more generic from the uploaded file.
'Create a POST web request to the REST interface using the passed URL
request = CType(WebRequest.Create(url), HttpWebRequest)
request.ContentType = "multipart/form-data; boundary=xYzZY"
request.Method = "POST"
request.KeepAlive = True
'Write the request to the requestStream
Using requestStream As IO.Stream = request.GetRequestStream()
'Create a variable "attachment_1" in the POST, specify the file name and file type
Dim preAttachment As String = dataBoundary + vbCrLf _
+ "Content-Disposition: form-data; name=""attachment_1""; filename=""" + fileName + """" + vbCrLf _
+ "Content-Type: " + fileType + vbCrLf _
+ vbCrLf
'Convert this preAttachment string to bytes
Dim preAttachmentBytes As Byte() = System.Text.Encoding.UTF8.GetBytes(preAttachment)
'Write this preAttachment string to the stream
requestStream.Write(preAttachmentBytes, 0, preAttachmentBytes.Length)
'Write the file as bytes to the stream by passing its exact location
Using fileStream As New IO.FileStream(Server.MapPath(filePath + fileName), 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
'Create a variable named content in the POST, specify the attachment name and comment text
Dim postAttachment As String = vbCrLf _
+ dataBoundary + vbCrLf _
+ "Content-Disposition: form-data; name=""content""" + vbCrLf _
+ vbCrLf _
+ "Action: comment" + vbLf _
+ "Attachment: " + fileName + vbCrLf _
+ "Text: Some description" + vbCrLf _
+ vbCrLf _
+ "--xYzZY--"
'Convert postAttachment string to bytes
Dim postAttachmentBytes As Byte() = System.Text.Encoding.UTF8.GetBytes(postAttachment)
'Write the postAttachment string to the stream
requestStream.Write(postAttachmentBytes, 0, postAttachmentBytes.Length)
End Using
Dim response As Net.WebResponse = Nothing
'Get the response from our REST request to RT
'Required to capture response, without this Try-Catch attaching will fail
Try
response = request.GetResponse()
Using responseStream As IO.Stream = response.GetResponseStream()
Using responseReader As New IO.StreamReader(responseStream)
Dim responseText = responseReader.ReadToEnd()
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()
End Using
response.Close()
End If
Finally
request = Nothing
End Try
End Sub

tcpclient vs httpwebrequest

I used a tcpclient to make a connection to a streaming API and for some reason it doesn't work with a 301 error, (something wrong with my credentials). However when I use a httpwebrequest to the same API and use the same credentials and that works. I am trying to figure out what I am doing wrong:
TCPclient connection:
Try
Dim bufferread(defaultSize) As Byte
url = "xxxxxxxxx.com"
Dim tclient As TcpClient = New TcpClient(url, "80")
' use a network stream to download the tcpClient stream
nstream = tclient.GetStream()
' check if we can write to the stream to add the relevant headers and credentials
If nstream.CanWrite Then
Dim headers As String
headers = "GET " & addedUrl & " HTTP/1.0" & Chr(13) & "" & Chr(10)
headers &= "Authorization: Basic " & userNamePassword & Chr(13) & "" & Chr(10)
headers &= Chr(13) & "" & Chr(10)
Dim sendBytes As [Byte]() = Encoding.UTF8.GetBytes(headers)
nstream.Write(sendBytes, 0, sendBytes.Length)
If nstream.CanRead Then
Dim timestamp As DateTime = DateTime.Now
Dim data As String
numbytesRead = 0
' start reading from the stream
Do....
httpwebrequest:
While Not responseData = Nothing
Try
' setup the webrequest and headers to send
url = "https://xxxxxxxxxxxx.com" & addedUrl
If Not parsingTools.refreshDate = Nothing Then
url = parsingTools.refreshDate
End If
Dim poststring As String = ""
webrequest = TryCast(System.Net.WebRequest.Create(url), HttpWebRequest)
webrequest.Method = "GET"
webrequest.UserAgent = "xxxxxxxxxx"
webrequest.Referer = "xxxxxxxxxxxxx"
webrequest.Timeout = 20000
webrequest.KeepAlive = True
webrequest.Credentials = New System.Net.NetworkCredential ("xxxxxxxxxxxxx", "yyyyyyyyyyyyyy")
'get the responsestream
responseStream = webrequest.GetResponse().GetResponseStream()
'check if stream is readable
If responseStream.CanRead Then
HTTP 301 is not an error, it's a redirect. HttpWebRequest can handle redirects transparently but if you are doing all the HTTP implementation yourself with TcpClient then you need to parse and follow the redirect manually.