JSON deserialization error with Azure translation services - json

I am building a program in Visual Studio 2017 in Windows Forms - sorry but that's the only thing I know how to use - anyway, most everything for this is C#, so I've been having trouble getting help.
I have translated the Microsoft provided example for a C# program to connect to Azure Cognitive Translation services, signed up, got all my keys, etc.
When I run the code, I get the following error:
Newtonsoft.Json.JsonSerializationException:
'Cannot deserialize the
current JSON object (e.g. {"name":"value"}) into type
System.Collections.Generic.List1[System.Collections.Generic.Dictionary2[System.String,System.Collections.Generic.List1[System.Collections.Generic.Dictionary2[System.String,System.String]]]]'
because the type requires a JSON array (e.g. [1,2,3]) to deserialize
correctly.
To fix this error either change the JSON to a JSON array
(e.g. [1,2,3]) or change the deserialized type so that it is a normal
.NET type (e.g. not a primitive type like integer, not a collection
type like an array or List) that can be deserialized from a JSON
object. JsonObjectAttribute can also be added to the type to force it
to deserialize from a JSON object. Path 'error', line 1, position 9.'
I have tried too many things to list from many different sources. I do not know a whole lot about JSON and am asking for help with the code to solve the above issue.
Public Class DetectedLanguage
Public Property language As String
Public Property score As Double
End Class
Public Class Translation
Public Property text As String
Public Property two As String
End Class
Public Class Example
Public Property detectedLanguage As DetectedLanguage
Public Property translations As Translation()
End Class
Dim textToTranslate As String = root
Dim fromLanguage As String
Dim fromLanguageCode As String = cabbr
Dim toLanguageCode As String = "en"
Dim endpoint As String = String.Format(TEXT_TRANSLATION_API_ENDPOINT, "translate")
Dim uri As String = String.Format(endpoint & "&from={0}&to={1}", fromLanguageCode, toLanguageCode)
Dim body As System.Object() = New System.Object() {New With {Key .Text = textToTranslate}}
Dim requestBody = JsonConvert.SerializeObject(body)
Using client = New HttpClient()
Using request = New HttpRequestMessage()
request.Method = HttpMethod.Post
request.RequestUri = New Uri(uri)
request.Content = New StringContent(requestBody, Encoding.UTF8, "application/json")
request.Headers.Add("Ocp-Apim-Subscription-Key", COGNITIVE_SERVICES_KEY)
request.Headers.Add("Ocp-Apim-Subscription-Region", "westus")
request.Headers.Add("X-ClientTraceId", Guid.NewGuid().ToString())
Dim response = client.SendAsync(request).Result
Dim responseBody = response.Content.ReadAsStringAsync().Result
Dim result = JsonConvert.DeserializeObject(Of List(Of Dictionary(Of String, List(Of Dictionary(Of String, String)))))(responseBody)
Dim translation = result(0)("translations")(0)("text")
rtRoot.Text = translation
End Using
End Using
I have already used the jsonutil site to paste my JSON code in and get the classes.
Here is my JSON content:
[
{
"detectedLanguage":{
"language":"nl",
"score":1.0
},
"translations":[
{
"text":"bord vervangen en uitvoerig getest",
"to":"nl"
},
{
"text":"Board replaced and tested extensively",
"to":"en"
}
]
}
]

OK!!! after playing around with this - Jimi - your solution worked!!! thank you SO much! i had to remove the following to lines: request.Headers.Add("Ocp-Apim-Subscription-Region", "westus") request.Headers.Add("X-ClientTraceId", Guid.NewGuid().ToString())

Related

How to extract a specific object from a JSON?

I would like to know how to extract a specific object from a JSON.
I saw most of the problem solved on Stackoverflow before posting this, but there is no one who already talked about this.
I want need to get the slug value from the JSON objects.
Here is my code Get Users From JSON
Imports System
Imports Newtonsoft.Json.Linq
Public Module Module1
Public Sub Main()
Dim myJsonString = New System.IO.StreamReader(New System.Net.WebClient().
OpenRead("https://pastebin.com/raw/z4GZFuF3")).ReadToEnd()
Dim myJObject = JObject.Parse(myJsonString)
For Each match In myJObject("matches")
Console.WriteLine(match("id")("slug"))
Next
End Sub
End Module
And Here is the Output:
Run-time exception (line -1): Error reading JObject from JsonReader.
Current JsonReader item is not an object: StartArray. Path '', line 1, position 1.
Stack Trace:
[Newtonsoft.Json.JsonReaderException: Error reading JObject from JsonReader.
Current JsonReader item is not an object: StartArray. Path '', line 1, position 1.]
at Newtonsoft.Json.Linq.JObject.Load(JsonReader reader, JsonLoadSettings settings)
at Newtonsoft.Json.Linq.JObject.Parse(String json, JsonLoadSettings settings)
at Newtonsoft.Json.Linq.JObject.Parse(String json)
at Module1.Main()
What I have reduced since this error is that the object "matches" does not exist in the JSON text, but I have no idea what I should specify in its place to make this work.
The JSON that can be retrieved from the provided address:
(http://www.stginternational.org/wp-json/wp/v2/users)
is an array of Objects.
It can be parsed using JArray.Parse(), but I suggest to deserialize this JSON as .Net classes: it's much easier to handle.
The JSON's base object (each object in the array) is defined like this:
{
"id": 1,
"name": "drall",
"url": "",
"description": "",
"link": "http://www.stginternational.org/author/drall/",
"slug": "drall",
"avatar_urls": {
"24": "http://1.gravatar.com/avatar/dc6dd0ef71784957b629e124f19364cb?s=24&d=mm&r=g",
"48": "http://1.gravatar.com/avatar/dc6dd0ef71784957b629e124f19364cb?s=48&d=mm&r=g",
"96": "http://1.gravatar.com/avatar/dc6dd0ef71784957b629e124f19364cb?s=96&d=mm&r=g"
},
"meta": [],
"_links": {
"self": [
{
"href": "http://www.stginternational.org/wp-json/wp/v2/users/1"
}
],
"collection": [
{
"href": "http://www.stginternational.org/wp-json/wp/v2/users"
}
]
}
}
It can be represented by these .Net classes:
Public Class UserObject
Public Property Id As Long
Public Property Name As String
Public Property Url As String
Public Property Description As String
Public Property Link As Uri
Public Property Slug As String
<JsonProperty("avatar_urls")>
Public Property AvatarUrls As Dictionary(Of String, Uri)
Public Property Meta As List(Of Object)
<JsonProperty("_links")>
Public Property Links As Links
End Class
Public Class Links
Public Property Self As List(Of LinkCollection)
Public Property Collection As List(Of LinkCollection)
End Class
Public Class LinkCollection
Public property Href As Uri
End Class
With this model, you can simply use JsonConvert.DeserializeObject(), specifying the Type to deserialize to.
As mentioned, this is an Array or List of objects, where the base object is an UserObject, so you can specify a List(Of UserObject) :
Dim json = JsonConvert.DeserializeObject(Of List(Of UserObject))(json)
You can then access the class object as usual:
Imports System.Net
Imports Newtonsoft.Json
Dim users As List(Of UserObject) = Nothing
Using client As New WebClient()
Dim json = client.DownloadString([The URL])
users = JsonConvert.DeserializeObject(Of List(Of UserObject))(json)
End Using
If users IsNot Nothing Then
For Each user In users
Console.WriteLine(user.Slug)
Console.WriteLine(user.Links.Self(0).Href)
Console.WriteLine(user.Links.Collection(0).Href)
For Each avatar In user.AvatarUrls
Console.WriteLine($"Key: {avatar.Key}, Value: {avatar.Value}")
Next
Next
End If
In case you just want one of the properties (slug, in this case), you can use JArray.Parse() to parse the JSON and read the property value directly:
Using client As New WebClient()
Dim json = client.DownloadString([The URL])
Dim users = JArray.Parse(json)
For Each user As JToken In users
Console.WriteLine(user("slug"))
Next
End Using
While Jimi's answer is preferable because it deserializes the JSON into a strongly typed object, here is an alternative since you only care about getting a single property from the array of objects.
It does the following three steps:
Get the JSON from the endpoint
Convert the JSON literal into JArray
Use LINQ to get just the Slug item of each object in the array
Dim myJsonString = New System.IO.StreamReader(New System.Net.WebClient().OpenRead("http://www.stginternational.org/wp-json/wp/v2/users")).ReadToEnd
Dim arrayOfObjects = JArray.Parse(myJsonString)
Dim arrayOfSlugs = From jsonObject In arrayOfObjects Select jsonObject.Item("slug")
Example: Live Demo

Deserializing JSON into a List (or other object type)

I am having issues deserializing some JSON into an object type that I can work with.
I have been playing around with multiple different ways to deserialize something, but I cannot get any of them to work. I am trying, currently, to use the Newtonsoft.Json deserializer.
Public Class ServerRecord
Inherits Record
<Newtonsoft.Json.JsonProperty("sys_class_name")>
Public Property sys_class_name As String
Get
End Get
Set(value As String)
End Set
End Property
<Newtonsoft.Json.JsonProperty("host_name")>
Public Property host_name As String
Get
End Get
Set(value As String)
End Set
End Property
<Newtonsoft.Json.JsonProperty("u_recovery_time_achievable")>
Public Property u_recovery_time_achievable As String
Get
End Get
Set(value As String)
End Set
End Property
End Class
Dim lstSNServersList As New List(Of ServerRecord)
Dim objServiceNowTableAPIClient As TableAPI.TableAPIClient(Of ServerRecord)
Dim objServiceNowRESTQueryResponse As RESTQueryResponse(Of ServerRecord)
objServiceNowTableAPIClient = New TableAPIClient(Of wServerRecord)(strServiceNowCMDBServersTableName, strServiceNowInstanceName, strServiceNowUser, strServiceNowPassword)
strServiceNowQuery = "sys_class_name=cmdb_ci_win_server^ORsys_class_name=cmdb_ci_linux_server"
objServiceNowRESTQueryResponse = objServiceNowTableAPIClient.GetByQuery(strServiceNowQuery)
'this much does work and it does return a result set
'this is my attempt to convert this response into a list of ServerRecords, but this does not work currently:
lstSNServersList = JsonConvert.DeserializeObject(Of List(Of ServerRecord))(objServiceNowRESTQueryResponse.RawJSON)
The objServiceNowRestQueryResponse.RawJSON string looks like this (though much longer):
{
"result":[
{
"sys_id":"00040665dbxxxxxx96191e",
"u_recovery_time_achievable":"720",
"sys_class_name":"cmdb_ci_linux_server",
"host_name":"rlserver001"
},
{
"sys_id":"00ec543d1xxxx66e4bcb6d",
"u_recovery_time_achievable":"4",
"sys_class_name":"cmdb_ci_linux_server",
"host_name":"plserver001"
},
{
"sys_id":"0105d975dbxxxxx8961998",
"u_recovery_time_achievable":"",
"sys_class_name":"cmdb_ci_linux_server",
"host_name":"tlserver001"
}
]
}
This is the error message I get when trying to run my code:
Exception thrown: 'Newtonsoft.Json.JsonSerializationException' in
Newtonsoft.Json.dll
Additional information: Cannot deserialize the current JSON object
(e.g. {"name":"value"}) into type
'System.Collections.Generic.List`1[CMDBReconciliation.CMDBReconciliation+ServiceNowServerRecord]'
because the type requires a JSON array (e.g. [1,2,3]) to deserialize
correctly.
To fix this error either change the JSON to a JSON array (e.g.
[1,2,3]) or change the deserialized type so that it is a normal .NET
type (e.g. not a primitive type like integer, not a collection type
like an array or List) that can be deserialized from a JSON object.
JsonObjectAttribute can also be added to the type to force it to
deserialize from a JSON object.
Path 'result', line 1, position 10.
This will work. It just extracts the array part from the json string.
Dim start As Integer = objServiceNowRESTQueryResponse.IndexOf("[")
Dim last As Integer = objServiceNowRESTQueryResponse.LastIndexOf("]")
lstSNServersList = JsonConvert.DeserializeObject(Of List(Of ServerRecord))(objServiceNowRESTQueryResponse.Substring(start, last - start + 1))

Json conversion to double and bind to WPF nummericupdown fails

Currently i get an error on a binding. The situation is that i write my settings to a JSON file. When the app opens again the JSON file is read and used throughout the application. Now there's a strange thing: When i bind a double value to the value of a nummericupdown than i get an error: type 'JValue' to type 'System.Nullable1[System.Double]'for 'en-US' however this error doesn't occur when i recreate the JSON list and file. (simply said when i delete the file and restart the app it will create a new instance of a class en write it to disk)
Property in class:
Public Property SomeValue As Double
Write/Reader JSON:
'Write
Using _file As StreamWriter = New StreamWriter(SettingFilePath)
Dim serializer As New JsonSerializer()
serializer.Formatting = Formatting.Indented
serializer.Serialize(_file, Me)
End Using
'Read
Return JsonConvert.DeserializeObject(Of Settings)(File.ReadAllText(settingsfile))
JSON string:
"SomeValue": 1.0,
Binding in XAML:
<Controls:NumericUpDown
Width="200"
HorizontalAlignment="Center"
Maximum="5"
Minimum="1"
NumericInputMode="All"
Speedup="false"
Value="{Binding SomeValue}" />
Please note that i use the Mathapps Metro nummericupdown control version 1.6.5
Newtonsoft version 10.0.0.1 (Cannot update due to dependencies)
Edit:
As asked i digged deeper and now know where it starts, but don't know yet how to resolve it. Is start with my class for example:
Public class Hello
Dim a as Object
Dim b as EnumTypeOfObjectIn_A
Dim SomeOtherStuff as String
End class
Now when i DeserializeObject de file to the Class Hello then variable a becomes a object of type JObject and this is why alot of logica afterwords goes wrong. When i create the object in code everything goes well because the TypeOf object matches the one i put in. So is there a work arround for the Deserializer to convert the object to the one that is indicated in variable b ?
Found the solution i was looking for. The Newtonsoft JSON contains the JsonSerializerSettings class that helps the de/serialization process. For me it is important to add the Type of object when serializing so that's exactly what TypeNameHandling and TypeNameAssemblyFormatHandling is for in the Newtonsoft JSON assembly
I ended up with this code:
Public Class Hello
Public Property A As Object
Dim settingsfile As String = "C:\jsontest.json"
Public Sub Save()
Using _file As StreamWriter = New StreamWriter(settingsfile)
_file.Write(JsonConvert.SerializeObject(Me, Formatting.Indented, New JsonSerializerSettings() With {
.TypeNameHandling = TypeNameHandling.Objects,
.TypeNameAssemblyFormatHandling = TypeNameAssemblyFormatHandling.Simple
}))
End Using
End Sub
Public Function Load() As Hello
Return JsonConvert.DeserializeObject(Of Hello)(File.ReadAllText(settingsfile), New JsonSerializerSettings() With {.TypeNameHandling = TypeNameHandling.Objects})
End Function
End Class
Public Class Person
Public Property Name As String
Public Property Age As Integer
Sub New()
Me.Name = "John"
Me.Age = 130
End Sub
End Class
Producing this JSON output, note the $Type
{
"$type": "MyNamespace.Hello, MyNamespace",
"A": {
"$type": "MyNamespace.Person, MyNamespace",
"Name": "John",
"Age": 130
}
}

How to parse Poloniex Json into VB Net Object?

I'm currently pulling in the Poloniex returnCompleteBalances info in the following JSON format:
{"LTC":{"available":"5.015","onOrders":"1.0025","btcValue":"0.078"},"NXT:{...} ... }
I am trying to add the info to a class I made, and separate the different coins(property names) and their associated info. So far I have the following:
Sub GetBalances()
Dim method As String = calldata("returnCompleteBalances")
Dim allData As JObject = JObject.Parse(method)
Dim coinlist As New List(Of balancedata)
For Each token As JToken In allData("objects")
Dim prop As JProperty = token
coinlist.Add(New balancedata With {.Coin = prop.Name, .available = prop.Value("available"), .onOrders = prop.Value("onOrders"), .btcValue = prop.Value("btcValue")})
Next
End Sub
And the class
Public Class balancedata
Public Property Coin As String
Public Property available As Decimal
Public Property onOrders As Decimal
Public Property btcValue As Decimal
End Class
When I run the code, I receive an error on the for each token as Jtoken line that reads: "Object reference not set to an instance of an object"
How do I resolve this? I do not know all of the values for the property name, LTC, BTC, etc. so I am trying to look through them all and itemize the associated values into a list.

Cannot deserialize the current JSON object (e.g. {"name":"value"}) into type 'System.Collections.Generic.List`

I know there's already a bunch of these questions on SO but none of those answers is working for me. I've been on it all day now and I'm just fried so it's an easy win for the JSON people out there.
The error is
An unhandled exception of type 'Newtonsoft.Json.JsonSerializationException' occurred in Newtonsoft.Json.dll
Additional information: Cannot deserialize the current JSON object (e.g. {"name":"value"}) into type 'System.Collections.Generic.List`1[FrozenSmoke.WorkflowDescription]' because the type requires a JSON array (e.g. [1,2,3]) to deserialize correctly.
To fix this error either change the JSON to a JSON array (e.g. [1,2,3]) or change the deserialized type so that it is a normal .NET type (e.g. not a primitive type like integer, not a collection type like an array or List<T>) that can be deserialized from a JSON object. JsonObjectAttribute can also be added to the type to force it to deserialize from a JSON object.
Path 'Workflows', line 1, position 13.
The code is (VB.NET)
Dim z As New List(Of WorkflowDescription)
z = Newtonsoft.Json.JsonConvert.DeserializeObject(Of List(Of WorkflowDescription))(ResponseStatus.Content)
Here is the JSON I'm getting back from the server and is contained in ResponseStatus.Content
{"Workflows":[{"GUID":"594d2946-7bee-49b3-b8bf-e5ee6715a188","Name":"ProcessElectronicContribution"},{"GUID":"fe368a11-2b79-41f9-bee9-edb031612365","Name":"AddActivist"},{"GUID":"4c552492-0014-439d-952b-aeb320e6d218","Name":"AddPartialActivist"}]}
Here is the class
Public Class WorkflowDescription
Public Property Name As String = ""
Public Property GUID As String = ""
End Class
Your json is not simply an array/list but an object container which contains a Workflows property which is a list/array.
{"Workflows":[{"GUID": ....
Workflows is the List/Array but note that it is inside a brace. That is the "outer container".
Public Class WorkFlowContainer
Public Property WorkFlows As List(Of WorkflowItem)
End Class
Public Class WorkflowItem
Public Property Name As String
Public Property GUID As String
End Class
The WorkFlows element in the json will map to the property of the same name. You can get rid of the container after you deserialize:
' ultimate destination
Private myWorkFlows As List(Of WorkflowItem)
...
' elsewhere
Dim jstr = ... ` from whereever
' deserialize to the container
Dim wf = JsonConvert.DeserializeObject(Of WorkFlowContainer)(jstr)
' extract the list
myWorkFlows = wf.WorkFlows
You can ignore the WorkFlowContainer with an extra step in deseriazlizing:
Dim jstr = ... ` from whereever
Dim jopbj - JObject.Parse(jstr)
myWorkFlows = JsonConvert.DeserializeObject(Of List(Of WorkFlows))(jobj("Workflows"))
This way you dont have to define the extra class and dont have to use wf. to get at the data.
You probably know that most arrays can be deserialized as either a List or array. To define Workflows as a property array:
Public Property WorkFlows As WorkflowItem()