All,
Edit: Firstly thanks for everyone's help. Secondly I'm new to Stack Overflow so apologises if I've added this edit incorrectly.
Following the commments and replies I've updated my class structure to:
services class:
using System;
using System.Collections.Generic;
using System.Text;
using System.Text.Json;
namespace RTT_API
{
class services
{
public List<service> service = new List<service>();
public services()
{
}
}
}
Service class:
using System;
using System.Collections.Generic;
using System.Text;
namespace RTT_API
{
class service
{
public string atocCode{get; set;}
public service()
{
}
}
}
Unfortunately I'm still getting the same error. I think I still haven't quite matched my class structure to the JSON structure? Unfortunately I'm not sure where my mistake is. If it helps to highlight my mistake using a comparison then the following works:
Location class
using System;
using System.Collections.Generic;
using System.Text;
namespace RTT_API
{
class location
{
public string name { get; set; }
public string crs { get; set; }
public location()
{
}
}
}
Location deserilisation command and test output:
location locations = JsonSerializer.Deserialize<location>(channelResponse.RootElement.GetProperty("location").GetRawText());
MessageBox.Show(locations.crs);
Original question:
My JSON is as follows:
{
"location": {
"name": "Bournemouth",
"crs": "BMH",
"tiploc": "BOMO"
},
"filter": null,
"services": [
{
"locationDetail": {
"realtimeActivated": true,
"tiploc": "BOMO",
"crs": "BMH",
"description": "Bournemouth",
"wttBookedArrival": "011630",
"wttBookedDeparture": "011830",
"gbttBookedArrival": "0117",
"gbttBookedDeparture": "0118",
"origin": [
{
"tiploc": "WATRLMN",
"description": "London Waterloo",
"workingTime": "230500",
"publicTime": "2305"
}
],
"destination": [
{
"tiploc": "POOLE",
"description": "Poole",
"workingTime": "013000",
"publicTime": "0130"
}
],
"isCall": true,
"isPublicCall": true,
"realtimeArrival": "0114",
"realtimeArrivalActual": false,
"realtimeDeparture": "0118",
"realtimeDepartureActual": false,
"platform": "3",
"platformConfirmed": false,
"platformChanged": false,
"displayAs": "CALL"
},
"serviceUid": "W90091",
"runDate": "2013-06-11",
"trainIdentity": "1B77",
"runningIdentity": "1B77",
"atocCode": "SW",
"atocName": "South West Trains",
"serviceType": "train",
"isPassenger": true
}
]
}
My class structure is as follows:
servicelist class:
using System;
using System.Collections.Generic;
using System.Text;
using System.Text.Json;
namespace RTT_API
{
class servicelist
{
public List<services> service = new List<services>();
public servicelist()
{
}
}
}
services class:
using System;
using System.Collections.Generic;
using System.Text;
namespace RTT_API
{
class services
{
public int serviceUid;
public services()
{
}
}
}
For deserialisation I have tried:
services servicelist = JsonSerializer.Deserialize<services>(channelResponse.RootElement.GetProperty("services").GetRawText());
and
servicelist servicelist = JsonSerializer.Deserialize<servicelist>(channelResponse.RootElement.GetProperty("services").GetRawText());;
In both cases I get 'System.Text.Json.JsonException'
I think there is a mismatch betwee the class structure and the JSON but I can't work what the problem is? It's the first time I've tried to desarialise an array.
Thanks
using System;
using System.Collections.Generic;
using System.Text;
namespace RTT_API
{
class location
{
public string name { get; set; }
public string crs { get; set; }
public location()
{
}
}
}
You can generate exact C# classes according to your JSON using tools for exactly that purpose. I used https://json2csharp.com/ , another is https://jsonutils.com/ - these are web services and don't require installation on computer, another option is generating classes through Visual Studio (with Web Essentials installed), there you would use Edit - Paste special - paste JSON as class.
Once you have the valid classes (I pasted generated classes below) you can deserialize entire Root object and then access any part of it, including services part:
// jsonInputText holds entire JSON string you posted
Root root = JsonSerializer.Deserialize<Root>(jsonInputText);
List<Service> serviceList = root.services;
Generated classes:
public class Location
{
public string name { get; set; }
public string crs { get; set; }
public string tiploc { get; set; }
}
public class Origin
{
public string tiploc { get; set; }
public string description { get; set; }
public string workingTime { get; set; }
public string publicTime { get; set; }
}
public class Destination
{
public string tiploc { get; set; }
public string description { get; set; }
public string workingTime { get; set; }
public string publicTime { get; set; }
}
public class LocationDetail
{
public bool realtimeActivated { get; set; }
public string tiploc { get; set; }
public string crs { get; set; }
public string description { get; set; }
public string wttBookedArrival { get; set; }
public string wttBookedDeparture { get; set; }
public string gbttBookedArrival { get; set; }
public string gbttBookedDeparture { get; set; }
public List<Origin> origin { get; set; }
public List<Destination> destination { get; set; }
public bool isCall { get; set; }
public bool isPublicCall { get; set; }
public string realtimeArrival { get; set; }
public bool realtimeArrivalActual { get; set; }
public string realtimeDeparture { get; set; }
public bool realtimeDepartureActual { get; set; }
public string platform { get; set; }
public bool platformConfirmed { get; set; }
public bool platformChanged { get; set; }
public string displayAs { get; set; }
}
public class Service
{
public LocationDetail locationDetail { get; set; }
public string serviceUid { get; set; }
public string runDate { get; set; }
public string trainIdentity { get; set; }
public string runningIdentity { get; set; }
public string atocCode { get; set; }
public string atocName { get; set; }
public string serviceType { get; set; }
public bool isPassenger { get; set; }
}
public class Root
{
public Location location { get; set; }
public object filter { get; set; }
public List<Service> services { get; set; }
}
If you need to deserialize only just a part of your json then you can use the JObject and JToken helper classes for that.
var json = File.ReadAllText("Sample.json");
JObject topLevelObject = JObject.Parse(json);
JToken servicesToken = topLevelObject["services"];
var services = servicesToken.ToObject<List<Service>>();
The topLevelObject contains the whole json in a semi-parsed format.
You can use the indexer operator to retrieve an object / array by using one of the top level keys.
On a JToken you can call the ToObject<T> to deserialize the data into a custom data class.
In order to be able to parse your json I had to adjust the services type because the W90091 as serviceUid can't be parsed as int. So here is my Service class definition:
public class Service
{
public string ServiceUid;
}
One thing to note here is that casing does not matter in this case so please use CamelCasing in your domain models as you would normally do in C#.
Thanks for everyone's help.
Firstly I had to make a few changes to the class names as they didn't match the JSON. I also had to change the syntax of two commands which I've detailed below:
I changed the definition of the list of objects from:
public List<services> service = new List<services>();
to:
public List<service> destination { get; set; };
and deserilisation command from:
services servicelist = JsonSerializer.Deserialize<services>(channelResponse.RootElement.GetProperty("services").GetRawText());
to
var servicelist = JsonSerializer.Deserialize<List<service>>(channelResponse.RootElement.GetProperty("services").GetRawText());
The change from services to var might not be the best solution. I think it's the first change, and matching the class names to the JSON, that fundamentally fixed the issue.
Related
So I have an API set up that returns a JSON. The response looks as follows:
{
"success": true,
"results": 1,
"data": [
{
"location": {
"type": "Point",
"coordinates": [
-83.338322,
42.705647
],
"formattedAddress": "Some adress",
"city": "SomeCity",
"state": "STATE",
"zipcode": "000000",
"country": "US"
},
"_id": "630ce2c5a963f97ddae7387f",
"title": "Node Developer",
"description": "Must be a full-stack developer, able to implement everything in a MEAN or MERN stack paradigm (MongoDB, Express, Angular and/or React, and Node.js).",
"email": "employer#gmail.com",
"address": "someADress",
"company": "Company Ltd",
"industry": [
"Information Technology"
],
"jobType": "Permanent",
"minEducation": "Bachelors",
"positions": 2,
"experience": "No Experience",
"salary": 155000,
"lastDate": "2022-09-05T15:41:44.912Z",
"user": "630cdf34b2bc6356a75ec29c",
"postingDate": "2022-08-29T16:01:09.707Z",
"slug": "node-developer"
}
] }
And I am trying to serialize it as an object in C# using the following code:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Networking;
public class test : MonoBehaviour
{
public string domain = "http://localhost:3000/api/v1";
public string request = "/jobs";
private bool coroutineRunning = false;
Request req;
private void Start()
{
req = new Request();
}
void Update()
{
if (Input.GetKeyDown(KeyCode.Space) && !coroutineRunning)
{
StartCoroutine(GetRequest(domain + request));
}
}
IEnumerator GetRequest(string uri)
{
coroutineRunning = true;
UnityWebRequest request = UnityWebRequest.Get(uri);
yield return request.SendWebRequest();
if (request.result == UnityWebRequest.Result.Success)
{
string jsonText = request.downloadHandler.text;
Debug.Log(jsonText);
SetUpObject(jsonText);
}
else
{
Debug.LogError(request.result);
}
coroutineRunning = false;
}
void SetUpObject(string json)
{
req = JsonUtility.FromJson<Request>(json);
Debug.Log(JsonUtility.ToJson(req, true));
Debug.Log(req);
}
}
The Request class:
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[Serializable]
public class Data
{
public Location location { get; set; }
public string _id { get; set; }
public string title { get; set; }
public string description { get; set; }
public string email { get; set; }
public string address { get; set; }
public string company { get; set; }
public string[] industry { get; set; }
public string jobType { get; set; }
public string minEducation { get; set; }
public int positions { get; set; }
public string experience { get; set; }
public int salary { get; set; }
public DateTime lastDate { get; set; }
public string user { get; set; }
public DateTime postingDate { get; set; }
public string slug { get; set; }
}
[Serializable]
public class Location
{
public string type { get; set; }
public double[] coordinates { get; set; }
public string formattedAddress { get; set; }
public string city { get; set; }
public string state { get; set; }
public string zipcode { get; set; }
public string country { get; set; }
}
[Serializable]
public class Request
{
public bool success { get; set; }
public int results { get; set; }
public Data[] data { get; set; }
}
The problem is that I can't figure out how I should create a class that can get serialized with this JSON. This API is from a course I took on creating API's and won't be used in a project, I am just trying to figure out how to properly use serialization with complex JSONs such as this one.
The request returns a string that is the JSON written above. I used that JSON format and JSON2CSHARP to generate the Request class (i know it should be called the result class). Now when I copied the generated class I swapped every List<T> with an array of that type. I also think that using Datetime instead of string and other type mismatches could be the source of the problem, but even if they were the JsonUtilty would've still populated the Success and Results fields of the Request class and left the Data as an empty array
From the Unity documentation, I see the following (emphasis added):
Fields of the object must have types supported by the serializer. Fields that have unsupported types, as well as private fields or fields marked with the NonSerialized attribute, will be ignored.
Based on that description, and the example provided, it looks like it may only work with fields and not properties. I would try to make everything a member variable instead of a property and see if that fixes it.
You don't need to remove setters, just download and install Newtonsoft.Json for Unity3d
using Newtonsoft.Json;
Request req = JsonConvert.DeserializeObject<Request>(json);
I have a Json file that was deserialized from a Json Api-Call, now I have to use this file as an object in the main program.
Here is a small section of it:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Newtonsoft.Json;
namespace Api1
{
public class EcmSimpleField
{
public string value { get; set; }
public string displayName { get; set; }
public string internalName { get; set; }
public string dbName { get; set; }
public bool visible { get; set; }
public string type { get; set; }
}
public class BaseParameter
{
public string value { get; set; }
public string type { get; set; }
}
public class SystemField
{
public string value { get; set; }
public string type { get; set; }
}
How can I use this file as an object in the main program and work with it?
Create a class for the json like you shared above and use deserialise it using Newtonsoft.json dll or any other library.
var obj = JsonConvert.DeserializeObject<YourClass>(jsonString);
This thread will probably help you:
How can I parse JSON with C#?
If your JSON file has changing parameters then the parameters will need to be retrieved in arrays because the array index will always be the same even if the "parameter" changes.
I'm trying to deserialize the following xml document into a C# object:
<ns1:StockerFichiers
xmlns:ns1="http://www.foo.fr/bar/Repository"
xmlns:ns0="http://www.foo.fr/bar/Transport/">
<ns1:fichiersAStocker>
<ns0:FichierIdentifie>
<ns0:Contenu></ns0:Contenu>
<ns0:DomaineIdLocalDoc>128</ns0:DomaineIdLocalDoc>
<ns0:EstOriginal>true</ns0:EstOriginal>
<ns0:IdLocalDoc>2018-07-06T154554_70183_2</ns0:IdLocalDoc>
<ns0:PieceDynamique>false</ns0:PieceDynamique>
<ns0:GoldenSource>false</ns0:GoldenSource>
<ns0:TypeDoc>PDF</ns0:TypeDoc>
<ns0:TypeMime>application/pdf</ns0:TypeMime>
</ns0:FichierIdentifie>
</ns1:fichiersAStocker>
</ns1:StockerFichiers>
I know a lot of deserialization questions already exist, but even if some seems to be solving the same issue I face, None of what I've tried did populate my List<FichierIdentifie>.
Where I deserialize:
public void StockerFichiersXmlBase64(string fichiersAStocker)
{
//serializer
XmlRootAttribute xroot = new XmlRootAttribute();
xroot.ElementName = "StockerFichiers";
xroot.Namespace = NamespacesConstantes.NAMESPACE_SWREPOSITORY; //ns1
XmlSerializer deserializer = new XmlSerializer(typeof(StockerFichiersRoot),xroot );
//fichiersAStocker is base64 encoded
byte[] data = Convert.FromBase64String(fichiersAStocker);
StringReader stringReader = new StringReader(Encoding.UTF8.GetString(data));
//deserialization
StockerFichiersRoot deserializedFiles = (StockerFichiersRoot)deserializer.Deserialize(stringReader);
}
My current version :
// Root
[XmlRoot(ElementName = "StockerFichiers", Namespace = NamespacesConstantes.NAMESPACE_SWREPOSITORY)]
public class StockerFichiersRoot
{
[XmlElement(ElementName = "fichiersAStocker", Namespace = NamespacesConstantes.NAMESPACE_SWREPOSITORY)]
public FichiersAStocker fichiersAStocker { get; set; }
}
//sub root
public class FichiersAStocker
{
[XmlArray(ElementName = "fichiersAStocker", Namespace = NamespacesConstantes.NAMESPACE_SWREPOSITORY)]
[XmlArrayItem(ElementName = "FichierIdentifie", Namespace=NamespacesConstantes.NAMESPACE_MSS_TRANSPORT)]
public List<FichierIdentifie> FichiersIdentifie { get; set; }
}
public class FichierIdentifie
{
[XmlElement(Namespace = NamespacesConstantes.NAMESPACE_TRANSPORT)]
public byte[] Contenu { get; set; }
//all fields are similar to the first one
}
And with this variation of the subroot class according to Is it possible to deserialize XML into List<T>? :
//sub root
public class FichiersAStocker
{
[XmlElement(ElementName = "FichierIdentifie", Namespace=NamespacesConstantes.NAMESPACE_MSS_TRANSPORT)]
public List<FichierIdentifie> FichiersIdentifie { get; set; }
}
I've also tried to remove the class FichiersAStocker (the sub root), to put the List<FichierIdentifie> in the root class, with both [xmlArray..] and [XmlElement] variations but with no success.
I always get an object with the list empty.
Try using XML2CSharp to generate class. Then try using that class or use it for debugging.
Generated code for your XML looks like this:
(You can remove unwanted properties)
/*
Licensed under the Apache License, Version 2.0
http://www.apache.org/licenses/LICENSE-2.0
*/
using System;
using System.Xml.Serialization;
using System.Collections.Generic;
namespace Xml2CSharp
{
[XmlRoot(ElementName="FichierIdentifie", Namespace="http://www.foo.fr/bar/Transport/")]
public class FichierIdentifie {
[XmlElement(ElementName="Contenu", Namespace="http://www.foo.fr/bar/Transport/")]
public string Contenu { get; set; }
[XmlElement(ElementName="DomaineIdLocalDoc", Namespace="http://www.foo.fr/bar/Transport/")]
public string DomaineIdLocalDoc { get; set; }
[XmlElement(ElementName="EstOriginal", Namespace="http://www.foo.fr/bar/Transport/")]
public string EstOriginal { get; set; }
[XmlElement(ElementName="IdLocalDoc", Namespace="http://www.foo.fr/bar/Transport/")]
public string IdLocalDoc { get; set; }
[XmlElement(ElementName="PieceDynamique", Namespace="http://www.foo.fr/bar/Transport/")]
public string PieceDynamique { get; set; }
[XmlElement(ElementName="SisraGoldenSource", Namespace="http://www.foo.fr/bar/Transport/")]
public string SisraGoldenSource { get; set; }
[XmlElement(ElementName="TypeDocSisra", Namespace="http://www.foo.fr/bar/Transport/")]
public string TypeDocSisra { get; set; }
[XmlElement(ElementName="TypeMime", Namespace="http://www.foo.fr/bar/Transport/")]
public string TypeMime { get; set; }
}
[XmlRoot(ElementName="fichiersAStocker", Namespace="http://www.foo.fr/bar/Repository")]
public class FichiersAStocker {
[XmlElement(ElementName="FichierIdentifie", Namespace="http://www.foo.fr/bar/Transport/")]
public FichierIdentifie FichierIdentifie { get; set; }
}
[XmlRoot(ElementName="StockerFichiers", Namespace="http://www.foo.fr/bar/Repository")]
public class StockerFichiers {
[XmlElement(ElementName="fichiersAStocker", Namespace="http://www.foo.fr/bar/Repository")]
public FichiersAStocker FichiersAStocker { get; set; }
[XmlAttribute(AttributeName="ns1", Namespace="http://www.w3.org/2000/xmlns/")]
public string Ns1 { get; set; }
[XmlAttribute(AttributeName="ns0", Namespace="http://www.w3.org/2000/xmlns/")]
public string Ns0 { get; set; }
}
}
Really frustrating mistake that took me half a day to solve :
notice how "NamespacesConstantes.NAMESPACE_MSS_TRANSPORT" is close to "NamespacesConstantes.NAMESPACE_TRANSPORT". Add some lazy autocompletion and you can fool yourself while defining the [XmlElement...] in the "FichiersAStocker" class.
Thanks for your help Matt, I noticed this mistake while i paste some of my code on https://dotnetfiddle.net/ ! :)
I am trying to import a JSON file into an object in C# (VS 2017 on Mac) to do further operations on it.
I have this JSON file example:
{
"subdomain": "mycompany",
"name": "MyCompany Inc",
"website": "https://www.mycompany.com",
"edition": "DIRECTORY",
"licensing":
{
"apps":
[
"boxnet"
]
},
"admin": {
"profile":
{
"firstName": "John",
"lastName": "Smith",
"email": "joe#mycompany.com",
"login": "joe#mycompany.com",
"mobilePhone": null
},
"credentials":
{
"password":
{
"value": "NotAPassword"},
"recovery_question":
{
"question": "Best Solution",
"answer": "MyOne"
}
}
}
}
}
So I generated a C# library to create an object type to import into:
using System;
namespace OrgCustom
{
using System;
using System.Net;
using System.Collections.Generic;
using Newtonsoft.Json;
public class Licensing
{
public List<string> apps { get; set; }
}
public class Profile
{
public string firstName { get; set; }
public string lastName { get; set; }
public string email { get; set; }
public string login { get; set; }
public object mobilePhone { get; set; }
}
public class Password
{
public string value { get; set; }
}
public class RecoveryQuestion
{
public string question { get; set; }
public string answer { get; set; }
}
public class Credentials
{
public Password password { get; set; }
public RecoveryQuestion recovery_question { get; set; }
}
public class Admin
{
public Profile profile { get; set; }
public Credentials credentials { get; set; }
}
public class Org
{
public string subdomain { get; set; }
public string name { get; set; }
public string website { get; set; }
public string edition { get; set; }
public Licensing licensing { get; set; }
public Admin admin { get; set; }
}
}
And so, I should be able to import the file quite easily, using the Newtownsoft.Json library?
Well, my program code is:
using System;
using System.IO;
using System.Runtime.Serialization.Json;
using RestSharp;
using Newtonsoft.Json;
using OrgCustom;
namespace TestStart
{
class Program
{
static void Main(string[] args)
{
string JSONstring = File.ReadAllText("CreateOrgExample.json");
OrgCustom.Org objOrg = JsonConvert.DeserializeObject<OrgCustom.Org>(JSONstring);
Console.WriteLine(objOrg.ToString());
}
}
}
The problem is that when I run it, I get a message on the line from the Deserialize line that JsonConvert is a type, which is not valid in the given context.
What am I doing wrong here? That line I saw in the Introduction to JSON with C# MVA course and I believe that it should work?!?!
Thanks in advance,
QuietLeni
It seems to an issue with your JSON having an extra closing bracket at the end. So you might getting error at parsing.
At a glance I do not see a syntax error. You might check assembly references and then use a global:: qualifier combined with intellisense to to drill down to the convert call (but again it looks correct to me.)
As an aside, your Password class does not define a RecoveryQuestion property as is found in the JSON snippet.
This shouldn't prevent Newtonsoft from deserializing the JSON snippet into the structure you do have defined, though.
I would like to deserialize the following JSON (using Json.NET) to an object, but cannot, as the class name would need to begin with a number.
An example of this is the Wikipedia article API. Using the API to provide a JSON response returns something like this. Note the "16689396" inside the "pages" key.
{
"batchcomplete":"",
"continue":{
"grncontinue":"0.893378504602|0.893378998188|35714269|0",
"continue":"grncontinue||"
},
"query":{
"pages":{
"16689396":{
"pageid":16689396,
"ns":0,
"title":"Jalan Juru",
"extract":"<p><b>Jalan Juru</b> (Penang state road <i>P176</i>) is a major road in Penang, Malaysia.</p>\n\n<h2><span id=\"List_of_junctions\">List of junctions</span></h2>\n<p></p>\n<p><br></p>"
}
}
}
}
How could I deserialize this JSON containing a number which changes based on the article?
It sounds like the Pages property in your Query class would just need to be a Dictionary<int, Page> or Dictionary<string, Page>.
Complete example with the JSON you've provided - I've had to guess at some of the name meanings:
using System;
using System.Collections.Generic;
using System.IO;
using Newtonsoft.Json;
public class Root
{
[JsonProperty("batchcomplete")]
public string BatchComplete { get; set; }
[JsonProperty("continue")]
public Continuation Continuation { get; set; }
[JsonProperty("query")]
public Query Query { get; set; }
}
public class Continuation
{
[JsonProperty("grncontinue")]
public string GrnContinue { get; set; }
[JsonProperty("continue")]
public string Continue { get; set; }
}
public class Query
{
[JsonProperty("pages")]
public Dictionary<int, Page> Pages { get; set; }
}
public class Page
{
[JsonProperty("pageid")]
public int Id { get; set; }
[JsonProperty("ns")]
public int Ns { get; set; }
[JsonProperty("title")]
public string Title { get; set; }
[JsonProperty("extract")]
public string Extract { get; set; }
}
class Test
{
static void Main()
{
string text = File.ReadAllText("test.json");
var root = JsonConvert.DeserializeObject<Root>(text);
Console.WriteLine(root.Query.Pages[16689396].Title);
}
}
Related question: Json deserialize from wikipedia api with c#
Essentially you need to changes from using a class for the pages to a dictionary, which allows for the dynamic nature of the naming convention.
Class definitions :
public class pageval
{
public int pageid { get; set; }
public int ns { get; set; }
public string title { get; set; }
public string extract { get; set; }
}
public class Query
{
public Dictionary<string, pageval> pages { get; set; }
}
public class Limits
{
public int extracts { get; set; }
}
public class RootObject
{
public string batchcomplete { get; set; }
public Query query { get; set; }
public Limits limits { get; set; }
}
Deserialization :
var root = JsonConvert.DeserializeObject<RootObject>(__YOUR_JSON_HERE__);
var page = responseJson.query.pages["16689396"];
You can implement your own DeSerializer or editing the JSON before you DeSerialize it.