Parse Simple JSON with VB.NET - json

I have a simple JSON string that I am trying to parse with Visual Studio Express 2010 using native .net 4.0 instead of NewtonSoft. The json data that I am trying to parse looks like the following.
"{"token_type":"Bearer",""expires_in":3599,"access_token":"VxwK6YWYj6paqyMK2D2r4uDl34qg"}"
I can get the following code to run without error but when I try to dump the contents of the object I don't have any in the list. Here is the class I created.
Public Class AuthToken
Public Property token_type As String
Get
Return m_token_type
End Get
Set(ByVal value As String)
m_token_type = value
End Set
End Property
Private m_token_type As String
Public Property expires_in() As Integer
Get
Return m_expires_in
End Get
Set(ByVal value As Integer)
m_expires_in = value
End Set
End Property
Private m_expires_in As String
Public Property access_token As String
Get
Return m_access_token
End Get
Set(ByVal value As String)
m_access_token = value
End Set
End Property
Private m_access_token As String
End Class
My feeling is that my problem is in my class but I am not sure. So after looking for hours on this site and others Trouble parsing Json into .net Object I have put together the following code to parse the information and dump it to a RichTextBox just to see what it is.
Dim sr As New StreamReader(req.GetResponse.GetResponseStream)
Dim authtoken As New List(Of AuthToken)()
Dim ms As New MemoryStream(System.Text.Encoding.Unicode.GetBytes(sr.ReadToEnd))
Dim serializer As New System.Runtime.Serialization.Json.DataContractJsonSerializer(authtoken.GetType)
authtoken = DirectCast(serializer.ReadObject(ms), List(Of AuthToken))
ms.Close()
ms.Dispose()
sr.Close()
sr.Dispose()
For Each token In authtoken
rtbResponse.AppendText("Token: " & token.access_token & " Expires in: " & token.expires_in)
Next
So is my class created incorrectly? Is the data from the memorystream just not getting into the authtoken object because the class doesn't match the contents of the json data as it is deserialized?
If I am using the "DataContractSerializer" do I need to have data contract "stuff" in my class?
Any help is GREATLY appreciated.

The data is not getting into the authtoken variable because you don't have a list of auth tokens there - only one object. So if you get those JSON objects one at the time get rid of your lists and do it like that:
Dim sr As New StreamReader(req.GetResponse.GetResponseStream)
Dim authtoken As AuthToken
Dim ms As New MemoryStream(System.Text.Encoding.Unicode.GetBytes(sr.ReadToEnd))
Dim serializer As New System.Runtime.Serialization.Json.DataContractJsonSerializer(GetType(AuthToken))
authtoken = DirectCast(serializer.ReadObject(ms), AuthToken)
ms.Close()
ms.Dispose()
sr.Close()
sr.Dispose()
rtbResponse.AppendText("Token: " & authtoken.access_token & " Expires in: " & authtoken.expires_in)

Related

Deserialize and serialize Json data in Winform

I have a winform with a combobox and some textboxes. I get the Json data via REST API and deserialize it via Json.NET and a class file.
The JsonHelper
Imports Newtonsoft.Json
Public Module JsonHelper
Public Function FromClass(Of T)(data As T, Optional isEmptyToNull As Boolean = False, Optional jsonSettings As JsonSerializerSettings = Nothing) As String
Dim response As String = String.Empty
If Not EqualityComparer(Of T).Default.Equals(data, Nothing) Then
response = JsonConvert.SerializeObject(data, jsonSettings)
End If
Return If(isEmptyToNull, (If(response = "{}", "null", response)), response)
End Function
Public Function ToClass(Of T)(data As String, Optional jsonSettings As JsonSerializerSettings = Nothing) As T
Dim response = Nothing
If Not String.IsNullOrEmpty(data) Then
response = If(jsonSettings Is Nothing,
JsonConvert.DeserializeObject(Of T)(data),
JsonConvert.DeserializeObject(Of T)(data, jsonSettings))
End If
Return response
End Function
End Module
Imports Newtonsoft.Json
Namespace Models
Public Class Header
<JsonProperty("Name")>
Public Property Name As String
<JsonProperty("DisplayAt")>
Public Property DisplayAt As String
End Class
The Class file
Public Class DataSource
<JsonProperty("Id")>
Public Property Id As String
<JsonProperty("Name")>
Public Property Name As String
<JsonProperty("Headers")>
Public Property Headers As Header()
<JsonProperty("Rows")>
Public Property Rows As String()()
<JsonProperty("TotalRows")>
Public Property TotalRows As Integer
<JsonProperty("LastUpdated")>
Public Property LastUpdated As DateTime
<JsonProperty("CompanyId")>
Public Property CompanyId As Integer
End Class
Public Class Category
<JsonProperty("DataSource")>
Public Property DataSource As DataSource
End Class
End Namespace
The combobox is populated with data from the Json file and via bindingsource the textboxes are connected to the combobox. So if you select another row, the values of the textboxes change.
The bindingsource
Dim bindingSource As BindingSource = New BindingSource()
bindingSource.DataSource = dt
bindingSource.Sort = "Weergave DESC"
ListBox1.DataSource = bindingSource
ListBox1.DisplayMember = "Weergave"
ListBox1.ValueMember = "Id"
'ListBox1.Sorted = True
txtWeergave.DataBindings.Clear()
txtWeergave.DataBindings.Add(New Binding("Text", ListBox1.DataSource, "Weergave", True, DataSourceUpdateMode.OnPropertyChanged))
txtProjectnaam.DataBindings.Clear()
txtProjectnaam.DataBindings.Add(New Binding("Text", ListBox1.DataSource, "Projectnaam", True, DataSourceUpdateMode.OnPropertyChanged))
txtProjectnummer.DataBindings.Clear()
txtProjectnummer.DataBindings.Add(New Binding("Text", ListBox1.DataSource, "Projectnummer", True, DataSourceUpdateMode.OnPropertyChanged))
txtServicemonteur.DataBindings.Clear()
txtServicemonteur.DataBindings.Add(New Binding("Text", ListBox1.DataSource, "Servicemonteur", True, DataSourceUpdateMode.OnPropertyChanged))
I wan't to make some changes to the data and update the database via a PUT request.
Therefore I made the following routine:
Private Sub PutData()
Dim request As WebRequest = WebRequest.Create("my url")
request.ContentType = "application/json"
request.Method = "PUT"
' Get the response.
Dim response As HttpWebResponse = CType(request.GetResponse(), HttpWebResponse)
' Get the stream containing content returned by the server.
Dim dataStream As Stream = 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()
'Dim JObject As Object
Dim rawJson As String = responseFromServer
Dim dataSource As String = JsonHelper.FromClass(Of Category)(rawJson).DataSource
End Sub
The following things are not clear for me.
If I make changes in the textbox, the changes are also made in the combobox because they have been connected with eachother via a bindingsource. But does the values also change in the Class file?
How can I make changes to the values of the textboxes and update the datasource via a PUT request?
It's not completely clear becacuse some things are missing from your question, such as your binding configuration, but..
Generally I wouldn't expect things to be that "when I change the textbox the combo will change". Let's take some artificial example of a Person class with Name and Ethnicity. Name is a string and would be bound to a textbox. Ethnicity is a fixed list of values, and I would expect a combo to be bound up such that the combo's datasource, displaymember and valuememeber related to the columns/properties of a list of ethnicities, and then the combo's selectedvalue be bound to the person's ethnicity setting. This way changing the selected item in the combo edits their ethnicity to one of the other values in the fixed list of ethnicities. Changing the value displayed in the name box doesn't change anything about the ethnicity. If you have a list of multiple Person that the bindingsource is managing, then you can navigate the bindingsource to show different people and edit them. It's probably easiest to see if you also add a datagridview, albeit temporarily, bound to the same bindingsource that persons are bound through; changing the current row of the grid navigates the bindingsource and the textbox/combobox will change to show the details for the new person
The PUT request is easier to answer; you formulate a block of json for the server to work on by re-serializing your edited class to JSON, and then send it as the body of the put request
request.Method = "PUT"
'formulate a body
Dim postData = JsonHelper.FromClass(editedPerson)
Dim encoding As New ASCIIEncoding() 'or whatever
Dim byte1 As Byte() = encoding.GetBytes(postData)
request.ContentType = "application/json"
request.ContentLength = byte1.Length
Dim reqStream = request.GetRequestStream()
reqStream.Write(byte1, 0, byte1.Length)
reqStream.Close()
' Get the response.
Dim response As HttpWebResponse = CType(request.GetResponse(), HttpWebResponse)
By the way, in C# at least, you can right click your project name and choose Add REST Client, give it the URL of the swagger/openapi descriptor of your web service and it will make all the client classes for you which can simplify interaction a lot. Though it's a C# only thing (it's based on autorest which I don't think supports VB), C# and VB are the same thing internally, so you can add a C# project alongside your VB one purely for purposes of creating a rest client, and then import a reference to the c# project into your VB one

Web API Contoller - What is the proper format of the data to be returned

I have Web API controller that retrieves ticket information. At the start -- The API is called and the request is routed to the proper controller function. The controller passes a request to the database. From there the retrieved data is ran through a dictionary block where the field name is associated with the data. Next the data is serialized. Then the data is passed back to the controller. At this point I know the Json string looks good. But, when the properly formatted json data is passed back to the caller a bunch slashes are added to the output.
My understanding is that Web API is supposed to automatically format the return data. I suspect I am formatting the data for the controller correctly before it is returned.
Public Function GetTicketSearch(ByVal SourceTktNum As String) As Object
'GET api/outage/SourceTktNum
Dim strFullName As String = MethodBase.GetCurrentMethod().ReflectedType.FullName
Dim strMethodName As String = MethodBase.GetCurrentMethod().Name
Dim strClassRoutine As String = strMethodName & " / " & strFullName
Try
Dim objJsonRptRtn As Object = GetReportData_bllBLL.BLL__DataSet__GetReportData__GetData(strMARCLSysId, strLogonSysId, SourceTktNum)
'AT THIS POINT I KNOW THE JSON STRING LOOKS AS IT SHOULD.
Return objJsonRptRtn
'AFTER THE ABOVE STATEMENT SOMETHING HAPPENS TO THE DATA / SLASHES ARE ADDED TO THE OUTPUT TO BE RETURNED BY THE API
Catch ex As Exception
Dim strExMessage As String = ex.Message
Dim strStackTrace As String = ex.StackTrace
Dim strMsg As String = strExMessage & ControlChars.CrLf & ControlChars.Lf & strStackTrace & ControlChars.CrLf & ControlChars.Lf
MailLogEvent.BLL__Process__MailAndLogEvent__AddLogEntry(strMARCLSysId, strLogonSysId, 901020, dteTime_Start, 0, strMsg, strClassRoutine)
Throw New HttpResponseException(HttpStatusCode.InternalServerError)
End Try
End Function
Code to create JSON object to be passed back to the controller...
'--------------------------------------------------------- Create Json String
Dim dctDataDictionary As New Dictionary(Of String, String)
dctDataDictionary.Add("sourceTktNum", strSourceTktNumKey)
dctDataDictionary.Add("incidentTime", strIncidentTime)
dctDataDictionary.Add("incidentEndTime", strIncidentEndTime)
dctDataDictionary.Add("recordTimeStamp", strRecordTimeStamp)
dctDataDictionary.Add("outageReasonCd", strOutageReasonCd)
dctDataDictionary.Add("numDS3", strNumDS3)
dctDataDictionary.Add("numBlocked", strNumBlocked)
dctDataDictionary.Add("numVOIP", strNumVOIP)
dctDataDictionary.Add("numWireline", strNumWireline)
dctDataDictionary.Add("numEndUserCircuits", strNumEndUserCircuits)
dctDataDictionary.Add("stateCd", strStateCd)
dctDataDictionary.Add("city", strCity)
dctDataDictionary.Add("incidentDescription", strIncidentDescription)
dctDataDictionary.Add("causeDesc", strCauseDesc)
dctDataDictionary.Add("equipFailedDesc", strEquipFailedDesc)
dctDataDictionary.Add("networkPartDesc", strNetworkPartDesc)
dctDataDictionary.Add("restoreMethodDesc", strRestoreMethodDesc)
objJsonRptRtn = New System.Web.Script.Serialization.JavaScriptSerializer().Serialize(dctDataDictionary)
Return objJsonRptRtn
This could be happening because you are again trying to convert a json data into json, which results in extra slashes.
Can you show the code before you return 'objJsonRptRtn'.
As it turned out I was double serializing. I removed the statement that serialized the dictionary output. Then, simply passed the dictionary back to the controller then let the controller return the dictionary. Everything works great...
'--------------------------------------------------------- Create Dictionary
dctDataDictionary.Add("sourceTktNum", strSourceTktNumKey)
dctDataDictionary.Add("incidentTime", strIncidentTime)
dctDataDictionary.Add("incidentEndTime", strIncidentEndTime)
dctDataDictionary.Add("recordTimeStamp", strRecordTimeStamp)
dctDataDictionary.Add("outageReasonCd", strOutageReasonCd)
dctDataDictionary.Add("numDS3", strNumDS3)
dctDataDictionary.Add("numBlocked", strNumBlocked)
dctDataDictionary.Add("numVOIP", strNumVOIP)
dctDataDictionary.Add("numWireline", strNumWireline)
dctDataDictionary.Add("numEndUserCircuits", strNumEndUserCircuits)
dctDataDictionary.Add("stateCd", strStateCd)
dctDataDictionary.Add("city", strCity)
dctDataDictionary.Add("incidentDescription", strIncidentDescription)
dctDataDictionary.Add("causeDesc", strCauseDesc)
dctDataDictionary.Add("equipFailedDesc", strEquipFailedDesc)
dctDataDictionary.Add("networkPartDesc", strNetworkPartDesc)
dctDataDictionary.Add("restoreMethodDesc", strRestoreMethodDesc)
Return dctDataDictionary
Public Function GetTicketSearch(ByVal SourceTktNum As String) As Object
'GET api/outage/SourceTktNum
Dim strFullName As String = MethodBase.GetCurrentMethod().ReflectedType.FullName
Dim strMethodName As String = MethodBase.GetCurrentMethod().Name
Dim strClassRoutine As String = strMethodName & " / " & strFullName
Try
Dim dctDataDictionary As Object = GetReportData_bllBLL.BLL__DataSet__GetReportData__GetData(strMARCLSysId, strLogonSysId, SourceTktNum)
If dctDataDictionary Is Nothing Then
Throw New HttpResponseException(HttpStatusCode.PartialContent)
Else
Return dctDataDictionary
End If
Catch ex As Exception
Dim strExMessage As String = ex.Message
Dim strStackTrace As String = ex.StackTrace
Dim strMsg As String = strExMessage & ControlChars.CrLf & ControlChars.Lf & strStackTrace & ControlChars.CrLf & ControlChars.Lf
MailLogEvent.BLL__Process__MailAndLogEvent__AddLogEntry(strMARCLSysId, strLogonSysId, 901020, dteTime_Start, 0, strMsg, strClassRoutine)
Throw New HttpResponseException(HttpStatusCode.InternalServerError)
End Try
End Function

Azure Mobile Service Casting JSON to Type in VB.Net

Hi there I have been messing with Azure Mobile Services recently and after solving one problem I have come up against another one. I have a stored procedure held on my Azure SQL db which is then invoked by a custom API on my Mobile service.
In my client I can call the API to return a JSON token (or array):
Dim result As Linq.JToken = Await App.subtlesoftClient.InvokeApiAsync("test1",
System.Net.Http.HttpMethod.Get, Nothing)
I then convert this into a json string:
Dim jString As String = result.ToString
Which gives me:
{[
{
"id": 2,
"message": "This is another test message cos everything is almost almost great but what can you do eh",
"messageDate": "2015-05-10T00:00:00Z"
}
]}
What I can't figure out is how to take the result and pass it into my class:
Public Class test1
Private _ID As Integer
Private _MessageDate As Date
Private _Message As String
<JsonProperty(PropertyName:="id")>
Public Property ID As Integer
Get
Return _ID
End Get
Set(value As Integer)
_ID = value
End Set
End Property
<JsonProperty(PropertyName:="message")>
Public Property Message As String
Get
Return _Message
End Get
Set(value As String)
_Message = value
End Set
End Property
<JsonProperty(PropertyName:="messageDate")>
Public Property MessageDate As Date
Get
Return _MessageDate
End Get
Set(value As Date)
_MessageDate = value
End Set
End Property
End Class
I have tried:
Dim myArray = result.Children(Of Linq.JProperty)().
FirstOrDefault(Function(x) x.Name = "").Value
To try and put it into an array I can enumerate through. This causes errors probably because I am not passing a name into the function as my json does not appear to have a name.
Ultimately the return json will be multiple objects so I want to be able to pass them into a MobileServiceCollection(Of MyType), and I don't know how. The documentation on this seems pretty scant.
Well thanks for giving me some pointers anyway seems it was very easy in the end, isn't it always when you figure it out:
Dim result = Await App.subtlesoftClient.InvokeApiAsync("test1", System.Net.Http.HttpMethod.Get, Nothing)
Dim jString As String = result.ToString
Dim myTest = JsonConvert.DeserializeObject(Of List(Of test1))(jString)
This works fine, seems the square brackets on the JSON string indicate its is an array.

Google finance record Json Parsing vb.net

I am creating vb.net application. I am getting Json data from google finance. I am facing a problem in parsing. The problem is that :
I will give an example (not about google)
This is the class
Public Class MyModel
Dim m_tes As String
Dim m_client_list As String
Public Property type() As String
Get
Return m_tes
End Get
Set(ByVal value As String)
m_tes = value
End Set
End Property
Public Property client_list() As String
Get
Return m_client_list
End Get
Set(ByVal value As String)
m_client_list = value
End Set
End Property
End Class
and this is the JSON Deserializer
Dim deserializedProduct As MyModel = JsonConvert.DeserializeObject(Of MyModel)(JSON)
MsgBox(deserializedProduct.type)
MsgBox(deserializedProduct.client_list)
If I get one record Json data ,It works fine
like
dim JSON = {"type":"newModel","client_list":"Joe"}
The output of the msgbox is
newModel
Joe
The problem is that if I get a list of Json
I need a way to split this list likeh the following:
Json = {"type":"clientlist","client_list":"client 1"},{"type":"clientlist","client_list":"client 1"}
I haven't worked a whole lot with JSON, but I think you can pass a collection into the deserializer to get a back a collection of the deserialized objects.
In other words:
Dim deserializedProduct As List(Of MyModel) = JsonConvert.DeserializeObject(Of List(Of MyModel))(JSON)
The above code is similar to what you posted, except that is uses List<T> instead of a single instance of your MyModel object, and for the type used with the DeserializeObject you give it a List(Of ModelType).
Note that your MsgBox(deserializedProduct.type) and MsgBox(deserializedProduct.client_list) won't show you the results in a List<T> (you'll get the type name instead) - you'll need to loop through the list. Something like this:
For Each Dim model As MyModel In deserializedProduct
MsgBox(model.type)
MsgBox(model.client_list)
Next

ServiceStack.Text reading json results not working

I am just trying to figure out the best way to deserialize a json string returned from a 3rd party api call. I read ServiceStack is fast so want to try it out. No experience and here is what I have done:
Opened Visual Studio 2013
Created new project Windows Forms Application
Installed ServiceStack.Text (based on https://servicestack.net/download)
Added a button (btnView) and textbox (txtOutput)
Add code to btnView_Click event
Private Sub btnView_Click(sender As Object, e As EventArgs) Handles btnView.Click
Me.Cursor = Cursors.WaitCursor
Dim wp As New WebPost 'this allows to pass url and return results
wp.URL = "xxxx"
Dim sJSONRetVal As String = wp.Request(String.Empty, True)
'sJSONRetVal return values looks like the following:
'{"complaints":[{"feedback_type":"abuse","subject":"Sales Agent Position"},{"feedback_type":"abuse","subject":"Sales Agent Position"}],"message":"OK","code":0}
'ServiceStack.Text example
Dim t As SMTP_Complaints = ServiceStack.Text.JsonSerializer.DeserializeFromString(Of SMTP_Complaints)(sJSONRetVal)
'For Each xi As SMTP_Complaints In t
' txtOutput.Text &= xi.mail_from & vbCrLf
'Next
wp = Nothing
txtOutput.Text = t.ToString
Me.Cursor = Cursors.Default
End Sub
Public Class SMTP_Complaints
Dim _feedback_type As String = ""
Dim _subject As String = ""
Public Property feedback_type As String
Get
Return _feedback_type
End Get
Set(value As String)
_feedback_type = value
End Set
End Property
Public Property subject As String
Get
Return _subject
End Get
Set(value As String)
_subject = value
End Set
End Property
End Class
The above doesn't seem to get any data. how would I loop through the data returned and return the data from both instances? Just not sure how I need to set this up to read the json data and then be able to output.
Based on the returned JSON of:
{"complaints":[{"feedback_type":"abuse","subject":"Sales Agent Position"},{"feedback_type":"abuse","subject":"Sales Agent Position"}],"message":"OK","code":0}
You will need two DTOs to deserialise this result.
I have used auto implemented properties here to simplify the complexity of the code. If you use an older version of VB, you'll need to expand these out to include a backing field with get and set method.
Public Class SMTP_Complaint
Public Property feedback_type As String
Public Property subject As String
End Class
Public Class SMTP_ComplaintsResponse
Public Property complaints As SMTP_Complaint()
Public Property message As String
Public Property code As Integer
End Class
You need the SMTP_ComplaintsResponse class because your complaints are wrapped in your JSON response.
Then to deserialise the response:
Dim response = JsonSerializer.DeserializeFromString(Of SMTP_ComplaintsResponse)(sJSONRetVal)
And your complaints are then accessible:
For Each complaint As var In response.complaints
Console.WriteLine("Type: {0}, Subject {1}", complaint.feedback_type, complaint.subject)
Next