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.
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);
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.
I need a little assistance in obtaining values from a JSON object in C#. Here is the code and the output. I am trying to retrieve value of ScoreRepresentation from both the objects. The obtained values in this case would be BR400L and null as per the below output.
Can anyone please assist? Newbie in C# :) Thanks in advance
using System;
using Microsoft.VisualBasic;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
namespace Test
{
class Program
{
static void Main(string[] args)
{
var json = "{\"Results\":[{\"RequestIdentifier\":\"Lexile\",\"ValueType\":\"INTEGER\",\"Scores\":[{\"lexile\":{\"ScoreValue\":-400,\"ScaledScore\":-400,\"ScoreRepresentation\":\"BR400L\"}}]},{\"RequestIdentifier\":\"UnifiedScaleScore\",\"ValueType\":\"INTEGER\",\"Scores\":[{\"unifiedScaleScore\":{\"ScoreValue\":610,\"ScaledScore\":610,\"ScoreRepresentation\":null}}]}]}";
var deserialized = JsonConvert.DeserializeObject(json);
Console.WriteLine(deserialized);
}
}
}
Output:
{
"Results": [
{
"RequestIdentifier": "Lexile",
"ValueType": "INTEGER",
"Scores": [
{
"lexile": {
"ScoreValue": -400,
"ScaledScore": -400,
"ScoreRepresentation": "BR400L"
}
}
]
},
{
"RequestIdentifier": "UnifiedScaleScore",
"ValueType": "INTEGER",
"Scores": [
{
"unifiedScaleScore": {
"ScoreValue": 610,
"ScaledScore": 610,
"ScoreRepresentation": null
}
}
]
}
]
}
I like to go the "Model" route. You create models of your data, then you can easily deserialize to them. Sometimes when I am feeling lazy, I will use this site to do my work for me.
So, for your specific example, it gives back these models:
public class Lexile {
public int ScoreValue { get; set; }
public int ScaledScore { get; set; }
public string ScoreRepresentation { get; set; }
}
public class UnifiedScaleScore {
public int ScoreValue { get; set; }
public int ScaledScore { get; set; }
public object ScoreRepresentation { get; set; }
}
public class Score {
public Lexile lexile { get; set; }
public UnifiedScaleScore unifiedScaleScore { get; set; }
}
public class Result {
public string RequestIdentifier { get; set; }
public string ValueType { get; set; }
public List<Score> Scores { get; set; }
}
public class Root {
public List<Result> Results { get; set; }
}
Then, you can simply deserialize to Root by doing this:
var deserialized = JsonConvert.DeserializeObject<Root>(json);
Keep in mind that if your JSON is not perfect, you will find some inconsistencies with the output. You may have to massage your models a bit to fix those issues. You can't just assume that site gives you 100% accurate data.
But, if it's good enough, you can now get at every property you'd ever need to without having to putz around with dynamics or JToken.
For example:
foreach(var r in deserialized.Results)
{
foreach(var s in r.Scores)
{
Console.Write(s.unifiedScaleScore.ScoreRepresentation);
}
}
I have the following JSON data structure stored in a file, I have made a JSON data model in C# using the following tool JsonToCsharp. Usually, this tool is perfect and makes me awesome data models, but this time, for an unknown reason, each time I parse the JSON content, all string lists are null.
{
"Targets": [
{
"Name": "myTarget",
"Sharpmakes": [
{
"Name": "myTarget_v01",
"Dest": "/myTarget/folder/destination"
}
],
"Includes": [
"default_files" // <= This will always be null
]
},
{
"Name": "default_files",
"Directories": [
{
"Source": "/default/utils",
"Dest": "/utils",
"Includes": [ "*.bat", "*.ini", "*.txt", "*.xml", "*.json" ] // <= This will always be null
},
],
},
],
}
This is the code I am using for parsing my JSON:
try
{
var jsonContent = System.IO.File.ReadAllText(packageDefinitionJsonConfigPath);
return JsonConvert.DeserializeObject<Package>(jsonContent);
}
catch (Exception exception)
{
Log.Error($"Could not parse the json \n\n{packageDefinitionJsonConfigPath}");
throw exception;
}
Nothing is quite special about this code snippet, it's a simple NewtonSoft JSON parse.
And here are my generated models that JsonToCsharp gave me, (which looks just fine)...
[JsonObject]
public class Package
{
[JsonProperty("Targets")]
public List<Target> Targets { get; set; }
}
public class Sharpmake
{
[JsonProperty("Name")]
public string Name { get; set; }
[JsonProperty("Excludes")]
public IList<string> Excludes { get; set; }
[JsonProperty("Dest")]
public string Dest { get; set; }
[JsonProperty("Includes")]
public IList<string> Includes { get; set; }
}
public class File
{
[JsonProperty("Source")]
public string Source { get; set; }
[JsonProperty("Dest")]
public string Dest { get; set; }
}
public class Directory
{
[JsonProperty("Source")]
public string Source { get; set; }
[JsonProperty("Dest")]
public string Dest { get; set; }
[JsonProperty("Includes")]
public IList<string> Includes { get; set; }
}
public class Target
{
[JsonProperty("Name")]
public string Name { get; set; }
[JsonProperty("Sharpmakes")]
public IList<Sharpmake> Sharpmakes { get; set; }
[JsonProperty("Includes")]
public IList<string> Includes { get; set; }
[JsonProperty("Files")]
public IList<File> Files { get; set; }
[JsonProperty("Directories")]
public IList<Directory> Directories { get; set; }
}
public class RootObject
{
[JsonProperty("Targets")]
public IList<Target> Targets { get; set; }
}
Does anyone have an idea why my model could work just fine for everything except for my string lists? There nothing out of the extraordinary in this code snippet, so I'm really clueless here...
Updating my package to the latest version of Json.Net (12.0.2) seems to have fixed the issue
That would match with the release notes fixes
https://github.com/JamesNK/Newtonsoft.Json/releases/tag/12.0.2
I am consuming an API that returns the following JSON:
[
{
"product": {
"id": 2,
"name": "Auto"
}
}
]
So, I am trying to deserialize this in C# object wihout success.
I'd tried a lot of other's stackoverflow solutions.
Here are my attempt:
public class DomainMessageResponse : BaseResponseMessage
{
public Example data { get; set; }
}
public class Example
{
[JsonProperty("product")]
public Product product { get; set; }
}
public class Product
{
[JsonProperty("id")]
public int id { get; set; }
[JsonProperty("name")]
public string name { get; set; }
}
The problem is that the JSON is beginning with [] and our generic method (that I use from an internal framework) was not able to due with it. I'm getting the following exception:
Cannot deserialize the current JSON array (e.g. [1,2,3]) into type....
Thanks #EZI and #eocron for valid solution's.
You should deserialize to array/list. Below code should work...
var list = JsonConvert.DeserializeObject<List<Item>>(json);
public class Product
{
public int id { get; set; }
public string name { get; set; }
}
public class Item
{
public Product product { get; set; }
}
There is two solutions to your problem, considering the way you want to use your object.
First one is to simply create DTO with same fields. Used when you need full control:
using System.Collections.Generic;
using System.Runtime.Serialization;
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
namespace ConsoleTest
{
class Program
{
[DataContract]
public class Example
{
[DataMember]
public Product Product { get; set; }
}
[DataContract]
public class Product
{
[DataMember]
public int Id { get; set; }
[DataMember]
public string Name { get; set; }
}
static void Main(string[] args)
{
var json = #"
[
{
""product"": {
""id"": 2,
""name"": ""Auto""
}
}
]";
var obj = JsonConvert.DeserializeObject<List<Example>>(json,
new JsonSerializerSettings
{
ContractResolver = new CamelCasePropertyNamesContractResolver()
});
}
}
}
The second one used when you want a few fields from json and don't care much about everything else, and uses dynamic type. Easy to code, easy to use, looks pretty good, but not very safe:
using System.Collections.Generic;
using Newtonsoft.Json;
namespace ConsoleTest
{
class Program
{
static void Main(string[] args)
{
var json = #"
[
{
""product"": {
""id"": 2,
""name"": ""Auto""
}
}
]";
dynamic list = JsonConvert.DeserializeObject<List<dynamic>>(json);
var id = (int)list[0].product.id;
}
}
}