I dont really understand what I do wrong when I try to Deserialize the JSON stuff I get.
You can get the response from http://api.steampowered.com/ISteamApps/GetAppList/v2?format=json
Imports Newtonsoft.Json
Imports Newtonsoft.Json.Linq
Public Class Form1
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Dim SteamGameInfoObject As Object = JsonConvert.DeserializeObject(Of Object)(New System.Net.WebClient().DownloadString("http://api.steampowered.com/ISteamApps/GetAppList/v2?format=json"))
End Sub
Public Class SteamRootObject
Public Class SteamAPIJSONResult
Public Property applist As List(Of applistlist)
End Class
Public Class applistlist
Public Property apps As List(Of appslist)
End Class
Public Class appslist
Public Property appid As Integer()
Public Property name As String()
End Class
End Class
End Class
I dont know how to "To fix this error either change the JSON to a JSON array"
You have a few problems here:
You define appid and name as arrays of integers and strings, respectively. In the JSON these are primitive values not arrays, so the VB.NET properties themselves should be declared to be simple integers and strings.
You define applist as a List(Of applistlist). Despite the name, the property value in the JSON is a single object not an array, so the property should refer to a single object also.
In Form1_Load you need to deserialize to the correct type, SteamRootObject. If you do JsonConvert.DeserializeObject(Of Object)(jsonString) you are not telling Json.NET the type to which to deserialize!
Stylistically there is no need to nest the inner classes inside the root class, it adds to complexity.
There are plenty of on-line tools to auto-generate .Net classes from JSON that can be found quickly using google, for instance http://json2csharp.com/ (for c#) or http://jsonutils.com/ or http://www.httputility.net/json-to-csharp-vb-typescript-class.aspx. In the future, use one of these to check your work.
Thus your fixed classes should look like:
Public Class App
Public Property appid As Integer
Public Property name As String
End Class
Public Class Applist
Public Property apps As New List(of App)
End Class
Public Class SteamRootObject
Public Property applist As Applist
End Class
And, to deserialize:
Dim SteamGameInfoObject = JsonConvert.DeserializeObject(of SteamRootObject)(jsonString)
Prototype fiddle.
Related
I'm currently using Visual Basic for a College Project which requires us to make a simple database system. For my system I have a base(abstract) class called Record which is inherited by the different types of records there are in my database e.g. Member, User, Role.
I am saving my data in csv files and have already written a CSVHandler class. However, I want an elegant way of constructing an instance of a class derived from Record with a string from the CSVHandler.
This is where the problem occurs. The only way I can think of doing this is by making a Constrcutor or Shared Function in each class derived from Record. However, Visual Basic does not allow you make Constructors or Shared Functions also MustOverride.
Here is the code I would expect to write:
' Base Class
Public MustInherit Class Record
Public MustOverride Shared Function fromString(ByVal str as String) As Record
End Class
' Example Of Class Derived From Record
Public Class User
Inherits Record
Private _id As String
Private _name As String
Public Sub New(ByVal id As String, ByVal name As String)
_id = id
_name = name
End Sub
Public Overrides Shared Function fromString(ByVal str as String) As Record
Dim strs() As String = str.Split(",")
Return New User(strs(0), strs(1))
End Function
End Class
' Example Of Creating Instacnce Of User
Dim user1 = User.fromString("1671,Kappeh")
Is there a way to achieve this effect?
Have your constructor call a Protected MustOverride method that does the initialisation.
Public MustInherit Class Record
'This is required because each derived constructor must be able to implicitly invoke a parameterless
'base constructor if it doesn't explicitly invoke a base constructor with parameters.
Protected Sub New()
End Sub
Public Sub New(csv As String)
Init(csv)
End Sub
Protected MustOverride Sub Init(csv As String)
End Class
Public Class User
Inherits Record
Private Property Id As String
Private Property Name As String
'This is still required because you can use a base constructor directly to create a derived instance.
Public Sub New(csv As String)
MyBase.New(csv)
End Sub
Public Sub New(id As String, name As String)
Id = id
Name = name
End Sub
Protected Overrides Sub Init(csv As String)
'Add your type-specific implementation here.
End Sub
End Class
This "solution" doesn't actually do what I thought it would because, while it forces you to override Init in a derived class, you still have to provide a derived constructor that invokes the base constructor that calls Init and you still can't enforce that. I think that I'll leave this as an answer though, because, while it doesn't actually provide a solution to your problem, it demonstrates further why (as far as I can tell) there is no such solution.
The following is similar to the answer from #jmcilhinney in that it forces the derived class to implement an initialization method. However it makes use of a generic shared function and uses the little known GetUninitializedObject method to get around using the generic New constraint and it's requirement of an accessible parameter-less constructor.
Public MustInherit Class Record
Public Shared Function fromString(Of T As {Record})(ByVal str As String) As T
' create an unintialized instance of T
Dim ret As T = DirectCast(System.Runtime.Serialization.FormatterServices.GetUninitializedObject(GetType(T)), T)
ret.Initialize(str)
Return ret
End Function
Protected MustOverride Sub Initialize(source As String)
End Class
The User class then would be something like this:
Public Class User : Inherits Record
Private _id As String
Private _name As String
Public Sub New(ByVal id As String, ByVal name As String)
_id = id
_name = name
End Sub
Protected Overrides Sub Initialize(source As String)
Dim strs() As String = source.Split(","c)
_id = strs(0)
_name = strs(1)
End Sub
End Class
Example usage:
Dim userRecord As User = Record.fromString(Of User)("1,2")
some awesome dude put out the CS:GO skins data out as JSON.
http://api.ncla.me/data/data.json
But I am really struggling to deserialize it and access the individual items.
Could you guys help? Is it possible without third-party additions? ( I don't care how fast or slow it is. )
This is how far I have come
Public Class RootObject
Public Property ResultList_Main As List(Of ListWrapper_Main)
Public Class ListWrapper_Main
Public Property WeaponInfo As List(Of ListWrapper)
End Class
Public Class ListWrapper
Public Property value As String
Public Property quantity As String
End Class
End Class
jsonObject = jsSerializer.Deserialize(Of RootObject)(responseFromServer)
For Each Itemdetail1 In jsonObject.ResultList_Main
For Each Itemdetail2 In Itemdetail1.WeaponInfo
'Would like to display WeaponInfo + Value + Quantity here
Next
Next
I have something similar to the flowing two simple classes:
<DataContract> _
Public Class C1
Public Sub New(x_ As Int64)
_x= x_
End Sub
<DataMember()> _
Public Property x As Int64
End Class
<DataContract> _
Public Class C2
Public Sub New(y_ As string)
_y= y_
End Sub
<DataMember()> _
Public Property y As string
End Class
and the following structure that made of both:
<DataContract, StructLayout(LayoutKind.Sequential), _
KnownType(GetType(C1)), KnownType(GetType(C2))> _
Public structure S1
<DataMember, MessageHeaderArray> _
Public Second() As C1
<DataMember> _
Public First As C2
End structure
Finally, I'm calling a sub from a server's interface that sends an array of those structures as follows:
<ServiceContract(CallbackContract:=GetType(IClient))> _
Public Interface IServer
<OperationContract> _
Sub SendToServer(ByVal S()As S1)
End Interface
The problem is when I'm trying to pass this using WCF I'm getting a strange exception of the following format:
The use of type 'S1' as a get-only collection is not supported with NetDataContractSerializer. Consider marking the type with the CollectionDataContractAttribute attribute or the SerializableAttribute attribute or adding a setter to the property.
I tried to use the two suggested attributes, but I found that they should be used on declaring new class collection of types public class xx(Of T), not for my case (an exception telling that when used), I really can't understand about which get-only property he speaking about, because I have none, anyway, removing Public Second() As C1 from the structure, or passing one instance of the structure instance of an array, fixes the problem.
So I tried to change S1 to a class instead of structure, and the array into a List with get & set parts, but nothing helps, any clue what is going here?
Is there a reason you are using NetDataContractSerializer? Unless you are trying to support some legacy code, I believe you should use DataContractSerializer.
I'm learning how to access data on a DB using a WCF web service. My main issue I've run into is that when making a call for the result from the service, the return value is of type UniversityClass but no properties are available and I believe its real type is simply an object, therefore I have no access to any of its 'real' properties.
Heres a snippet of the class in my interface called 'Service1'
<ServiceContract()>
Public Interface IService1
<OperationContract()>
Function GetUniversity(ByVal universityID As Integer) As UniversityClass
End Interface
<DataContract()>
Public Class UniversityClass
Private _universityId As Integer
Public Property UniversityID As Integer
Get
Return _universityId
End Get
Set(value As Integer)
_universityId = value
End Set
End Property
and heres a preview of me making the call to the service to get the data
Dim client As New ServiceReference1.Service1Client
Dim result As New ServiceReference1.UniversityClass
Dim x = client.GetUniversityAsync(Integer.Parse(tbUniversityID.Text))
Dim r As WCFServiceExample.ServiceReference1.UniversityClass = Await x
If x.IsCompleted Then
result = x.Result
End If
tbResult.Text = result. _ _ _ _
'// ^ No properties accessible here even though it recognizes that result is of type UniversityClass
Upon inspecting ServiceReference1.UniversityClass I get taken to Referece.vb and notice that there is Partial Class UniversityClass which inherits object. I think perhaps that may be the reason why I don't have any access to the properties defined in my Service1 class because it thinks UniversityClass is an object with no type.
I've tried rebuilding all projects individually, rebuilding the solution and still nothing.
Would love some assistance with how to actually get an object of type UniversityClass to return from my service.
Recognizes the type: http://i50.tinypic.com/e5mhvk.jpg
No properties available: http://i50.tinypic.com/wmjui9.jpg
Any help would be greatly greatly appreciated!
Your client can't see the UniversityID because you haven't marked it as a data member:
<DataContract()>
Public Class UniversityClass
Private _universityId As Integer
<DataMember()>
Public Property UniversityID As Integer
Get
Return _universityId
End Get
Set(value As Integer)
_universityId = value
End Set
End Property
I am having difficulty loading some child attributes of a given entity. I have managed to load child entities on other objects, but not this one. To add to the frustration, the child entities I am trying to load are referenced from another Entity, and from this they work fine...
My code is as follows.
ViewWasteApplication Page
Protected Overrides Sub OnNavigatedTo(ByVal e As System.Windows.Navigation.NavigationEventArgs)
If NavigationContext.QueryString.ContainsKey("ID") Then
' load an existing record - edit mode
Context.Load(Context.GetWasteApplicationsByIDQuery(Int32.Parse(NavigationContext.QueryString("ID").ToString())),
AddressOf wasteApplicationLoaded, Nothing)
Else
MessageBox.Show("Application not found")
End If
End Sub
This calls GetWasteApplicationsByID - which is as follows:
Public Function GetWasteApplicationsByID(ByVal query As Int32) As IQueryable(Of WasteApplication)
Dim result = Me.ObjectContext.WasteApplications.Include("CurrentlyWith") _
.Include("Packaging") _
.Include("WasteStream") _
.Where(Function(f) f.ID = query)
Return result
End Function
The WasteApplication is being returned, but neither of the 3 child entities are appearing.
I have created a MetaData class for this WasteApplication, as follows:
<MetadataTypeAttribute(GetType(WasteApplications.WasteApplicationsMetaData))> _
Partial Public Class WasteApplications
Friend NotInheritable Class WasteApplicationsMetaData
'Metadata classes are not meant to be instantiated.
Private Sub New()
MyBase.New()
End Sub
Public Property ID As Integer
Public Property RequestedByName As String
Public Property RequestedByExtension As String
Public Property CARQRequired As Boolean
Public Property OriginOfMaterialID As Integer
Public Property Comments As String
Public Property MaterialName As String
Public Property PackagingID As Integer
Public Property FacilityPath As String
Public Property ProcessStatus As String
Public Property DateSubmitted As DateTime
Public Property RequestedByUsername As String
Public Property CurrentlyWithID As Integer
Public Property WasteStreamID As Integer
<Include()>
Public Property WasteStream As WasteStreams
<Include()>
Public Property Packaging As Packaging
End Class
End Class
Can anyone see anything wrong with this? I load the same two child objects on another page, and these seem to load just fine. The code for this is as follows:
View Chemical Application (This works)
Protected Overrides Sub OnNavigatedTo(ByVal e As System.Windows.Navigation.NavigationEventArgs)
Context.Load(Context.GetChemicalApplicationsByIDQuery(Int32.Parse(NavigationContext.QueryString("ID"))),
AddressOf wasteApplicationLoaded, Nothing)
End Sub
With the RIA function as follows:
Public Function GetChemicalApplicationsByID(ByVal query As Int32) As IQueryable(Of ChemicalApplication)
Return Me.ObjectContext.ChemicalApplications.Include("Chemical") _
.Include("ProcessStatus") _
.Include("PlanningApprover") _
.Include("FacilitiesApprover") _
.Include("MaintenanceApprover") _
.Include("PPCPermit") _
.Include("DischargeConsent") _
.Include("Facility") _
.Include("Packaging") _
.Include("WasteStream") _
.Where(Function(f) f.ID = query)
End Function
Any suggestions?
NOTE: I have not posted any of the XAML bindings, as I have confirmed via debugging that the source entities do not contain the child data, so therefore binding will not be an issue.
I am using Silverlight 4 with Entity Framework 4.
You will need to create metadata classes for the entities you wish to include and mark the fields with the [Include] attribute.
[MetadataTypeAttribute(typeof(Client.ClientMetadata))]
public partial class Client
{
internal sealed class ClientMetadata
{
private ClientMetadata()
{
}
[Required(ErrorMessage="You must enter a client name")]
public string Name;
[Include]
public EntityCollection<Contact> Contacts;
[Include]
public Employee Employee;
[Include]
public BillTo BillTo;
}
}
See RIA Services and relational data for more.
You need to do the 2 following things in order for this to work:
a) Add the include parameter in a metadata class (as DaveB proposed)
b) on the domain service queries (server side) add the include directive - Me.ObjectContext.WasteApplications.Include("CurrentlyWith")
I managed to solve the issue, you need to load the respective entities into the datacontext as well as loading the linked entity. i.e in my case I need to add:
Context.Load(Context.GetWasteStreamsQuery())
Context.Load(Context.GetPackagingQuery())
so that the linked child entities exist. My full onNavigate therefore looks like this:
Protected Overrides Sub OnNavigatedTo(ByVal e As System.Windows.Navigation.NavigationEventArgs)
If NavigationContext.QueryString.ContainsKey("ID") Then
Context.Load(Context.GetWasteApplicationsByIDQuery(Int32.Parse(NavigationContext.QueryString("ID").ToString())),
AddressOf wasteApplicationLoaded, Nothing)
Context.Load(Context.GetWasteStreamsQuery())
Context.Load(Context.GetPackagingQuery())
Else
MessageBox.Show("Application not found")
End If
End Sub