Using json function with a string in vb.net - json

When I try to send back a json string with the following json function the string is inserts new lines and escapes characters in vb.net.
Questions
How do I get it to return as proper json?
Is it possible to use something like Json(data:=jsonstr, JsonRequestBehavior.AllowGet) to fix the issue?
Is it possible to use notation similar to C# when dealing with Json strings? Dim someJson as string= #"{""firstname"":"+c.c_firstname+"}"
-
Function get_people_jsonresult(Optional id As Integer = 0) As JsonResult
Dim c As dtb_people = db.dtb_people.Where(Function(x) x.c_Id = 1).Single
Dim jsonstr As String = "{
""firstname"":""" + c.c_firstname + """,
""lastname"":""" + c.c_lastname + """,
""id"":" + c.c_Id.ToString + "
}"
Return Json(jsonstr, JsonRequestBehavior.AllowGet)
End Function
Returned string
"[{\r\n \"firstname\":\"john\",\r\n \"lastname\":\"smith\",\r\n \"id\":1\r\n }]"
updated:
The idea is to figure out different ways to do the same thing to figure out a style that I like.
1) I found this solution but kind of quirky but makes sense - i.e. turn it into an object it will recognize vs. something generic like Ctype(jsonstr, object). I think the point is that jsonresult is meant to serialize json, but this is already serialized, so it should be returned as is.
Dim d As Dictionary(Of String, String) = JsonConvert.DeserializeObject(Of Dictionary(Of String, String))(jsonstr)
Return Json(d, JsonRequestBehavior.AllowGet)
2) Still not sure if something like this is possible
3) It doesn't look like # offers any benefit since vb.net does multi-line string literals an optional format could be a string interpolation and to use single quotes vs. double so there is no need to escape them.
Dim jsonstr2 As String = $"{{
'firstname': '{c.c_firstname}',
'lastname':'{c.c_lastname}' ,
'id':{c.c_Id.ToString}
}}"

You can return the dtb_people object instead of building the string as below:
Return Json(c, JsonRequestBehavior.AllowGet)
The returned Json will use whatever the property names of your dtb_people class are
If you are wanting to use different property names in your Json, you would decorate your dtb_people class with a JsonProperty declaration and set the PropertyName to whatever you want
[JsonProperty(PropertyName = "firstname")]

The answer to your question which was why it was inserting VBCrLf is because you made a string with some carriage return. Having your string like this on multiple lines will make a string VBCrLf inside it. But #Darthchai has the answer to make your Json

Related

VB Variable JSON String

In Visual Basic code, when I try to insert a variable into this JSON string it comes back
as a 400 bad request. How do I correctly feed this JSON string a variable?
Dim myJSON As String = "{""StoreId"":""12345"",""TerminalId"":""12345"",""CaptureMode"":""true"",""MerchantReferenceCode"":""VARIABLEINSERTEDHERE"",""InvoiceNumber"":""12345"",""TimeoutMinutes"":""5"",""ShowAddress"":""true"",""AddressRequired"":""true"",""TransactionTotal"":""33.33"",""TaxTotal"":""2.00"",""CustomerCode"":""12345""}"
Your JSON as it sits right now is an Object that looks like this:
{
"StoreId": "12345",
"TerminalId": "12345",
"CaptureMode": "true",
"MerchantReferenceCode": "VARIABLEINSERTEDHERE",
"InvoiceNumber": "12345",
"TimeoutMinutes": "5",
"ShowAddress": "true",
"AddressRequired": "true",
"TransactionTotal": "33.33",
"TaxTotal": "2.00",
"CustomerCode": "12345"
}
One option that you have is to create a new JObject, use the Add method (documentation) to build the object's properties, and then the ToString method (documentation) to serialize the object to JSON. This way you don't have to worry about properly formatting the JSON, just let the library do it for you.
Take a look at this example:
Dim myVariable = "VARIABLEINSTEREDHERE"
Dim request = New JObject()
request.Add("StoreId", 12345)
request.Add("TerminalId", 12345)
request.Add("CaptureMode", True)
request.Add("MerchantReferenceCode", myVariable)
request.Add("InvoiceNumber", 12345)
request.Add("TimeoutMinutes", 5)
request.Add("ShowAddress", True)
request.Add("AddressRequired", True)
request.Add("TransactionTotal", 33.33)
request.Add("TaxTotal", 2.00) ' taxation is theft
request.Add("CustomerCode", 12345)
Dim myJson = request.ToString()
Example: https://dotnetfiddle.net/FQDpVq
The short answer to the question you asked:
myjson = myjson.replace("VALUEPLACEHOLDER1","SoMeTHiNGeLSe")
Now, if you are talking about tricky pattern matching, then you will need to use regex if you want to approach this from a string-manipulation perspective. That sets you up for all sorts of unanticipated problems down the road with things you didn't anticipate, though, and you'll probably be happier in the long run if you embrace using JSON.
Try using the NewtonSoft JSON libraries. Then you can do something like:
dim myobj as new MyClass
myobj = jsonconvert.deserializeobject(of MyClass)(myjson)
That will turn your JSON string into an instance of MyClass called myobj, and you can access its properties directly, changing whatever you want:
myobj.MerchantReferenceCode = "SpecialMerchant"
Note that if the class definition for MyClass has properties that the JSON has no values for, they'll be present in the new class instance with no values. You can then set those values as you wish.
If the JSON has properties that don't exist in your class, they'll be dropped/lost in the conversion, so you do need to study your source data.
And you turn it back into a string again easily:
dim newjson as string = jsonconvert.serializeobject(myobj)

JSON to DataTable net with varing roots

This is my first dealing with JSON and unfortunately I have to do it in VB.Net, company policy. So I have searched high and low and tried a lot of examples even converted some of the C# code to VB.Net but I can't seem to find a complete solution.
I receive a JSON string like this:
{
"65080007":{
"partNo":"ATD000007",
"description":"Swingarm Hat Platform",
"quantity":4,
"assemblyseq":""
},
"65080143":{
"partNo":"ATD000143",
"description":"ASY Gas Spring Bracket",
"quantity":2,
"assemblyseq":""
},
"65080071":{
"partNo":"ATD000071",
"description":"TT Gas Spring",
"quantity":2,
"assemblyseq":""
},
"65080147":{
"partNo":"ATD000147",
"description":"ASY Lateral Hinge",
"quantity":8,
"assemblyseq":""
},
"65085181":{
"partNo":"RD0181",
"description":"ASY KIT Bolt, Carriage, 0.375 in x 16, 1.5 in (x45) & Nut, Flange, 0.375 in x 16 (x45)",
"quantity":1,
"assemblyseq":""
},
"65080796":{
"partNo":"ATD000796",
"description":"Decal, TT Equipped, Rectangular, 5 in x 10 in",
"quantity":1,
"assemblyseq":""
},
"65080797":{
"partNo":"ATD000797",
"description":"Decal, TT Open/Close, Triangular, 12 in x 8 in",
"quantity":1,
"assemblyseq":""
},
"65080745":{
"partNo":"ATD000745",
"description":"",
"quantity":1,
"assemblyseq":""
}
}
What I need to do bind or assign this data to a DataGridView.DataSource.
I've seen some examples but I can't set it as a DataSource.
I've tried this example:
Sub Main()
Dim json_result = GetJson()
Dim table = JsonConvert.DeserializeAnonymousType(json_result, (DataTable))
Dim newJString = Newtonsoft.Json.JsonConvert.SerializeObject(table, Newtonsoft.Json.Formatting.Indented)
Console.WriteLine("Re-serialized JSON: ")
Console.WriteLine(newJString)
Console.WriteLine("")
End Sub
Public Function GetJson() As String
Dim json_result As String = <![CDATA[
' I used the above json string
Return json_result
End Function
I have made my JSON classes to deserialise the JSON and tried JsonConvert.Deserialize keep getting an error it epected a array and found an object.
Public Class Jobs
'<JsonProperty("partno")>
Public Property PartNo As String
' <JsonProperty("description")>
Public Property Description As String
'<JsonProperty("quantity")>
Public Property Quantity As String
'<JsonProperty("assemblyseq")>
Public Property Assemblyseq As String
End Class
The issue I think is the root properties "65080797" these numbers will not be the same every time we get the JSON back from NetSuite.
So I tried to:
Dim obj = JsonConvert.DeserializeObject(Of Jobs)(result)
Console.WriteLine(obj.PartNo) it comes out PartNo = nothing
So I've tried this:
Dim resultA = JsonUtil.Deserialize(Of Jobs)(result, ignoreRoot:=True)
Module JsonUtil
Function Deserialize(Of T As Class)(ByVal json As String, ByVal ignoreRoot As Boolean) As T
Return If(ignoreRoot, JObject.Parse(json)?.Properties()?.First()?.Value?.ToObject(Of T)(), JObject.Parse(json)?.ToObject(Of T)())
End Function
End Module
This gives me the first group:
ATD000007
Swingarm Hat Platform
4
The assembly number was blank.
I'm open for any suggestions on how I can get the above JSON into a data table or DataGridView or how to make a list without the root "65080797" this number will be unique with every response.
The people that designed this response string refuses to remove the root properties.
Thank you for taking the time to read this mess.
All comments/suggestions are appreciated.
Yes, Json array looks like [something] instead of {somthing}, you could convert it to array if you want but you can also do it in different ways and even without any external library, you could create a datatable then bind it to datagridview or you could add data directly to datagridview.
Anyway, I made a datatable for you.
Imports System.Web.Script.Serialization 'for reading of JSON (+add the reference to System.Web.Extensions library)
Dim JSONC = New JavaScriptSerializer().Deserialize(Of Dictionary(Of String, Dictionary(Of String, String)))(JSON) 'you could do it in different ways too
Dim NewDT As New DataTable
'Create Columns
For Each key In JSONC.First.Value.Keys
'"65080007" <first
'{ "partNo":"ATD000007", "description":"Swingarm Hat Platform", "quantity":4, "assemblyseq":"" } <first.value
' "partNo" <first.value.key(s) :"ATD000007" <first.value.value(s)
NewDT.Columns.Add(key)
Next
'Add Rows
For Each item In JSONC
NewDT.Rows.Add(item.Value.Values.ToArray)
Next
DataGridView1.DataSource = NewDT
If you have unusually structured JSON like that, your best bet is probably to resort to using raw JObject and JToken handling instead of trying to get JSON.NET to deserialize into structured data automatically.
Create a method that will convert an individual JToken into the Job class you described in your question. I've added a Key property to identify those unique keys in the JSON that were problematic for you; if you don't need these, just remove the .Key bit from the example below.
Public Function CreateJob(data As JToken)
Return New Job With
{
.Key = data.Path,
.PartNo = data("partNo"),
.Description = data("description"),
.Quantity = data("quantity"),
.Assemblyseq = data("assemblyseq")
}
End Function
Once you have Job objects being created, you can walk the entire structure and turn it into an array of jobs with the sample code below.
Dim result As JObject = JsonConvert.DeserializeObject(json)
Dim jobs As Job() = result.Values().Select(Of Job)(AddressOf CreateJob).ToArray()
Once you have an array of Job objects, binding to a DataSource should be trivial.

What is wrong with this 1 line code?

dim json2=Newtonsoft.Json.Linq.JObject.Parse("[{""currency_code"":""1ST"",""cash"":""0"",""reserved"":""0""},{""currency_code"":""8BT"",""cash"":""0"",""reserved"":""0""}]")
The doublequotes are just escape characters. The actual string is
[{"currency_code":"1ST","cash":"0","reserved":"0"},{"currency_code":"8BT","cash":"0","reserved":"0"}]
Which as you can see is a legitimate json.
Basically it looks like a legitimate json array. I want to turn that into an array of strings
Basically I want to turn that into
{
"{""currency_code"":""1ST"",""cash"":""0"",""reserved"":""0""}",
"{""currency_code"":""8BT"",""cash"":""0"",""reserved"":""0""}"
}
First I parse that into a jobject andd............ I failed.
It's a legitimate json. Why I can't parse that into a jobject?
Some background.
I created 2 json helper function to help me parse any json. One convert json to dictionary. Another parse json into array. In fact, the whole json, is either dictionary (nested or not nested) or array (nested or not nested). Am I correct with this one?
Now the codes are:
Public Shared Function jObjectToDictionary(json As String) As Generic.Dictionary(Of String, String)
Dim json1 = JObject.Parse(json)
Dim dict = json1.ToObject(Of Generic.Dictionary(Of String, Object))
Dim dict2 = dict.ToDictionary(Function(x) x.Key, Function(x) x.Value.ToString)
Return dict2
End Function
Public Shared Function jObjectToArray(json As String) As Generic.List(Of String)
Dim json2 = JObject.Parse(json)
Dim ar = json2.ToObject(Of Generic.List(Of Object))
Dim ar2 = ar.ConvertAll(Function(x) x.ToString)
Return ar2
End Function
The code sort of works.
I then did
Dim jsonar = jsonHelper.jObjectToDictionary(_jsonResult)(starttoken) 'works
Dim ar1 = jsonHelper.jObjectToArray(jsonar) 'doesn't work
Then I examine why jObjectToArray doesn't work and it leads to this one line code that I think should work but doesn't.
That's what I ask. If you can fix this problem of that one line code, I can figure the rest out.
The reason that JObject.Parse is failing is because your JSON represents an array of objects, not just a single object. You can tell because the JSON begins and ends with square brackets [ and ], as opposed to curly braces { and } which denote a single object. To parse an array, you need to use JArray.Parse. (Note you can also use JToken.Parse -- that will parse either a single object or an array.)
Dim json2 = Newtonsoft.Json.Linq.JArray.Parse("[{""currency_code"":""1ST"",""cash"":""0"",""reserved"":""0""},{""currency_code"":""8BT"",""cash"":""0"",""reserved"":""0""}]")
Demo fiddle: https://dotnetfiddle.net/hZlc3m

Separate JSON objects with JSON.NET (vb)

I am having trouble separating pieces of a JSON object. Inside the json string there are 3 objects. One is called "JSONData", which I need to separate into its own object. I have tried so many things I'm starting to lose track. Two of which that seems to have been most helpful are below. However, they both end up empty. No errors, just empty. Hopefully someone can help!!
Dim j As String = JsonConvert.SerializeXmlNode(xml) 'Started out as XML
Dim o As JObject = JsonConvert.DeserializeObject(j) 'Then Json String to JObject
Dim channel As JObject = DirectCast(o("JSONData"), JObject) 'Try #1 to separate
'/// or
Dim jsondata As String = o.Item("JSONData") 'Try #2
'/// i have tried both above with ("IMSXMLLog.JSONData") as well. Same Result.
https://jsfiddle.net/jharris8567/v23kj42v/ - Full JSON
JSONData is inside another object IMSXMLLog, so your inclination to use the path IMSXMLLog.JSONData is correct. However, the indexer on JToken does not support paths, only single property names. To use path syntax you need to use the SelectToken method:
Dim data as JObject = DirectCast(o.SelectToken("IMSXMLLog.JSONData"), JObject)
Fiddle: https://dotnetfiddle.net/Wu70Tu

Better way to deserialize Minecraft json

I am trying to work with Minecraft json from (1.8.json download). A Sample:
{
"objects": {
"realms/lang/de_DE.lang": {
"hash": "729b2c09d5c588787b23127eeda2730f9c039194",
"size": 7784
},
"realms/lang/cy_GB.lang": {
"hash": "7b52463b2df4685d2d82c5d257fd5ec79843d618",
"size": 7688
},
"minecraft/sounds/mob/blaze/breathe4.ogg": {
"hash": "78d544a240d627005aaef6033fd646eafc66fe7a",
"size": 22054
},
"minecraft/sounds/dig/sand4.ogg": {
"hash": "37afa06f97d58767a1cd1382386db878be1532dd",
"size": 5491
}
}
}
The actual json is much longer, some 2940 lines.
I need a way to deserialize this that isn't completely insane - using JSONUtils I get 4411 Lines of Code, but the same code can't be used for any other version of Minecraft.
The automated tools can be very useful, but they are not perfect - especially when it comes to dictionaries.
The first thing to note is that the structure is the same for all of them, that is they all consist of hash and size properties. This means rather than creating hundreds of identical classes we can use the same one over and over:
' the type that repeats from your robot:
Public Class MinecraftItem
Public Property hash As String
Public Property size As Int32
End Class
Since the automated tools are working on the fly (they do not look ahead...or back) they don't really know that they are all the same. The next thing is that the classes the robots generate wont work in this case:
Public Property minecraft/sounds/music/game/creative/creative3.ogg As _
MinecraftSoundsMusicGameCreativeCreative3Ogg
That is illegal as a property name. However, the names will work just fine as Dictionary keys. In addition to the above MinecraftItem class, we might want a container class:
Public Class MinecraftContainer
Public objects As Dictionary(Of String, MinecraftItem)
End Class
There are (at least) 3 ways to get at the data:
Method 1: Pluck out a single item
Imports Newtonsoft.Json
Imports Newtonsoft.Json.Linq
Dim jstr As String = ...from whereever
' parse the json into a JObject
Dim js As JObject = JObject.Parse(jstr)
' if you somehow know the names, you can pluck out the data:
Dim mi = js("objects")("minecraft/sounds/mob/blaze/hit2.ogg")
Console.WriteLine(mi("hash").ToString & " " & mi("size").ToString)
The first line parses the original json string into a JObject. This allows us to work with the contents in various ways. For instance, we can reference "objects" in the json and them the items by name, which is exactly what happens in the next line:
' drill into "objects", get the "...hit2.ogg" item
Dim mi = js("objects")("minecraft/sounds/mob/blaze/hit2.ogg")
This will work if you just need to fetch a particular item from the big file. The mi variable created is a "special" json token, so use the names to get the data bits you want
hash = mi("hash").ToString
size = mi("size").ToString
Method 2: Deserialize To a Dictionary
This would be my preferred method. Include the same Import statements as in the first example, then:
' parse the json string
Dim js As JObject = JObject.Parse(jstr)
' deserialize the inner "objects" to a NET Dictionary
Dim myItems = JsonConvert.DeserializeObject(Of Dictionary(Of String, _
MinecraftItem))(js("objects").ToString)
This will create myItems as a Net Dictionary(Of String, MincraftItem) from the json. Since the MinecraftObject class doesn't do anything but hold the dictionary, we skipped it.
The keys are the long names and each value is a MinecraftItem which allows you to reference them more conventionally:
' get one of the items into a variable
gravel3 = myItems("minecraft/sounds/mob/chicken/step2.ogg")
ConsoleWriteLine("Gravel3 hash: {0}, size: {1}",
gravel3.hash, gravel3.size.ToString)
If you are not familiar with the .Net Dictionary it is somewhat like an array or List except you access your items by a Key rather then index. To loop thru them all:
Dim n As Integer = 0
For Each kvp As KeyValuePair(Of String, MinecraftItem) In myItems
Console.WriteLine("Name: {0} Hash: {1} size: {2}",
kvp.Key,
kvp.Value.hash,
kvp.Value.size.ToString)
n += 1
If n >= 2 Then Exit For ' just print 3
Next
Output:
Name: realms/lang/de_DE.lang Hash: 10a54fc66c8f479bb65c8d39c3b62265ac82e742 size: 8112
Name: realms/lang/cy_GB.lang Hash: 14cfb2f24e7d91dbc22a2a0e3b880d9829320243 size: 7347
Name: minecraft/sounds/mob/chicken/step2.ogg Hash: bf7fadaf64945f6b31c803d086ac6a652aabef9b size: 3838
Just remember, the Key will always be the long path name, and each .Value is MinecraftItem object.
Method 3: Deserialize To a Container
You can skip the parsing step by using the MinecraftContainer class:
Dim jstr As String = ...from whereever
Dim myJItems = JsonConvert.DeserializeObject(Of MinecraftContainer)(jstr)
Note that this time, you pass the entire string you downloaded to JsonConvert. The result will be an extra outer object which contains a dictionary property named "Objects". So, you reference the items using some leading references:
gravel3hash = myJItems.Object("minecraft/sounds/dig/gravel3.ogg").hash
gravel3 = myJItems.Object("minecraft/sounds/dig/gravel3.ogg")
ConsoleWriteLine("Gravel3 hash: {0}, size: {1}",
gravel3.hash, gravel3.size.ToString)
'or:
ConsoleWriteLine("Gravel3 hash: {0}, size: {1}",
myJItems.Object("minecraft/sounds/dig/gravel3.ogg").hash,
myJItems.Object("minecraft/sounds/dig/gravel3.ogg").size.ToString)
This method is just one line of code to deserialize, but it means
a) I have to define the container class and
b) I have to use myJItems.Object to drill into the otherwise empty container to get at the Dictionary.
Personally, I would forego this and use method 2 - one extra line of code makes it a bit easier to work with. That said, you can also extract the dictionary collection from the container:
Dim myItems As Dictionary(Of String, MinecraftItem)= myJItems.Object