Json with parameters in Vb.net - json

I need to send json data to an API including a QR code and some other values.
this is what i got from them
The needed parameter is:
• Parameter "data" in JSON:
id -> 100 (fixed, it is the ID needed for our software)
qrcode -> QRcode value
Example: data={"id":"100","qrcode":"VL11bbdb186a3a6dcfc57a1b07149c9a0e"}
and this is the code i use
Call:
Dim jsonPost As New JsonPost(postadress)
Dim dictqr As New Dictionary(Of String, Object)
dictqr.Add("id", lastmeas.id)
dictqr.Add("qrcode", lastmeas.qrcode)
jsonPost.PostData(dictqr)
and this is the definition
Public Class JsonPost
Private urlToPost As String = ""
Public Sub New(ByVal urlToPost As String)
Me.urlToPost = urlToPost
End Sub
Public Function PostData(ByVal dictData As Dictionary(Of String, Object)) As Boolean
Dim webClient As New WebClient()
Dim resByte As Byte()
Dim resString As String
Dim reqString() As Byte
ServicePointManager.ServerCertificateValidationCallback = Function(o, certificate, chain, errors) True
Try
webClient.Headers("content-type") = "application/json"
webClient.Headers("accept") = "*/*"
reqString = Encoding.Default.GetBytes(JsonConvert.SerializeObject(dictData, Newtonsoft.Json.Formatting.None))
resByte = webClient.UploadData(Me.urlToPost, "POST", reqString)
resString = Encoding.Default.GetString(resByte)
Form1.respuesta_envio = resString
webClient.Dispose()
Return True
Catch ex As Exception
Form1.respuesta_envio = ex.Message
CreateObject("WScript.Shell").Popup(ex.Message, 5, "Data not transfered")
End Try
Return False
End Function
End Class
if i deserialize, i get
{"id":"100","qrcode":"example"}
but i do not know how to include this data= part

The API appears to be asking you to send a JSON string inside a form-url-encoded parameter. That's unpleasant and not a logical way to design an API, but if that's what they require then that's what you'll have to do.
Therefore you need to:
remove the Content-Type header telling the server to expect a JSON body in the request. What you'll actually be sending is form-url-encoded data where the one parameter happens to contain JSON within its value. i.e. remove this line:
webClient.Headers("content-type") = "application/json"
prepend the data= bit to the JSON string generated by the SerializeObject function:
reqString = Encoding.Default.GetBytes("data=" & JsonConvert.SerializeObject(dictData, Newtonsoft.Json.Formatting.None))

Related

Iterate Object Deserialized JSON

I cannot figure out how to iterate through an object to retrieve a list of errors sent in a JSON string. I have a For Each loop looing at each key pair value in my JSON but the third key pair is an object of key pairs. I cannot access these using the same For Each structure (I can access them if I loop through the object but want to keep it consistent if possible.. My 'Case Is "Errors" case statement is where I want to iterate the errors object but I am not sure how to get to it.. Here is my code.. I hope someone can assist..
Sample JSON:
{"success":"true","api_reference":3821,"errors":[{"record":"landlord","record_id":"-16::1::LPMB40-2385DDDC","error":"Please
ensure the email field has been
completed","error_code":"33101"},{"record":"landlord","record_id":"-16::1::LPMB40-2385DDDC","error":"Please
ensure the email field is a valid email
address","error_code":"33102"}]}
Dim jss = New JavaScriptSerializer()
Dim data = jss.Deserialize(Of Object)(responseFromServer)
Dim strSuccess = "", strAPIReference = ""
Dim intExpiresIn = 0
Dim ErrorsObject As Object
For Each kvp As KeyValuePair(Of String, Object) In data
Select Case kvp.Key
Case Is = "success"
strSuccess = kvp.Value
Case Is = "api_reference"
strAPIReference = kvp.Value
Case Is = "errors"
ErrorsObject = kvp.Value
For Each errorskvp As KeyValuePair(Of String, Object) In ErrorsObject
Next
End Select
Next
I would suggest doing this strongly typed, so that you can deserialize the json to a real object and use the object properties. That way it's much easier to read the values and loop errors etc:
Classes:
Public Class JsonResponse
Public Property Success As Boolean
Public Property Api_reference As String
Public Property Errors As IEnumerable(Of JsonError)
End Class
Public Class JsonError
Public Property Record As String
Public Property Record_Id As String
Public Property [Error] As String
Public Property Error_Code As String
End Class
Deserialization and use:
Dim j As New JavaScriptSerializer()
Dim data As JsonResponse = j.Deserialize(Of JsonResponse)(responseFromServer)
If Not data.Success Then
For Each myError As JsonError In data.Errors
Next
End If

Serialized JSON in VB.NET not recognised by web server

I'm new to VB.NET and am working on a simple program that will serialize two variables into JSON and POST the data to a web server. The data is being received by the Python server but it is giving an error when trying to deserialize the data.
The inputs are:
tester_id = 2
operation = "P"
When serialized this looks like:
{
"tester_id": 2,
"operation": "P"
}
Our server is giving an error and has the following log.
[Sat Aug 19 13:46:53.485257 2017] [:error] [pid 17352] <QueryDict: {u'{\\r\\n "tester_id": 2,\\r\\n "operation": "P"\\r\\n}': [u'']}>
This suggests that it is receiving a key of:
{u'{\\r\\n "tester_id": 2,\\r\\n "operation": "P"\\r\\n}
With a value of:
[u'']
This isn't correct and I don't understand why it is being received like this, any help is greatly appreciated! See below for the VB.NET code.
Class:
Public Class JSON_get_sensor_id_POST
Public Property tester_id() As Integer
Get
Return m_tester_id
End Get
Set(ByVal value As Integer)
m_tester_id = value
End Set
End Property
Private m_tester_id As Integer
Public Property operation() As String
Get
Return m_operation
End Get
Set(ByVal value As String)
m_operation = value
End Set
End Property
Private m_operation As String
End Class
Call function:
Dim set_tester_id As Integer = 1
Dim set_operation As String = "P"
Dim manuf_url As String = "https://XYZ...."
Dim JSON_to_send As New JSON_get_sensor_id_POST
JSON_to_send.tester_id = set_tester_id
JSON_to_send.operation = set_operation
Dim postData = JsonConvert.SerializeObject(JSON_to_send, Formatting.Indented)
Dim return_object = POST_to_Server(manuf_url, postData)
Upload Function:
Private Function POST_to_Server(ByVal post_url As String, ByVal JSON_to_post As Object)
Dim user_login As String = "blah#blah.com"
Dim user_pass As String = "blah"
Dim myCache As New CredentialCache()
myCache.Add(New Uri(post_url), "Basic", New NetworkCredential(user_login, user_pass))
' Create a request using a URL that can receive a post.
Dim request As WebRequest = WebRequest.Create(post_url)
' Set the Method property of the request to POST.
request.Credentials = myCache
request.Method = "POST"
request.ContentType = "application/json"
' Create POST data and convert it to a byte array.
Dim byteArray As Byte() = Encoding.Default.GetBytes(JSON_to_post)
' Set the ContentLength property of the WebRequest.
request.ContentLength = byteArray.Length
' Get the request stream.
Dim dataStream As Stream = request.GetRequestStream()
' Write the data to the request stream.
dataStream.Write(byteArray, 0, byteArray.Length)
' Close the Stream object.
dataStream.Close()
' Get the response.
Dim response As WebResponse = request.GetResponse()
' Display the status.
Console.WriteLine(CType(response, HttpWebResponse).StatusDescription)
' Get the stream containing content returned by the server.
dataStream = response.GetResponseStream()
' Open the stream using a StreamReader for easy access.
Dim reader As New StreamReader(dataStream)
' Read the content.
Dim responseFromServer As String = reader.ReadToEnd()
' Display the content.
DebugMessage(responseFromServer)
' Clean up the streams.
reader.Close()
dataStream.Close()
response.Close()
Dim myObject = JsonConvert.DeserializeObject(Of JSON_sensor_id_request_return)(responseFromServer)
Return myObject
End Function
\r and \n are escape sequences that are not visible when a string is displayed. Instead of formatting your data like this:
{
"tester_id": 2,
"operation": "P"
}
try formatting it something like this:
{"tester_id": 2,"operation": "p"}

How to save a json file from an API in vb.net

I have an API where I consume a Json file from. The function I have written is
Public Function getData(ByVal _token As String, ByVal _identifier As String) As String
Dim client = New RestClient(_baseURI)
Dim request = New RestRequest("/datasources/{identifier}/data", Method.GET)
request.AddUrlSegment("identifier", _identifier)
request.AddHeader("Authorization", "Basic " + _token)
Dim jstr = client.Execute(request).Content
Dim allDATA As List(Of GeneralInfo) = JsonConvert.DeserializeObject(Of List(Of GeneralInfo))(jstr)
Return 0
End Function
This works perfectly well. I can save the string into a file. But I also need a json file and I just do not know how to accomplish this.
Based on this solution I tried
request.OnBeforeDeserialization = Function(resp)
resp.ContentType = "appliction/json"
End Function
Dim queryResult = client.Execute(request)
Console.WriteLine(queryResult.Content)
but without any result. Nothing will be written into the console. Any idea how I can get the json file? I am using
Imports Newtonsoft.Json
Imports RestSharp

Issues with JSON deserialization

I know there are a lot of answers related to this, however, I am unable to parse the response.
This is my JSON that I get back from wrGETURL.OpenRead(sURL):
{
"sessionKey": "TFtG+pGZ0cl0TuUbItWGy9xb9RyoPKGlY2EUF/nHe"
}
This is my JSON that I get back from getcall.OpenRead(sURL):
{
"success": true,
"message": "OK",
"total": 1,
"data": [
{
"domain": "emailsecautomate.co",
"status": "Active",
"order_date": "2017-04-26",
"service": "Email Security",
"company_name": "some name",
"address1": "1 somewhere",
"address2": null,
"city": "somecity",
"state": null,
"country": "some country",
"post_code": null,
"telephone": null,
"email": null,
"po_number": null,
"licenses": "10"
}
]
}
If I comment out the line JsonConvert.DeserializeObject(Of TotalResponse)(st) and output st to a MessageBox this is my JSON:
As you can see it's fine. However if I comment back in that line I get the following error:
401 Unauthorized
This is my full code:
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
user = username.Text
pwd = password.Text
'MessageBox.Show(savedUser)
If savedUser IsNot Nothing AndAlso savedUser = "-9999" Then
Dim sqlStatement As String = "INSERT INTO my_table VALUES ('" & user & "','" & pwd & "')"
mobjHost.SetSQL(sqlStatement)
End If
Dim encoded As String = System.Convert.ToBase64String(System.Text.Encoding.UTF8.GetBytes(user + ":" + pwd))
Dim sURL As String
sURL = "https://xxx.xxx/partners/auth"
Dim wrGETURL As New WebClient()
wrGETURL.Headers.Add("Authorization", "Basic " + encoded)
Try
Dim data As Stream = wrGETURL.OpenRead(sURL)
Dim reader As New StreamReader(data)
Dim s As String = reader.ReadToEnd()
Dim jsonResult = JsonConvert.DeserializeObject(Of IDictionary)(s)
'This line with/without ToString gives the error "objectreference is not set to an instance of Object"
Dim sessionKey = jsonResult.Item("sessionKey").ToString
'Not calling the function for now As even session key gives the same issue
'MessageBox.Show(sessionKey) This shows the sessionKey and everything is fine if this is used
'Me.getCustomers(sessionKey)
wrGETURL.Dispose()
Catch ex As Exception
MessageBox.Show(ex.Message)
End Try
End Sub
Public Function getCustomers(ByVal sKey As String)
Dim st As String = ""
Dim getcall As New WebClient()
getcall.Headers.Add("USER", user)
getcall.Headers.Add("KEY", sKey)
getcall.Headers.Add("Content-Type", "application/json")
Dim sURL = "https://xxx.xxx/partners/customers"
Try
Dim data As Stream = getcall.OpenRead(sURL)
Dim reader As New StreamReader(data)
st = reader.ReadToEnd()
theResponse = JsonConvert.DeserializeObject(Of TotalResponse)(st)
Catch ex As Exception
MessageBox.Show(ex.Message)
End Try
Return True
End Function
These are my classes for the JSON response:
Public Class TotalResponse
Public success As String
Public message As String
Public total As String
Public data As List(Of CustomerInfo)
End Class
Public Class CustomerInfo
Public domain As String
Public status As String
Public order_date As String
Public service As String
Public company_name As String
Public address1 As String
Public address2 As String
Public city As String
Public state As String
Public country As String
Public post_code As String
Public telephone As String
Public email As String
Public po_number As String
Public licenses As String
End Class
I would consider implementing Using for your WebClient and StreamReader objects:
Managed resources are disposed of by the .NET Framework garbage collector (GC) without any extra coding on your part. You do not need a Using block for managed resources. However, you can still use a Using block to force the disposal of a managed resource instead of waiting for the garbage collector.
Please also look at turning Option Strict On which will help you write better code:
Restricts implicit data type conversions to only widening conversions, disallows late binding, and disallows implicit typing that results in an Object type.
I would also look at using the JsonSerializationException within your Catch rather than a general Exception.
With your method getCustomers, consider changing it into a function and returning TotalResponse.
Lastly consider only declaring variables if they are needed and only when they are required. This helps with reducing the amount of code and with the workflow of your code. This can be particular useful for debugging.
With these changes your code would look something like this:
Private Async Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim sessionKey As String = ""
Using wb As New WebClient()
Dim encoded As String = System.Convert.ToBase64String(System.Text.Encoding.UTF8.GetBytes(user + ":" + pwd))
wb.Headers.Add("Authorization", "Basic " + encoded)
Dim data As Stream = wb.OpenRead("https://xxx.xxx/partners/auth")
Using reader As New StreamReader(data)
Try
Dim result As IDictionary = JsonConvert.DeserializeObject(Of IDictionary)(Await reader.ReadToEndAsync())
sessionKey = result.Item("sessionKey").ToString()
Catch ex As JsonSerializationException
'handle
End Try
End Using
End Using
If Not sessionKey = "" Then
Dim theResponse As TotalResponse = getCustomers(sessionKey)
End If
End Sub
Private Async Function getCustomers(ByVal sKey As String) As TotalResponse
Dim returnResponse As New TotalResponse
Using wb As New WebClient()
wb.Headers.Add("USER", user)
wb.Headers.Add("KEY", sKey)
wb.Headers.Add("Content-Type", "application/json")
Dim data As Stream = wb.OpenRead("https://api-dev.theemaillaundry.net/partners/customers")
Using reader As New StreamReader(data)
Try
returnResponse = JsonConvert.DeserializeObject(Of TotalResponse)(reader.ReadToEndAsync())
Catch ex As JsonSerializationException
'handle
End Try
End Using
End Using
Return returnResponse
End Function
I've also noted your SQL is open to SQL injection. It's outside the scope of this question however consider using SQL parameters. I'm not familiar with mobjHost.SetSQL so unfortunately I can't advise in this area.

POST using the uploadstring method to call a web service and pass a json array

I am attempting to do a POST to a web service. I am using the WebClient class and calling the uploadstring method. This works fine until the web service I call expects some data, particularly a json array. I am trying to find out what format the data needs to be in, in order for the web service to accept and consume it properly. Example:
WebClient myWebClient = new WebClient();
string resp = myWebClient.UploadString("www.myUrl.com", "POST", "someDataToSend");
Any help here would be appreciated!
the web service (vb.net) being called takes a keyvaluepair:
<OperationContract(), WebInvoke(BodyStyle:=WebMessageBodyStyle.WrappedRequest, Method:="POST", RequestFormat:=WebMessageFormat.Json, ResponseFormat:=WebMessageFormat.Json)> _
Public Function DoSomething(ByVal myKeyValuePair() As KeyValuePair(Of String, String)) As String
I found a solution for this. The data has to be in json format literally:
"{"Type":[{"key":"cType","value":"Age"}]}"
I created a class serialized it and then finagled the square brackets in.
Public Class cType
Private _key As String
Public Property Key() As String
Get
Return _key
End Get
Set(ByVal value As String)
value = "cType"
_key = value
End Set
End Property
Public value As String
End Class
Dim objType As cType = New cType
objType.value = "Age"
Dim myData As String = deserializer.Serialize(New With {.cType = objType})
myData = myData.Insert(12, "[")
myData = myData.Insert(myData.Length - 1, "]")