Getting results back from Shopify's graphql which it not in a standard structure to be able to deserialize simply.
Here's the result, but note the list of item1, item2, etc which can be from 1 to 100 items returned and this is the part I'm not sure how to deserialize and is my main question. Specifically, to a strongly typed List<Item> collection of items such that I can they query for any UserErrors, i.e. something like: lstItems.Any(l => l.UserErrors.Any()).
The second issue is that data will not always have these contents...other GraphQL queries will have different responses. Perhaps in this case, I should rename data in the string to another class name that will have these contents, then deserialize?
{
"data":{
"item1":{
"userErrors":[
]
},
"item2":{
"userErrors":[
]
}
},
"extensions":{
...
}
}
Here's what QuickType comes up with, but again, it assumes a discrete list of Items:
namespace QuickType
{
using System;
using System.Collections.Generic;
using System.Globalization;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
public partial class InventoryUpdateResult
{
[JsonProperty("data")]
public Data Data { get; set; }
[JsonProperty("extensions")]
public Extensions Extensions { get; set; }
}
public partial class Data
{
[JsonProperty("item1")]
public Item Item1 { get; set; }
[JsonProperty("item2")]
public Item Item2 { get; set; }
}
public partial class Item
{
[JsonProperty("userErrors")]
public UserError[] UserErrors { get; set; }
}
public partial class UserError
{
[JsonProperty("field")]
public string[] Field { get; set; }
[JsonProperty("message")]
public string Message { get; set; }
}
public partial class Extensions
{
....
}
}
Thanks #Charlieface for pointing me in the right direction. Here's what I ultimately did. The other part I was trying to figure out, which I didn't know and articulate at the time of writing the question, was how to separate out the data portion of the response, which had this issue from the extensions portion, which is structured properly and can be simply deserialized to a class.
So to split out the data portion, you parse the string to a JObject
Then deserialize just that portion to the Dictionary as suggested
Then you can iterate through the Dictionary to get all the standard class objects and do as you with with them (add them to their own list, etc.)
code:
var jsonObject = JObject.Parse(response);
Dictionary<string, InventoryUpdateResult> dicRawResults;
var data = (JObject)jsonObject["data"];
if (data != null)
{
dicRawResults = JsonConvert.DeserializeObject<Dictionary<string, InventoryUpdateResult>>(data.ToString());
foreach(var result in dicRawResults)
{
InventoryUpdateResult inventoryUpdateResult = result.Value;
}
}
Then I extracted the extensions portion and converted that to the class object as such:
jsonObject = JObject.Parse(shopifyResponse.Value);
var jExtension = (JObject)jsonObject["extensions"];
if (jExtension != null)
{
queryCost = jExtension.ToObject<GraphExtensions>();
.....
}
Related
I have a json file which has random names in roots but same structure in child elements. I would like to get all the child elements in an array or a list.
Sample json file :
{
"-LeHl495vL6vh-8CaLbD":{
"apiKey":"sr-tr-137-beea04e44cb452ba0da0ca090b7e61b4ec6ffc69"
},
"-LeHl6jrhUEMb7slZcpB":{
"apiKey":"sr-tr-137-aef7a23095c0c7baef1ef681bdd8bf9756ac2a17"
}
}
I have tried these classes but could not do it.
public class RequestedReport
{
public Dictionary<string, List<ReportData>> ReportDatas { get; set; }
}
public class ReportData
{
public string apiKey { get; set; }
}
So my expected output from deserialization is like List which contains all the apiKeys in json file.
Thanks in advance.
It looks to me like your JSON represents a Dictionary<string, ReportData> directly. There's no wrapper object, and no lists involved. If you deserialize your JSON to that type, it should be fine. Here's a complete example:
using System;
using System.Collections.Generic;
using System.IO;
using Newtonsoft.Json;
class Program
{
static void Main()
{
var json = File.ReadAllText("test.json");
var reports = JsonConvert.DeserializeObject<Dictionary<string, ReportData>>(json);
foreach (var pair in reports)
{
Console.WriteLine($"{pair.Key}: {pair.Value.ApiKey}");
}
}
}
public class ReportData
{
[JsonProperty("apiKey")]
public string ApiKey { get; set; }
}
If you just want the list of API keys, and you don't care about the field names associated with them, you can use:
var apiKeys = reports.Values.Select(x => x.ApiKey).ToList();
I feel like I'm making this much harder than it needs to be.
In C# using Netwonsoft JSON Compact with external data. Trying to figure out how to deserialize/parse data that looks like
{"http":{"0":{"title":"arbitrary","value":"arbitrary"},"1":{"title":"arbitrary","value":"arbitrary"}},"sip":{"1003":{"title":"arbitrary","value":"none"}}}
It's essentially an array of notifications and the ID -- "0", "1", and "1003" in the above examples is an arbitrary value and appears to have a valid range of 0 and roughly 65535.
But it's not formatted as an array (or I wouldn't be here) -- need help figuring out how to deserialize the value object while essentially ignoring the string identifier.
Thanks in advance
You can't easily deserialize it as an array, but you can deserialize it to a dictionary with integer keys. I don't know about Json.NET Compact, but this works fine with regular Json.NET:
using System;
using System.Collections.Generic;
using System.IO;
using Newtonsoft.Json;
class Root
{
public Dictionary<int, Property> Http { get; set; }
public Dictionary<int, Property> Sip { get; set; }
}
class Property
{
public string Title { get; set; }
public string Value { get; set; }
}
class Test
{
static void Main()
{
string json = File.ReadAllText("test.json");
var root = JsonConvert.DeserializeObject<Root>(json);
foreach (var entry in root.Http)
{
Console.WriteLine($"{entry.Key}: {entry.Value.Title}/{entry.Value.Value}");
}
}
}
If you really need the properties as arrays, I'd suggest having two separate classes: one for the JSON representation, and then another for real usage. For example:
class RootJson
{
public Dictionary<int, Property> Http { get; set; }
public Dictionary<int, Property> Sip { get; set; }
}
class Root
{
// TODO: Control access more :)
public Property[] Http { get; set; }
public Property[] Sip { get; set; }
}
Then:
var rootJson = ...;
var root = new Root
{
Http = rootJson.Http.Values.ToArray(),
Sip = rootJson.Sip.Values.ToArray(),
};
If you can't change the structure of the JSON, you can always do something like this. The dynamic type figures out what to do on runtime.
dynamic d = JsonConvert.DeserializeObject("{'http':{'0':{'title':'arbitrary','value':'arbitrary'},'1':{'title':'arbitrary','value':'arbitrary'}},'sip':{'1003':{'title':'arbitrary','value':'none'}}}");
Console.WriteLine(d.http["0"].title); // arbitrary
foreach(var prop in d.http) {
Console.WriteLine(prop);
}
foreach(var prop in d.sip) {
Console.WriteLine(prop);
}
Final output:
arbitrary
"0": {
"title": "arbitrary",
"value": "arbitrary"
}
"1": {
"title": "arbitrary",
"value": "arbitrary"
}
"1003": {
"title": "arbitrary",
"value": "none"
}
I am calling an external web service and this is what I get in response after posting to their server:
{
"status":200,
"data":{
"h21":{
"total_price":{
"acacia":{
"available":0,
"price":null,
"availability":false
},
"maple":{
"available":7,
"price":2399.0,
"availability":true
}
}
},
"h17":{
"total_price":{
"mahogany":{
"available":1,
"price":1899.0,
"availability":true
},
"oak":{
"available":0,
"price":null,
"availability":false
},
"maple":{
"available":6,
"price":1649.0,
"availability":true
}
}
}
}
}
I want this response to be converted into a list. I used jsontocsharp online converter to generate class and use code below:
var Jsonresult = JsonConvert.DeserializeObject<Sstageback.Models.Sstage.treeboRoomTypes.RootObject>(JsonReplace);
But the thing is mine is a dynamic JSON response which can change over course of time.
Note: The response which I get from the server is hotel and its room availability so while generating classes I can't generate with a single class file since the hotel id's may change also the room types and its availability also changes.
Example: h21 is one hotel id and total_price has its room type details similarly h17 is the next hotel and total_price has its room type details.
Basically, TotalPrice should be a Dictionary<string, Availability> or similar. It's not clear what list you'd have, but that's naturally a dictionary. That's then nested within a dictionary at the top level.
Sample code:
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Newtonsoft.Json;
public class Response
{
public int Status { get; set; }
public Dictionary<string, Hotel> Data { get; set; }
}
public class Hotel
{
[JsonProperty("total_price")]
public Dictionary<string, Room> TotalPrice { get; set; }
}
public class Room
{
public int Available { get; set; }
public decimal? Price { get; set; }
public bool Availability { get; set; }
}
class Test
{
static void Main(string[] args)
{
var text = File.ReadAllText("test.json");
var response = JsonConvert.DeserializeObject<Response>(text);
foreach (var pair in response.Data)
{
Console.WriteLine($"Key: {pair.Key}");
foreach (var nestedPair in pair.Value.TotalPrice)
{
var room = nestedPair.Value;
Console.WriteLine($" {nestedPair.Key}: {room.Available}/{room.Price}/{room.Availability}");
}
}
}
}
Output:
Key: h21
acacia: 0//False
maple: 7/2399.0/True
Key: h17
mahogany: 1/1899.0/True
oak: 0//False
maple: 6/1649.0/True
You'll need to make a DTO model that corresponds with the response. The value of a attribute can change, that's no problem, as long as the type stays the same ( an int stays an int and a string stays a string).
Your Object could look like this:
public class Room{
public int Available { get; set;}
public int Price { get; set; }
public bool availability { get; set; }
}
public class Hotel{
public string Name { get; set; }
public List<Room> Rooms { get; set; }
}
You should convert Serialize and Deserialize this. This is only an example, you want your model to be 100% the same as your JSON.
For an easy conversion between Models and DTO, you could use AutoMapper: http://automapper.org/
I have a web service that is outputting JSON in the form
{"AppointmentList":[{"AppointmentList":{"id":"1","MeetingId":"1","MeetingName":"Test Meeting 1","Length":"90","Room":"B2C","DateTimeFrom":"1st Sept 2016","Venue":"The old pub","DateCreated":"2016-08-30 00:00:00","DateDue":"2016-09-01 00:00:00","UserId":"JohnsonPa"}},{"AppointmentList":{"id":"2","MeetingId":"2","MeetingName":"Test Meeting 2","Length":"60","Room":"B2C","DateTimeFrom":"11th Sept 2016","Venue":"The old pub","DateCreated":"2016-09-01 00:00:00","DateDue":"2016-09-12 00:00:00","UserId":"JohnsonPa"}...}]}
I am trying to deserialise this in to List. Normally, I would have a Base Class that would contain a property List AppointmentList {get; set;}, however, that would mean that I can't use type T and need a pile of duplicate code for each class.
I can certainly create BaseClass with a property public List Data {get; set;} however, as the JSON won't deserialise to Data (incorrect name) and the JSON PropertyName can't be set to the class name derived from typeof(T).ToString().
Is there a way to achieve what I'm trying to do without resorting to lots of code duplication?
I've tried casting the deserialiser to JArray and creating a reader from that, but this throws an exception.
Im not sure if this is exactly what you need, but maybe something like this would work? It allows you to successfully deserialize to a JArray like you state you tried at the end of your question.
JArray result = JsonConvert.DeserializeObject<dynamic>(json).AppointmentList;
Here how to convert it to List<object>
dynamic data = JsonConvert.DeserializeObject(json);
JArray array = data.AppointmentList;
List<object> objectList = array.ToObject<List<object>>();
What is wrong with generics? If you want a schemaless data structure use JObject or dynamic if not you can try this.
class Program
{
public const string json = #"{""AppointmentList"":[{""AppointmentList"":{""id"":""1"",""MeetingId"":""1"",""MeetingName"":""Test Meeting 1"",""Length"":""90"",""Room"":""B2C"",""DateTimeFrom"":""1st Sept 2016"",""Venue"":""The old pub"",""DateCreated"":""2016-08-30 00:00:00"",""DateDue"":""2016-09-01 00:00:00"",""UserId"":""JohnsonPa""}},{""AppointmentList"":{""id"":""2"",""MeetingId"":""2"",""MeetingName"":""Test Meeting 2"",""Length"":""60"",""Room"":""B2C"",""DateTimeFrom"":""11th Sept 2016"",""Venue"":""The old pub"",""DateCreated"":""2016-09-01 00:00:00"",""DateDue"":""2016-09-12 00:00:00"",""UserId"":""JohnsonPa""}}]}";
static void Main(string[] args)
{
var items = Newtonsoft.Json.JsonConvert.DeserializeObject<AppointmentItemList<Meeting1>>(json).GetList();
var items2 = Newtonsoft.Json.JsonConvert.DeserializeObject<AppointmentItemList<Meeting2>>(json).GetList();
Console.ReadLine();
}
public class AppointmentItemList<T>
{
public List<AppointmentItem> AppointmentList { get; set; }
public class AppointmentItem
{
public T AppointmentList { get; set; }
}
public IList<T> GetList()
{
return AppointmentList.Select(al => al.AppointmentList).ToList();
}
}
public class Meeting1
{
[Newtonsoft.Json.JsonProperty("id")]
public string Id { get; set; }
public string MeetingName { get; set; }
}
public class Meeting2
{
[Newtonsoft.Json.JsonProperty("id")]
public string Id { get; set; }
public string Room { get; set; }
}
}
How to list all minecraft profiles by launcher_profiles.json file?
I tried to use the site json2csharp.com, but unfortunately when it generated the class ready code he has returned all the profiles as if it were also a class.
for example:
I used this simple code minecraft profile file ...
{
"profiles": {
"1.7.10": {
"name": "1.7.10",
"lastVersionId": "1.7.10"
}
},
"selectedProfile": "1.7.10"
}
But when I send the site to convert C# it returns this:
public class __invalid_type__1710
{
public string name { get; set; }
public string lastVersionId { get; set; }
}
public class Profiles
{
public __invalid_type__1710 __invalid_name__1.7.10 { get; set; }
}
public class RootObject
{
public Profiles profiles { get; set; }
public string selectedProfile { get; set; }
}
See for yourself: Json2CSharp
Have you any way I can read the launcher_profiles.json file minecraft using Newtonsoft.Json.Linq?
While useful in many cases, json2csharp.com is not foolproof. As you've seen, it does not handle cases where key names are dynamic or otherwise cannot be converted into valid C# identifiers. In these cases you will need to make manual adjustments to the generated classes. For example, you can use a Dictionary<string, Profile> in place of a static class to handle the dynamic keys of the profiles object.
Define your classes like this:
public class RootObject
{
public Dictionary<string, Profile> profiles { get; set; }
public string selectedProfile { get; set; }
}
public class Profile
{
public string name { get; set; }
public string lastVersionId { get; set; }
}
You can then deserialize into the RootObject class using either JavaScriptSerializer or Json.Net, whichever you prefer.
Here is a fiddle using Json.Net: https://dotnetfiddle.net/ZlEK63
So the problem may be that the launcher_profiles.json is not really kosher JSON.
Put this into Json2CSharp to see what I mean:
{
"profiles": [
{
"name": "1.7.10",
"lastVersionId": "1.7.10"
}
],
"selectedProfile": "1.7.10"
}
The difference here is that I've redefined the profiles node to correctly represent a collection (array) that's mapped to a generic list in C#.
You may need to manually parse that file as JSON.Net or other options will not be able to work with the invalid json format.
I generally don't work with the Linq versions of the Json.Net library, but I've come up with a simple example of how to get all of the names of the profiles (you can't serialize to a class with the given format).
class Program
{
//Add another "profile" to show this works with more than one
private static String json = "{ \"profiles\": { \"1.7.10\": { \"name\": \"1.7.10\", \"lastVersionId\": \"1.7.10\" }, \"1.7.11\": { \"name\": \"1.7.11\", \"lastVersionId\": \"1.7.11\" } }, \"selectedProfile\": \"1.7.10\" }";
static void Main(string[] args)
{
//Parse to JObject
var obj = Newtonsoft.Json.Linq.JObject.Parse(json);
foreach (var profile in obj["profiles"])
{
foreach (var child in profile.Children())
{
Console.WriteLine(child["name"]);
}
}
}
}