WCF VB serialize twice - json

I have a WCF service with Visual Basic code (below), I need the table that getAdministrationData() returns, and Newtonsoft serializer offers me what I need, so I just don't figure out how to make that the service returns me that, and not an object serialized twice.
<OperationContract()> _
<WebInvoke(Method:="POST", _
RequestFormat:=WebMessageFormat.Json, _
BodyStyle:=WebMessageBodyStyle.Wrapped, _
UriTemplate:="getAdministrationDataTree")> _
Public Function getAdministrationDataTree() As String
Dim myAdmManager As New AdministrationManager()
Dim model As DataSet = myAdmManager.getAdministrationData()
Dim json As String = JsonConvert.SerializeObject(model)
Return json
End Function
Hope you guys throw me some light at this, and sorry for the sloppy English.

In your interface class, you should declare definitions as below:-
<OperationContract()>
<WebGet(ResponseFormat:=WebMessageFormat.Json, BodyStyle:=WebMessageBodyStyle.Wrapped, UriTemplate:="getAdministrationDataTree")>
Public Function getAdministrationDataTree() As AdminData
You also need to define a data contract like below:-
Class AdminData
<DataMember()>
Public Property AdminDataField1 as String
'Define any properties you need
End Class
Then in definition class implement your method as below:-
Public Function getAdministrationDataTree() As AdminData
Dim myAdmManager As New AdministrationManager()
Dim model As DataSet = myAdmManager.getAdministrationData()
'Create an AdminData object and fill it with values you want to return
return AdminData
End Function
You will receive a JSON object.
If you can provide more details about your the data then I can give you exact code.

Related

How to parse a big JSON

I'm trying to parse a big JSON and I only need few things from it.
I've been trying to beautify it but I'm having trouble also because it seems that's not completely correct.
This is the website
and I've tried to delete all the unnecessary json
ending up with
[
[
"updateGlobalData",
{
"backgroundData":{
"cities":[
{
"type":"city",
"name":"Polis",
"id":186979,
"level":35,
"ownerId":"99253",
"ownerName":"D3vil666",
"ownerAllyId":"0",
"hasTreaties":0,
"actions":[
],
"state":"vacation",
"viewAble":1,
"infestedByPlague":false
},
{
"type":"city",
"name":"London",
"id":378440,
"level":28,
"ownerId":"242906",
"ownerName":"Mattia",
"ownerAllyId":"5541",
"ownerAllyTag":"LORDS",
"hasTreaties":0,
"actions":[
],
"state":"",
"viewAble":2,
"infestedByPlague":false
}
]
}
}
]
]
The properties I'm looking for are "State" and "ownerName".
State can be "vacation" like ""state"": ""vacation"" or "" like ""state"": """"
These properties are often repeated so I'm only looking for to parse them only once.
For example:
I want to know which state Mattia has and it should return "nothing".
Which state D3vil666 has and it should return "vacation".
The code I'm using:
Public Class Form1
Public Class GlobalData
Public Class BackgroundData
Public Property Cities As List(Of City)
End Class
Public Class City
Public Property Type As String
Public Property Name As String
Public Property OwnerName As String
Public Property State As String
End Class
Public Property BackgroundDataa As BackgroundData
End Class
Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
Dim client As New WebClient()
Dim jsonString As String = client.DownloadString("https://s10-it.ikariam.gameforge.com/?view=updateGlobalData&islandId=1649&backgroundView=island&currentIslandId=1649&actionRequest=90983fef22b312ff7cbd51f0183bc301&ajax=1")
Dim data As List(Of GlobalData) = JsonConvert.DeserializeObject(Of List(Of GlobalData))(jsonString)
Dim state = data(0).BackgroundDataa.Cities.FirstOrDefault(Function(x) x.OwnerName = "Mattia").State
MsgBox(state)
End Sub
End Class
but I'm getting the error:
Newtonsoft.Json.JsonSerializationException: 'Cannot deserialize the current JSON array (e.g. [1,2,3]) into type 'Ikariam_VM.Form1+GlobalData' because the type requires a JSON object (e.g. {"name":"value"}) to deserialize correctly.
To fix this error either change the JSON to a JSON object (e.g. {"name":"value"}) or change the deserialized type to an array or a type that implements a collection interface (e.g. ICollection, IList) like List that can be deserialized from a JSON array. JsonArrayAttribute can also be added to the type to force it to deserialize from a JSON array.
Path '[0]', line 1, position 2.'
I'm working on winform App for .net6+ and using the nuget Newtonsoft package to handle the json.
Any idea?
Thanks
edit1:
Code after suggestions
Imports System.Net
Imports System.Net.Http
Imports System.Net.WebRequestMethods
Imports System.Runtime.InteropServices.JavaScript.JSType
Imports System.Text.Json
Imports Microsoft.Web.WebView2.Core
Imports Microsoft.Web.WebView2
Imports Microsoft.Web.WebView2.WinForms
Imports System.Threading
Imports System.IO
Imports System.Runtime.InteropServices.JavaScript
Imports Newtonsoft.Json.Linq
Imports Newtonsoft.Json
Public Class Form1
Public Class GlobalData
Public Class BackgroundData
Public Property Cities As List(Of City)
End Class
Public Class City
Public Property Type As String
Public Property Name As String
Public Property OwnerName As String
Public Property State As String
End Class
End Class
Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
Dim client As New WebClient()
Dim jsonString As String = client.DownloadString("https://s10-it.ikariam.gameforge.com/?view=updateGlobalData&islandId=1649&backgroundView=island&currentIslandId=1649&actionRequest=90983fef22b312ff7cbd51f0183bc301&ajax=1")
Dim jArr = JArray.Parse(jsonString)
Dim cities = TryCast(jArr(0).OfType(Of JObject)() _
.Select(Function(p) p.Properties().Where(Function(p) p.Name = "backgroundData").First()) _
.FirstOrDefault().Value("cities"),
JArray)
Dim state As String = Nothing
If cities IsNot Nothing Then
state = CStr(cities.Where(Function(c) CStr(c("OwnerName") = "D3vil666")) _
.FirstOrDefault()("state"))
End If
End Sub
End Class
You don't need any custom classes to get data you need from a json string you posted. I haven't a VB.Net compillator so I post my code in c#. I hope you will find somebody to tranclate it to VB.Net
var jArr = JArray.Parse(json);
var cities = jArr[0].OfType<JObject>()
.Select(p => p.Properties().Where(p => p.Name == "backgroundData").First())
.FirstOrDefault().Value["cities"] as JArray;
string state=null;
if (cities != null)
state = (string)cities.Where(c => (string)c["ownerName"] == "D3vil666")
.FirstOrDefault()["state"]; // "vacation"
Serge's answer, translated into VB:
Dim jArr = JArray.Parse(json)
Dim cities = TryCast(jArr(0).OfType(Of JObject)() _
.Select(Function(p) p.Properties().Where(Function(q) q.Name = "backgroundData").First()) _
.FirstOrDefault().Value("cities"),
JArray)
Dim state As String = Nothing
If cities IsNot Nothing Then
state = CStr(cities.Where(Function(c) CStr(c("OwnerName") = "D3vil666")) _
.FirstOrDefault()("state"))
End If
I think this is a spot where VB still needs the continuation characters to handle the lines properly.

JsonConvert.DeserializeObject knowing class name (string)

I've a vb.net class that includes some serializable sub-classes
Public Class Model
<Serializable>
Public class foo
Public Property id as Integer
Public Property name as String
End Class
<Serializable>
Public Class bar
Public Property grading as Integer
Public Property minWage as Decimal
Public Property maxWage as Decimal
End Class
End Class
Now I receive from a web service, an object (as json formated string) and its class name (as string) and I'd like to Deserialize it as my object.
I could do, as it is actually working, a
Imports Newtonsoft.Json
Public Shared Function Deserialize(ByVal Json As String, ByVal name As String) As Object
Select Case name
Case "foo"
Return JsonConvert.DeserializeObject(of Model.foo)(Json)
Case "bar"
Return JsonConvert.DeserializeObject(of Model.bar)(Json)
End Select
End Function
But as you can imagine, I've a ton of classes, not just 2, so I tried to use Reflection
Imports System.Reflection
Imports Newtonsoft.Json
Public Shared Function Deserialize(ByVal Json As String, ByVal name As String) As Object
Dim assembly As Assembly = Assembly.GetAssembly(GetType(Model))
Dim type As Type = assembly.[GetType]("Model." & name) ' Why is this always Nothing?
Dim objInstance As Object = Activator.CreateInstance(type)
' objInstance = JsonConvert.DeserializeObject(Of ???)(Json)
Return objInstance
End Function
But on one hand the type variable is always Nothing, and on the other hand, I don't know what to put instead of the comment.
Can you please advise ?
You need to add the Namespace where the Model class is defined.
A nested class is separated by a +, so you have to add that to the full name of the Class object you want to create.
The composed string is then "[Namespace].[ClassName]+[NestedClassName]"
You don't need to create the instance, the Json Serializer will do that for you. Pass the Type of the class to the JsonConvert.DeserializeObject() method that accepts a Type as the second parameter.
Public Shared Function Deserialize(Json As String, className As String) As Object
Dim asm = Assembly.GetAssembly(GetType(Model))
Dim t As Type = asm.GetType($"{asm.GetName().Name}.Model+{className}")
Return JsonConvert.DeserializeObject(Json, t)
End Function
How you're going to use this, it's up to you :)
More generic:
Public Shared Function Deserialize(Of T)(Json As String, className As String) As Object
Dim asm = Assembly.GetAssembly(GetType(T))
Dim t1 As Type = asm.GetType($"{asm.GetName().Name}.{GetType(T).Name}+{className}")
Return JsonConvert.DeserializeObject(Json, t1)
End Function
Call as:
Dim deserialized = Deserialize(Of Model)(Json, "foo")
I've partially solve my problem, I can now crerate the right object, like so
Dim objType As Type = (From asm In AppDomain.CurrentDomain.GetAssemblies() From type In asm.GetTypes() Where type.IsClass AndAlso type.Name = name Select type).Single()
Dim objInstance As Object = Activator.CreateInstance(objType)
This is my final, working function, thanks to Jimi!
Public Shared Function Deserialize(ByVal Json As String, ByVal name As String) As Object
Try
Dim objType As Type = (From asm In AppDomain.CurrentDomain.GetAssemblies() From type In asm.GetTypes() Where type.IsClass AndAlso type.Name = name Select type).Single()
Return JsonConvert.DeserializeObject(Json, objtype)
Catch ex As Exception
Throw New Exception("Unknown class")
End Try
End Function

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

Parse Simple JSON with VB.NET

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)