Deserializing json array into .net class - vb.net

I'm having problems deserializing some json data, getting InvalidCastExceptions and the like.
Can anyone point me in the right direction?
Here's the json i'm wanting to deserialize;
[{"OrderId":0,"Name":"Summary","MaxLen":"200"},{"OrderId":1,"Name":"Details","MaxLen":"0"}]
Here's my code;
Public Class jsTextArea
Public OrderId As Integer
Public Name As String
Public MaxLen As String
End Class
Dim js As New System.Web.Script.Serialization.JavaScriptSerializer
Dim rawdata = js.DeserializeObject(textAreaJson)
Dim lstTextAreas As List(Of jsTextArea) = CType(rawdata, List(Of jsTextArea))

OrderId is an Int in your json (note the lack fo quotes round the values), but you're declaring it as String in "jsTextArea". Also, unless the type that rawdata is returned as has a cast to List(Of jsTextArea), which it probably doesn't the code you've shown won't work.
Update
To get the data out into a List(Of jsTextArea) try the following:
Dim js As New System.Web.Script.Serialization.JavaScriptSerializer
Dim lstTextAreas = js.Deserialize(Of List(Of jsTextArea))(textAreaJson)

Doing it all on one line worked a treat;
Dim lstTextAreas As List(Of jsTextArea) = js.Deserialize(textAreaJson, GetType(List(Of jsTextArea)))

Dim textAreaJson As String = "[{""OrderId"":0,""Name"":""Summary"",""MaxLen"":""200""},{""OrderId"":1,""Name"":""Details"",""MaxLen"":""0""}]"
Dim js As New System.Web.Script.Serialization.JavaScriptSerializer
Dim lstTextAreas As jsTextArea() = js.Deserialize(Of jsTextArea())(textAreaJson)

Here's a function to Deserialize JSON of any type:
Public Function DeserializeJson(Of T)(json As String) As T
Return New JavaScriptSerializer().Deserialize(Of T)(json)
End Function

Related

VB.NET, keywords as variable names

I have to deserialize some json data string into structure.
Problem is that data names conflicts vith VB keywords what is in C# not a case.
This is json string:
{"id":2526068,"date":"2019-07-21T19:15:17.4468196+02:00","error":""}
Problematic names are obviously "date" and "error". Somewhere I found that such variables should be surrended with []. But this don't work for me.
Here is my code:
Structure reqjson
Dim id As String
Dim [date] As String
Dim [error] As String
End Structure
Dim idnum As Long = 0
Dim sldate As String = ""
If Not String.IsNullOrEmpty(jsonstr) Then
Dim r As reqjson = JsonConvert.DeserializeObject(Of reqjson)(jsonstr)
idnum = CLng(r.id)
sladate = r.date.ToString("dd.MM.yyyy. hh:mm:ss.fff")
End If
Problem is that deserializer can't deserialize data if they don't have a same name what VB don't allow. In C# this declaration is legal:
struct reqjson{
string id;
string date;
string error;
};
But not in VB.NET. What to do here?
I don't see any problem with your deserialization. Your code works for me!
But perhaps you should address a couple potential issues. Don't use Dim for class level fields. Use Public or Private
Structure reqjson
Public id As String
Public [date] As String
Public [error] As String
End Structure
And I'm not changing anything here, other than adding the json string myself
Public Shared Sub foo()
Dim jsonstr = "{""id"":2526068,""Date"":""2019-07-21T19:15:17.4468196+02:00"",""error"":""""}"
Dim idnum As Long = 0
Dim sldate As String = ""
If Not String.IsNullOrEmpty(jsonstr) Then
Dim r As reqjson = JsonConvert.DeserializeObject(Of reqjson)(jsonstr)
idnum = CLng(r.id)
However, you are doing String.ToString(). Try this instead
sldate = Date.Parse(r.date).ToString("dd.MM.yyyy. hh:mm:ss.fff")
End If
End Sub
Or better yet, use an actual date in the struct
Structure reqjson
Public id As String
Public [date] As Date
Public [error] As String
End Structure
which makes your original code work
sldate = r.date.ToString("dd.MM.yyyy. hh:mm:ss.fff")

VB.NET How to parse and add the result into the list(of string) from json file?

I'm creating a launcher for Minecraft. I have a problem, My launcher using json files to load and check files. How can I add the strings from this json (example) into the AssetsList? https://s3.amazonaws.com/Minecraft.Download/indexes/1.8.json
My code, if it helps you to understand me (I'm using Newtonsoft.json to parse json):
The MCAssets class:
Public Class MCAssets
Public hash As String
End Class
The list:
Public AssetsList As New List(Of String)
The funchtion to get the assets:
Public Async Function GetAssets() As Task
If Not Directory.Exists(Root + "\assets\indexes") Then
Directory.CreateDirectory(Root + "\assets\indexes")
End If
Dim client = New WebClient()
Await client.DownloadFileTaskAsync(New Uri(String.Format("http://s3.amazonaws.com/Minecraft.Download/indexes/{0}.json", AssetIndex)), String.Format(Root + "\assets\indexes\{0}.json", AssetIndex))
Dim reader As New StreamReader(Root + "\assets\indexes\" + AssetIndex + ".json")
Dim assets As String = reader.ReadToEnd()
reader.Close()
Dim jsonresult = JsonConvert.DeserializeObject(Of Object)(assets)
For Each i In jsonresult("objects").Children()
AssetsList.Add(i.ToObject(Of MCAssets).hash)
Next
End Function
If you want know more about Minecraft assets, visit this: https://github.com/tomsik68/mclauncher-api/wiki/Minecraft-1.6-resources
You can do something like this:
Dim assetsObject = JsonConvert.DeserializeObject(Of JObject)(assets) 'assets is your json file
Dim allAssets = (From i In assetsObject("objects").Children() _
Select New MCAssets() With {.hash = i.First.Value(Of String)("hash")}).ToList()
By the way, there is not really a need to make a custom class. You can just add all of the hashes to a list of string like so:
Dim assetsObject = JsonConvert.DeserializeObject(Of JObject)(assets)
Dim allAssets = (From i In assetsObject("objects").Children() _
Select i.First.Value(Of String)("hash"))

List(of String) or Array or ArrayList

Hopefully a simple question to most programmers with some experience.
What is the datatype that lets me do this?
Dim lstOfStrings as *IDK*
Dim String0 As String = "some value"
Dim String1 As String = "some value"
Dim String2 As String = "some value"
Dim String3 As String = "some value"
Dim String4 As String = "some value"
Dim String5 As String = "some value"
lstOfStrings.add(String0, String1, String2, String3)
I would access these like this
Dim s1 = lstOfStrings(0)
Dim s2 = lstOfStrings(1)
Dim s3 = lstOfStrings(2)
Dim s4 = lstOfStrings(3)
if I use List(of String)
I am only able to .add one thing to the list (at a time), and in my function I want to be able to store several values(at a time).
Solution:
Private Function Foo() As List(Of String)
Dim temp1 As String
Dim temp2 As String
Dim temp3 As String
Dim temp4 As String
Dim temp5 As String
Dim temp6 As String
Dim inputs() As String = {temp1, temp2, temp3, temp4, temp5, temp6}
Dim lstWriteBits As List(Of String) = New List(Of String)(inputs)
Return lstWriteBits
End Function
List(Of String) will handle that, mostly - though you need to either use AddRange to add a collection of items, or Add to add one at a time:
lstOfString.Add(String1)
lstOfString.Add(String2)
lstOfString.Add(String3)
lstOfString.Add(String4)
If you're adding known values, as you show, a good option is to use something like:
Dim inputs() As String = { "some value", _
"some value2", _
"some value3", _
"some value4" }
Dim lstOfString as List(Of String) = new List(Of String)(inputs)
' ...
Dim s3 = lstOfStrings(3)
This will still allow you to add items later as desired, but also get your initial values in quickly.
Edit:
In your code, you need to fix the declaration. Change:
Dim lstWriteBits() As List(Of String)
To:
Dim lstWriteBits As List(Of String)
Currently, you're declaring an Array of List(Of String) objects.
You can do something like this,
Dim lstOfStrings As New List(Of String) From {"Value1", "Value2", "Value3"}
Collection Initializers
Neither collection will let you add items that way.
You can make an extension to make for examle List(Of String) have an Add method that can do that:
Imports System.Runtime.CompilerServices
Module StringExtensions
<Extension()>
Public Sub Add(ByVal list As List(Of String), ParamArray values As String())
For Each s As String In values
list.Add(s)
Next
End Sub
End Module
Now you can add multiple value in one call:
Dim lstOfStrings as New List(Of String)
lstOfStrings.Add(String1, String2, String3, String4)
look to the List AddRange method here
Sometimes I don't want to add items to a list when I instantiate it.
Instantiate a blank list
Dim blankList As List(Of String) = New List(Of String)
Add to the list
blankList.Add("Dis be part of me list") 'blankList is no longer blank, but you get the drift
Loop through the list
For Each item in blankList
' write code here, for example:
Console.WriteLine(item)
Next
You can use IList(Of String) in the function :
Private Function getWriteBits() As IList(Of String)
Dim temp1 As String
Dim temp2 As Boolean
Dim temp3 As Boolean
'Pallet Destination Unique
Dim temp4 As Boolean
Dim temp5 As Boolean
Dim temp6 As Boolean
Dim lstWriteBits As Ilist = {temp1, temp2, temp3, temp4, temp5, temp6}
Return lstWriteBits
End Function
use
list1.AddRange(list2) to add lists
Hope it helps.
For those who are stuck maintaining old .net, here is one that works in .net framework 2.x:
Dim lstOfStrings As New List(of String)( new String(){"v1","v2","v3"} )

Getting an invalid cast exception when trying to order a list of objects with linq

I'm trying to sort a list of tweets (class: SimpleTweet), which each have ID associated with them (x.ID where x is an object of class SimpleTweet). I'm using linq to sort this, using "OrderByDescending", but am getting an error on the line where I set a new object of type List(Of SimpleTweet) equal to the sorted list. The error I am getting is, "System.InvalidCastException: Unable to cast object of type 'System.Linq.OrderedEnumerable2[SimpleTweet,System.Int64]' to type 'System.Collections.Generic.List1[SimpleTweet]'".
The code:
<WebMethod()> _
Public Function GetTweetsByUserID(ByVal userID As Integer) As List(Of SimpleTweet)
Dim result As New List(Of SimpleTweet)
Dim urlTwitter As String = "https://api.twitter.com/1/statuses/user_timeline.xml?include_entities=true&include_rts=true&screen_name={0}&count=3"
'Dim twitterfeed As String = utils.GetUserTwitterFeeds(userID, "docphin")
Dim lq As New lqDFDataContext
Dim var = lq.web_GetTweetsByUserID(userID).ToList()
Dim sortedresult As New List(Of SimpleTweet)
If Not var Is Nothing Then
For Each twitterfeed In var
Dim listURL As String = String.Format(urlTwitter, twitterFeed.TweeterFeed)
Dim tweetXML As XmlDocument = utils.GetXMLForURL(listURL)
Dim tweetnodelist As XmlNodeList = tweetXML.ChildNodes(1).ChildNodes
For Each node As XmlNode In tweetnodelist
Dim tweet As New SimpleTweet
tweet.CreatedAt = node.SelectSingleNode("created_at").InnerText
tweet.HTMLText = utils.ReturnTextWithHRefLink(node.SelectSingleNode("text").InnerText)
tweet.ID = node.SelectSingleNode("id").InnerText
tweet.Name = node.SelectSingleNode("user/name").InnerText
tweet.ScreenName = node.SelectSingleNode("user/screen_name").InnerText
tweet.Text = node.SelectSingleNode("text").InnerText
tweet.UserID = node.SelectSingleNode("user/id").InnerText
tweet.ProfileImageURL = node.SelectSingleNode("user/profile_image_url_https").InnerText
result.Add(tweet)
Next
Next
sortedresult = result.OrderByDescending(Function(tweet) tweet.ID)
End If
Return sortedresult
End Function
You need to materialize the result with a call to .ToList(). Add it to the end of this line:
sortedresult = result.OrderByDescending(Function(tweet) tweet.ID)
sortedResult is of type List(Of SimpleTweet) and OrderByDescending returns an IOrderedEnumerable(Of SimpleTweet) that cannot automatically be cast to the expected type.
Since you want to return a List(Of SimpleTweet) you need to call ToList to create a new list from the IEnumerable(Of SimpleTweet):
Return sortedresult.ToList()
ToList forces an immediate query evaluation.

setting strings_array(0) = "" problem

im getting an exception on this:
Dim strings_extreme As String()
strings_extreme(0) = ""
it says that i am using it before it is being assigned a value
how do i initialize it?
please note that i need to be able to do this:
strings_extreme = input.Split(","c).Distinct().OrderBy(Function(s) s)
If you truly don't know how many strings there are going to be, then why not just use an IList:
Dim stringList As IList(Of String) = New List(Of String)
stringList.Add("")
You can get the Count of how many strings there are and you can For Each through all the strings in the list.
EDIT: If you're just trying to build an array from a Split you should be able to do this:
Dim strings_extreme() As String = input.Split(...)
Dim strings_extreme As List(Of String) = New List(Of String)
strings_extreme.Add("value1")
strings_extreme.Add("value 2")
strings_extreme.Add("value 3rd")
strings_extreme.Add("value again")
Dim strings() As String = strings_extreme.ToArray()
...
Dim strings_extreme(10) As String
strings_extreme(0) = ""
Further info: http://www.startvbdotnet.com/language/arrays.aspx
Dim strings_extreme as String() = {"yourfirstitem"}
But actually, why not take a look at some more advanced data structure from System.Collections namespace?
Shouldn't bother setting a string to "".
Try using:
Dim strings_extreme(10) As String
strings_extreme(yourIndex) = String.Empty