In my service class constructor I populate two repositories:
private List<BackupRule> rules;
private List<BackupPath> paths;
public RuleService()
{
List<BackupRule> _rules = new List<BackupRule>();
List<BackupPath> _paths = new List<BackupPath>();
using (var wc = new System.Net.WebClient())
{
string json = wc.DownloadString(jsonRuleFile);
if (json.Length > 0)
{
_rules = JsonConvert.DeserializeObject<List<BackupRule>>(json);
_paths = JsonConvert.DeserializeObject<List<BackupPath>>(json);
}
}
rules = _rules;
paths = _paths;
}
Then I try to create a rule and add the rule to the repository:
code to create the rules
IRuleService db = new RuleService();
List<BackupPath> paths = new List<BackupPath>();
paths.Add(new BackupPath { Type = PathType.Source, Value = "C:\\Test\\" });
paths.Add(new BackupPath { Type = PathType.Destination, Value = "C:\\Test\\" });
paths.Add(new BackupPath { Type = PathType.Source, Value = "C:\\Test\\" });
paths.Add(new BackupPath { Type = PathType.Source, Value = "C:\\Test\\" });
BackupRule rule1 = new BackupRule() { Name = "test1", Type = RuleType.Archive, UserName = System.Environment.UserName, Paths = paths, EndOfDay = true, Created = DateTime.Now};
BackupRule rule2 = new BackupRule() { Name = "test2", Type = RuleType.Archive, UserName = System.Environment.UserName, Paths = paths, EndOfDay = true, Created = DateTime.Now };
db.CreateRule(rule1);
db.CreateRule(rule2);
db.SaveChanges();
Interface Methods that add the rules to the repositories
public BackupRule CreateRule(BackupRule rule)
{
if (rules.Any(r => r.Name == rule.Name))
{
return null;
}
rule.Paths = rule.Paths.OrderBy(p => p.Type.GetHashCode()).ToList();
foreach (BackupPath path in rule.Paths)
{
path.Id = (paths.Count() == 0) ? 1 : paths.LastOrDefault().Id + 1;
paths.Add(path);
}
rule.Id = (rules.Count() == 0) ? 1 : rules.LastOrDefault().Id + 1;
rules.Add(rule);
rules = rules.OrderBy(r => r.Id).ToList();
return rule;
}
Interface Method that serializes (sic?) back to json
public void SaveChanges()
{
using (FileStream fileStream = File.Open(#jsonRuleFile, FileMode.OpenOrCreate))
using (StreamWriter streamWriter = new StreamWriter(fileStream))
using (JsonWriter jsonWriter = new JsonTextWriter(streamWriter))
{
jsonWriter.Formatting = Formatting.Indented;
JsonSerializer serializer = new JsonSerializer();
serializer.Serialize(jsonWriter, rules);
serializer.Serialize(jsonWriter, paths);
}
}
json output
[
{
"Id": 1,
"Name": "test1",
"UserName": "Aaron",
"rule_type": "Archive",
"Paths": [
{
"$id": "1",
"Id": 5,
"Value": "C:\\Test\\",
"Type": "Source"
},
{
"$id": "2",
"Id": 6,
"Value": "C:\\Test\\",
"Type": "Source"
},
{
"$id": "3",
"Id": 7,
"Value": "C:\\Test\\",
"Type": "Source"
},
{
"$id": "4",
"Id": 8,
"Value": "C:\\Test\\",
"Type": "Destination"
}
],
"EndOfDay": true,
"Created": "2014-07-12T20:14:03.9126784-05:00"
},
{
"Id": 2,
"Name": "test2",
"UserName": "Aaron",
"rule_type": "Archive",
"Paths": [
{
"$ref": "1"
},
{
"$ref": "2"
},
{
"$ref": "3"
},
{
"$ref": "4"
}
],
"EndOfDay": true,
"Created": "2014-07-12T20:14:03.9126784-05:00"
}
][
{
"Id": 5,
"Value": "C:\\Test\\",
"Type": "Source"
},
{
"Id": 6,
"Value": "C:\\Test\\",
"Type": "Source"
},
{
"Id": 7,
"Value": "C:\\Test\\",
"Type": "Source"
},
{
"Id": 8,
"Value": "C:\\Test\\",
"Type": "Destination"
},
{
"Id": 5,
"Value": "C:\\Test\\",
"Type": "Source"
},
{
"Id": 6,
"Value": "C:\\Test\\",
"Type": "Source"
},
{
"Id": 7,
"Value": "C:\\Test\\",
"Type": "Source"
},
{
"Id": 8,
"Value": "C:\\Test\\",
"Type": "Destination"
}
]
Classes being serialized
// using statements added to post to help
// reader understand I am using Json.Net
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
public class BackupRule
{
[JsonProperty]
public int Id { get; set; }
[JsonProperty]
public string Name { get; set; }
public string UserName { get; set; }
[JsonProperty(PropertyName = "rule_type")]
[JsonConverter(typeof(StringEnumConverter))]
public RuleType Type { get; set; }
[JsonProperty(ItemIsReference = true)]
public List<BackupPath> Paths { get; set; }
public bool EndOfDay { get; set; }
public DateTime Created { get; set; }
}
public class BackupPath
{
public int Id { get; set; }
public string Value { get; set; }
[JsonConverter(typeof(StringEnumConverter))]
public PathType Type { get; set; }
}
The problem(s) is the json isn't even a proper format it gives me:
Warning 1 Only one top-level array or object is allowed in a JSON document.
And it doesn't actually reference the serialized BackupPath class it just references other BackupPaths created in other BackupRule objects. Where did I go wrong here? Ideally I would like it to create two "tables" out of the lists and have the BackupRule reference the BackupPaths "table" much like it does in the second BackupRule example but instead of BackupRule #2 referencing BackupPath stored in BackupRule #1 I'd rather both reference the serialized BackupPath "table". Also ideally i'd like to store both of the serialized lists in one json file, but I am flexible on this.
As to the warning, that's because you have this:
serializer.Serialize(jsonWriter, rules);
serializer.Serialize(jsonWriter, paths);
As the warning says, JSON really can only have 1 top level element and you have written 2 top level elements. To make the warning go away, you could wrap rules and paths into a single object:
serializer.Serialize(jsonWriter, new {Rules = rules, Paths = paths});
Related
I believe I checked all the recursive JSON sections on here, none seem even recursive but whatever. I have a challenge. How do I iterate through all the depts of this JSON? This JSON has a depth of 200 and that's not even the biggest one.
The JSON "Recursive" is not even a true array, there's only 1 item.
{
"schema": [
{
"#id": 1,
"recursive": [
{
"#Id": 2,
"from": {
"#id": 1,
"recursive": [
{
"#Id": 2,
"from": {
"#id": 1,
"recursive": [
"#Id": 2,
"from" : 49
]
}
}
]
}
}
]
}
]
}
My Configuration classes
public class rootSchema
{
[JsonProperty("#id")]
public int #id { get; set; }
[JsonProperty("recursive")]
public List<recursive> recursive { get; set; }
}
public class from
{
[JsonProperty("#id")]
public int #id { get; set; }
[JsonProperty("recursive")]
public List<recursive> recursive { get; set; }
}
public class recursive
{
[JsonProperty("from")]
public from from { get; set; }
[JsonProperty("recursive")]
public List<recursive> recursive { get; set; }
}
When I attempt to deserialize this using NewtonSoft.JSON Deserializer, I get an int64 conversion error
Newtonsoft.Json.JsonSerializationException:
'Error converting value 49 to type 'Proj.recursive.from'. Path
'recursive[0].from.recursive[0].from.recursive[0].from.recursive[0]
.from.recursive[0].from.recursive[0].from.recursive[0].from.recursive[0]
.from.recursive[0].from.recursive[0].from.recursive[0].from.recursive[0]
.from.recursive[0].from.recursive[0].from.recursive[0].from.recursive[0]
.from.recursive[0].from.recursive[0].from.recursive[0].from.recursive[0]
.from.recursive[0].from.recursive[0].from.recursive[0].from.recursive[0]
.from.recursive[0].from', line 1, position 16273.'
I found the cause of this, because in the last element "from", its not a list, its an integer
"from": 49,
So I am not even sure how to account for a list, & and integer in my definitions. My second issue is, I'm not sure how to iterate through the recursion to get all the "recursive" elements.
Solved it. Im just going to leave this here
Defs
using Newtonsoft.Json;
using System.Collections.Generic;
namespace theHack
{
public class Root
{
[JsonProperty("ratsnest")]
public ratsnest ratsnest { get; set; }
}
public class ratsnest
{
[JsonProperty("garbagepile")]
public List<object> garbagepile { get; set; }
}
public class garbagepile
{
[JsonProperty("#id")]
public int #id { get; set; }
[JsonProperty("hammeredhotpoop")]
public List<object> hammeredhotpoop { get; set; }
}
public class hammeredhotpoop
{
[JsonProperty("#transitionId")]
public int #transitionId { get; set; }
[JsonProperty("nohumorleft")]
public object nohumorleft { get; set; }
}
public class outgoingTransitions
{
[JsonProperty("#transitionId")]
public int #transitionId { get; set; }
[JsonProperty("nohumorleft")]
public object nohumorleft { get; set; }
}
public class nohumorleft
{
[JsonProperty("#id")]
public int #id { get; set; }
[JsonProperty("hammeredhotpoop")]
public List<object> hammeredhotpoop { get; set; }
}
}
The "logic"... it compiles
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.IO;
namespace theHack
{
internal class Program
{
static void Main(string[] args)
{
string _data_file = GetFile();
// going normal, this is expected
Root root = JsonConvert.DeserializeObject<Root>(_data_file, new JsonSerializerSettings() { TypeNameHandling = TypeNameHandling.All, MaxDepth = 200, NullValueHandling = NullValueHandling.Ignore });
// can only be 1 root state, everything goes downhill from here
var parent = root.ratsnest.garbagepile[0];
//strip all the stupid ids, must repeat this because any element can return any type
var parentSerialized = JsonConvert.SerializeObject(parent);
// begin the descent to only lord knows where
garbagepile handful = JsonConvert.DeserializeObject<garbagepile>(parentSerialized, new JsonSerializerSettings() { TypeNameHandling = TypeNameHandling.All, MaxDepth = 200, NullValueHandling = NullValueHandling.Ignore });
// Can be integer or Jobject, who the heck knows, maybe a trainwreck managed to find its way here
List<object> incoming = handful.hammeredhotpoop;
foreach (var crap in incoming)
{
// whyyyyyyyyyyyyyyyy
if (crap.GetType() != typeof(int))
{
var rootOfEvil = JsonConvert.SerializeObject(crap);
// thank you James Newton King for making the longest constructor I've ever seen
hammeredhotpoop firstSeedOfEvil = JsonConvert.DeserializeObject<hammeredhotpoop>(rootOfEvil, new JsonSerializerSettings() { TypeNameHandling = TypeNameHandling.All, MaxDepth = 200, NullValueHandling = NullValueHandling.Ignore });
Console.WriteLine($"#transitionId: {firstSeedOfEvil.transitionId}");
var firstHorseman = JsonConvert.SerializeObject(firstSeedOfEvil.nohumorleft);
nohumorleft forgotwhatIwasDoing = JsonConvert.DeserializeObject<nohumorleft>(firstHorseman, new JsonSerializerSettings() { TypeNameHandling = TypeNameHandling.All, MaxDepth = 200, NullValueHandling = NullValueHandling.Ignore });
List<object> currentCrap = forgotwhatIwasDoing.hammeredhotpoop;
Console.WriteLine($"#id: {forgotwhatIwasDoing.#id}");
//loop
do
{
for (int i = 0; i < currentCrap.Count; i++)
{
//deserialize the List<object>
hammeredhotpoop omgIgiveup = updatemyresume(currentCrap[i]);
//output something
Console.WriteLine($"#transitionId: {omgIgiveup.transitionId}");
// create typed version from this current Transition
nohumorleft deserializedfirstHorseman = barreloflaughs(omgIgiveup.nohumorleft);
Console.WriteLine($"#id: {deserializedfirstHorseman.#id}");
//get the next set of incomingTansitions
currentCrap = deserializedfirstHorseman.hammeredhotpoop;
}
} while (currentCrap != null);
}
}
Console.ReadLine();
}
public static hammeredhotpoop updatemyresume(object garbageIn)
{
if (garbageIn.GetType() != typeof(int))
{
var hammerIt = JsonConvert.SerializeObject(garbageIn);
hammeredhotpoop garbageOut = JsonConvert.DeserializeObject<hammeredhotpoop>(hammerIt, new JsonSerializerSettings() { TypeNameHandling = TypeNameHandling.All, MaxDepth = 200, NullValueHandling = NullValueHandling.Ignore });
return garbageOut;
}
else { return null; }
}
public static nohumorleft barreloflaughs(object garbageIn)
{
var hammerIt = JsonConvert.SerializeObject(garbageIn);
nohumorleft garbageOut = JsonConvert.DeserializeObject<nohumorleft>(hammerIt, new JsonSerializerSettings() { TypeNameHandling = TypeNameHandling.All, MaxDepth = 200, NullValueHandling = NullValueHandling.Ignore });
return garbageOut;
}
public static string GetFile()
{
var fileName = #"C:\Users\me\source\test.json";
if (File.Exists(fileName))
{
using (StreamReader file = new StreamReader(fileName))
{
string text = File.ReadAllText(fileName);
file.Close();
return text;
}
}
else
{
Console.WriteLine("File does not exist");
return null;
}
}
}
}
a representation of the JSON
{
"ThisWasActuallyAnArray": [
{
"surprising": [
{
"typeNull": null,
"connectionId": "233ad541-7468-49b5-a7bb-dddddd",
"id": 29531,
"name": "funnyTown",
"letsEmbedSomeJson": "{\"id\":\"234\",..."
}
],
"type": "",
"id": 46243,
"name": "somestring"
}
],
"ratsnest": {
"whynot": null,
"garbagepile": [
{
"#id": 1,
"subData": null,
"subDataClass": "",
"id": "123-abc",
"hammeredhotpoop": [
{
"#transitionId": 4,
"datastuff": {
"abool": false,
"astring": "anyway",
"anInt": 1
},
"anotherRabbitHole2": 3,
"id": "123",
"name": "...",
"anotherRabbitHole": {
"#id": 5,
"someData": {
"setting1": true,
"Grouping": "FooBar",
"str1": "60",
"aBool": true,
"id": 5
},
"config": "somedata",
"id": "123",
"nohumorleft": {},
"name": "",
"notes": ""
},
"nohumorleft": {
"#id": 9,
"listData": {},
"id": "123",
"hammeredhotpoop": [
{
"#transitionId": 4,
"datastuff": {
"abool": false,
"astring": "anyway",
"anInt": 1
},
"anotherRabbitHole2": 3,
"id": "123",
"name": "...",
"anotherRabbitHole": {
"#id": 5,
"someData": {
"setting1": true,
"Grouping": "FooBar",
"str1": "60",
"aBool": true,
"id": 5
},
"config": "somedata",
"id": "123",
"nohumorleft": {},
"name": "",
"notes": ""
},
"nohumorleft": [
{
"#id": 9,
"listData": {},
"id": "123",
"hammeredhotpoop": [
{
"#transitionId": 4,
"datastuff": {
"abool": false,
"astring": "anyway",
"anInt": 1
},
"anotherRabbitHole2": 3,
"id": "123",
"name": "...",
"anotherRabbitHole": {
"#id": 5,
"someData": {
"setting1": true,
"Grouping": "FooBar",
"str1": "60",
"aBool": true,
"id": 5
},
"config": "somedata",
"id": "123",
"nohumorleft": {},
"name": "",
"notes": ""
},
"nohumorleft": {
"#id": 9,
"listData": {},
"id": "123",
"hammeredhotpoop": [
{
"#transitionId": 4,
"datastuff": {
"abool": false,
"astring": "anyway",
"anInt": 1
},
"anotherRabbitHole2": 3,
"id": "123",
"name": "...",
"anotherRabbitHole": {
"#id": 5,
"someData": {
"setting1": true,
"Grouping": "FooBar",
"str1": "60",
"aBool": true,
"id": 5
},
"config": "somedata",
"id": "123",
"name": "",
"notes": "",
"nohumorleft": 49
}
}
]
}
}
]
},
"3",
"2",
"1",
"upskill",
true
]
}
]
}
},
5,
4,
3,
2,
1,
"LOL"
],
"notes": "",
"someInt": 0,
"type": "",
"hammeredhotboogers": [],
"listData": {}
}
]
}
}
I have a model class that allows users to specify the template which is used to create content with specified properties.
public class Model
{
public string Id { get; set; }
public string Alias { get; set; }
public ICollection<Field> Fields { get; set; }
}
public class Field
{
public FieldType Type { get; set; }
public string Alias { get; set; }
}
public enum FieldType
{
String = 1,
Email = 2,
Password = 3,
DateTime = 4,
Integer = 5,
Decimal = 6,
...
}
The content that is created based on this template will have the structure as below:
public class Entry
{
public string _id { get; set; }
public List<FieldValue> FieldValues { get; set; }
}
public class FieldValue
{
public object Value { get; set; }
public string Alias { get; set; }
public FieldType Type { get; set; }
}
So, I for example, can have data such as:
PersonModel
{
"id": "34752b15",
"alias": "person",
"fields": [
{
"type": 1,
"alias": "name"
},
{
"type": 2,
"alias": "email"
}
]
}
PersonEntries:
[
{
"_id": "426e",
"fieldValues": [
{
"alias": "name",
"value": "John",
"type": 1
},
{
"alias": "email",
"value": "john#stark.com",
"type": 2
}
]
},
{
"_id": "c6110fc3cc0e",
"fieldValues": [
{
"alias": "name",
"value": "Arya",
"type": 1
},
{
"alias": "email",
"value": "arya#stark.com",
"type": 2
}
]
}
]
Or:
ShapeModel
{
"id": "afd69af4",
"alias": "shape",
"fields": [
{
"type": 1,
"alias": "name"
},
{
"type": 6,
"alias": "area"
},
{
"type": 6,
"alias": "perimeter"
}
]
}
ShapeEntries:
[
{
"_id": "426e",
"fieldValues": [
{
"alias": "name",
"value": "my-square",
"type": 1
},
{
"alias": "area",
"value": 1,
"type": 6
},
{
"alias": "perimeter",
"value": 4,
"type": 6
}
]
},
{
"_id": "426enbv",
"fieldValues": [
{
"alias": "name",
"value": "my-triangle",
"type": 1
},
{
"alias": "area",
"value": 0.5,
"type": 6
},
{
"alias": "perimeter",
"value": 3,
"type": 6
}
]
}
]
and so on.
The idea is to create graphql schemas dynamically (on runtime) when a new model is created and allow users to query entries based on the model alias.
What I tried is:
public ISchema CreateEntrySchema(List<Entry> entries, Model model, IServiceCollection services)
{
var entryType = new ObjectGraphType() { Name = model.Alias };
entryType.Field("_id", new IdGraphType());
foreach (var field in model.Fields)
{
if (entryType.Fields.FirstOrDefault(f => f.Name == field.Alias) != null)
{
continue;
}
Type clrGraphType = field.Type.GetStandardType().GetGraphTypeFromType(isNullable: true);
IGraphType graphType = (IGraphType)Activator.CreateInstance(clrGraphType);
entryType.Field(field.Alias,
graphType,
resolve: context =>
{
var entry = (Entry)context.Source;
object firstOrDefault = entry?.FieldValues.FirstOrDefault(value => value.Alias == context.FieldDefinition.Name)?.Value;
return firstOrDefault;
});
}
var queryType = new ObjectGraphType();
queryType.Field(
model.Alias,
type: new ListGraphType(entryType),
arguments: new QueryArguments(ConstructArguments(model.Fields)),
resolve: context =>
{
List<KeyValuePair<string, ArgumentValue>> args = context.Arguments?.Where(pair => pair.Value.Value != null).ToList();
if (!args?.Any() ?? true)
{
return entries;
}
return args.Aggregate(entries, (current, pair) =>
current.Where(entry => entry.FieldValues.FirstOrDefault(field => field.Alias == pair.Key) != null && entry.FieldValues.FirstOrDefault(field => field.Alias == pair.Key).Value.Equals(pair.Value.Value))
.ToList());
});
ISchema schema = new Schema { Query = queryType };
schema.RegisterType(entryType);
services.AddGraphQL(a =>
{
a.AddSchema(schema).AddClrTypeMappings();
});
return schema;
}
The problem is that it is registering only the last schema. So, for example, if I will call this method like:
CreateEntrySchema(personEntries, personModel, services);
CreateEntrySchema(shapeEntries, shapeModel, services);
And query like this:
{
shape{
name
}
person{
name
}
}
The result is:
"GraphQL.Validation.Errors.FieldsOnCorrectTypeError: Cannot query field 'person' on type 'Object'. Did you mean 'shape'?",
Given 2 JSON strings:
[
{
"id":"BA",
"description":"BrandA",
"values":[
{
"id":"CategoryA",
"description":"CategoryA"
},
{
"id":"CategoryB",
"description":"CategoryB"
},
{
"id":"CategoryC",
"description":"CategoryC"
},
{
"id":"CategoryD",
"description":"CategoryD"
},
{
"id":"CategoryE",
"description":"CategoryE"
},
{
"id":"CategoryF",
"description":"CategoryF"
},
{
"id":"CategoryG",
"description":"CategoryG"
},
{
"id":"CategoryH",
"description":"CategoryH"
}
]
},
{
"id":"BB",
"description":"BrandB",
"values":[
{
"id":"CategoryA",
"description":"CategoryA"
},
{
"id":"CategoryB",
"description":"CategoryB"
},
{
"id":"CategoryC",
"description":"CategoryC"
}
]
}
]
AND
[
{
"id":"BA",
"description":"BrandA",
"values":[
{
"id":"CategoryA",
"description":"CategoryA"
},
{
"id":"CategoryC",
"description":"CategoryC"
}
]
},
{
"id":"BB",
"description":"BrandB",
"values":[
{
"id":"CategoryB",
"description":"CategoryB"
}
]
}
]
First one is the original. The second are the values that I want to remove from the original. So basically, if there is a match on brand and category between first and second JSON, regardless of the order of the elements, I want that match to be removed.
The expected result would be someting like this:
[
{
"id":"BA",
"description":"BrandA",
"values":[
{
"id":"CategoryB",
"description":"CategoryB"
},
{
"id":"CategoryD",
"description":"CategoryD"
},
{
"id":"CategoryE",
"description":"CategoryE"
},
{
"id":"CategoryF",
"description":"CategoryF"
},
{
"id":"CategoryG",
"description":"CategoryG"
},
{
"id":"CategoryH",
"description":"CategoryH"
}
]
},
{
"id":"BB",
"description":"BrandB",
"values":[
{
"id":"CategoryA",
"description":"CategoryA"
},
{
"id":"CategoryC",
"description":"CategoryC"
}
]
}
]
Catagory A and C in Brand A were removed as well as Category B in Brand B.
Based in some research, I was using https://github.com/wbish/jsondiffpatch.net, tried to work with it's functions, but so far I didn't manage to achieve the result I want. Also, to solve this by processing JSON direcly is not a must. If there is a simpler solution to achieve that by converting them to lists and use something like LINQ for example, it works for me as well (tried that, but didn't manage to find a way to do this comparison).
Thanks in advance.
If performance does not matter, the JsonSerializer and LINQ can be used:
Model
public class JsonModel
{
public class ValueModel
{
public string Id { get; set; }
public string Description { get; set; }
}
public string Id { get; set; }
public string Description { get; set; }
public IEnumerable<ValueModel> Values { get; set; }
}
Deserialize and LINQ
string json1Str = #"[...]";
string json2Str = #"[...]";
var opt = new System.Text.Json.JsonSerializerOptions { PropertyNameCaseInsensitive = true };
var json1 = System.Text.Json.JsonSerializer.Deserialize<List<JsonModel>>(json1Str, opt);
var json2 = System.Text.Json.JsonSerializer.Deserialize<List<JsonModel>>(json2Str, opt);
var result = json1.
Join(json2, j1 => j1.Id, j2 => j2.Id, (j1, j2) => new JsonModel
{
Id = j1.Id,
Description = j1.Description,
Values = j1.Values.Where(j1 => !j2.Values.Select(val => val.Id).Contains(j1.Id))
});
Console.WriteLine(System.Text.Json.JsonSerializer.Serialize(result, new System.Text.Json.JsonSerializerOptions { WriteIndented = true }));
}
Result
[
{
"Id": "BA",
"Description": "BrandA",
"Values": [
{
"Id": "CategoryB",
"Description": "CategoryB"
},
{
"Id": "CategoryD",
"Description": "CategoryD"
},
{
"Id": "CategoryE",
"Description": "CategoryE"
},
{
"Id": "CategoryF",
"Description": "CategoryF"
},
{
"Id": "CategoryG",
"Description": "CategoryG"
},
{
"Id": "CategoryH",
"Description": "CategoryH"
}
]
},
{
"Id": "BB",
"Description": "BrandB",
"Values": [
{
"Id": "CategoryA",
"Description": "CategoryA"
},
{
"Id": "CategoryC",
"Description": "CategoryC"
}
]
}
]
How do I create a JSON array using Newtonsoft.JSON (json.net) from this json string
[
{
"Cells": {
"results": [
{
"Key": "Title",
"Value": "hello",
"ValueType": "Edm.String"
},
{
"Key": "Size",
"Value": "54549",
"ValueType": "Edm.Int64"
},
{
"Key": "Path",
"Value": "http://somesite/a/hello.pptx",
"ValueType": "Edm.String"
},
{
"Key": "Summary",
"Value": "Some summary <ddd/> interesting reading <ddd/> nice book <ddd/> ",
"ValueType": "Edm.String"
},
{
"Key": "Name",
"Value": "http://somesite",
"ValueType": "Edm.String"
}
]
}
},
{
"Cells": {
"results": [
{
"Key": "Title",
"Value": "hi joe",
"ValueType": "Edm.String"
},
{
"Key": "Size",
"Value": "41234",
"ValueType": "Edm.Int64"
},
{
"Key": "Path",
"Value": "http://someothersite/interesting/hi.pptx",
"ValueType": "Edm.String"
},
{
"Key": "Summary",
"Value": "Some summary <ddd/> interesting reading <ddd/> nice book <ddd/> ",
"ValueType": "Edm.String"
},
{
"Key": "Name",
"Value": "http://somesite",
"ValueType": "Edm.String"
}
]
}
}
]
json2csharp gives me following classes for this structure
public class Result
{
public string Key { get; set; }
public string Value { get; set; }
public string ValueType { get; set; }
}
public class Cells
{
public List<Result> results { get; set; }
}
public class RootObject
{
public Cells Cells { get; set; }
}
How do I use these classes to create json array?
UPDATE AND SOLUTION
this will work
static void Main(string[] args)
{
RootObject ro = new RootObject();
Cells cs = new Cells();
cs.results = new List<Result>();
Result rt = new Result();
rt.Key = "Title";
rt.Value = "hello";
rt.ValueType = "Edm.String";
cs.results.Add(rt);
Result rs = new Result();
rs.Key = "Size";
rs.Value = "3223";
rs.ValueType = "Edm.Int64";
cs.results.Add(rs);
ro.Cells = cs;
string json = JsonConvert.SerializeObject(ro);
}
this will work
static void Main(string[] args)
{
RootObject ro = new RootObject();
Cells cs = new Cells();
cs.results = new List<Result>();
Result rt = new Result();
rt.Key = "Title";
rt.Value = "hello";
rt.ValueType = "Edm.String";
cs.results.Add(rt);
Result rs = new Result();
rs.Key = "Size";
rs.Value = "3223";
rs.ValueType = "Edm.Int64";
cs.results.Add(rs);
ro.Cells = cs;
string json = JsonConvert.SerializeObject(ro);
}
You're looking for the function DeserializeObject<T>:
var json = ""; // string up above in your code
var jObect = JsonConvert.DeserializeObject<RootObject>(json);
// Use
var cells = jObject.Cells;
var result1 = cells.results.FirstOrDefault();
Given an example of a POCO below:
public class Account
{
public string Email { get; set; }
public bool Active { get; set; }
public DateTime CreatedDate { get; set; }
public IList<string> Roles { get; set; }
}
This can be achieved by deserializing your JSON string show below:
string json = #"{
'Email': 'james#example.com',
'Active': true,
'CreatedDate': '2013-01-20T00:00:00Z',
'Roles': [
'User',
'Admin'
]
}";
Account account = JsonConvert.DeserializeObject<Account>(json);
Console.WriteLine(account.Email);
Reference Newtonsoft's documentation below:
http://www.newtonsoft.com/json/help/html/DeserializeObject.htm
If you want the string representation of an object, especially a json object, the most relevant is .ToString ().
But, it could fail for other reasons ...
I am trying to deserialize an AchievementConfigurations: list REST Response from here https://developers.google.com/games/services/publishing/api/achievementConfigurations/list.
The problem is that this line only fills out the top level object and the List remains empty. No error messages are throw which makes this difficult to track down what is going on. I used a website to generate the json structured classes and after that I removed the duplicates which where unnecessary.
The response looks like this, I have removed the achievementConfiguration resource because it is really long but it can be found here https://developers.google.com/games/services/publishing/api/achievementConfigurations#resource
{
"kind": "gamesConfiguration#achievementConfigurationListResponse",
"nextPageToken": string,
"items": [
achievementConfigurations Resource
]
}
I have a series of classes I have created mirroring the data starting with the AchievementConfigurationListResponse class
public class AchievementConfigurationListResponse
{
public string kind = "gamesConfiguration#achievementConfigurationListResponse";
public string nextPageToken = "";
List<AchievementConfigurationResource> items = new List<AchievementConfigurationResource>();
}
Next up is the AchievementConfigurationResource which is an item in the list, it has several nested objects
public class AchievementConfigurationResource
{
public static string[] types = new string[] { "STANDARD", "INCREMENTAL" };
public static string[] states = new string[] { "REVEALED", "HIDDEN", "UNLOCKED" };
public string kind = "gamesConfiguration#achievementConfiguration";
public string token = "";
public string id = "";
public string achievementType = types[0];
public string initialState = states[0];
public int? stepsToUnlock;
public AchievementConfigurationDetail draft = new AchievementDataResource();
public AchievementConfigurationDetail published = new AchievementDataResource();
}
Those nested object are of this type of AchievementConfigurationDetail
public class AchievementConfigurationDetail
{
public string kind = "gamesConfiguration#achievementConfigurationDetail";
public LocalizedStringBundle name = new LocalizedStringBundle();
public LocalizedStringBundle description = new LocalizedStringBundle();
public int pointValue = 5;
public string iconUrl = "";
public int sortRank = 1;
}
Which contains several LocalizedStringBundles
public class LocalizedStringBundle
{
public string kind = "gamesConfiguration#localizedStringBundle";
public List<Translation> translations = new List<Translation>();
public class Translation
{
public string kind = "gamesConfiguration#localizedString";
public string locale = "en-US";
public string value = "";
}
}
I call this on the json with the following line:
AchievementConfigurationListResponse res = JsonConvert.DeserializeObject<AchievementConfigurationListResponse>(content);
Here is a copy of the response, sensitive data removed but the keys and structure are all intact. This one only contains a single record because the full file is something like 5000 lines long.
{
"kind": "gamesConfiguration#achievementConfigurationListResponse",
"items": [
{
"kind": "gamesConfiguration#achievementConfiguration",
"token": "Unique Token",
"id": "Unique ID",
"achievementType": "STANDARD",
"initialState": "REVEALED",
"draft": {
"kind": "gamesConfiguration#achievementConfigurationDetail",
"name": {
"kind": "gamesConfiguration#localizedStringBundle",
"translations": [
{
"kind": "gamesConfiguration#localizedString",
"locale": "en-US",
"value": "Name"
}
]
},
"description": {
"kind": "gamesConfiguration#localizedStringBundle",
"translations": [
{
"kind": "gamesConfiguration#localizedString",
"locale": "en-US",
"value": "Description"
}
]
},
"pointValue": 5,
"iconUrl": "Icon url",
"sortRank": 1
},
"published": {
"kind": "gamesConfiguration#achievementConfigurationDetail",
"name": {
"kind": "gamesConfiguration#localizedStringBundle",
"translations": [
{
"kind": "gamesConfiguration#localizedString",
"locale": "en-US",
"value": "Name"
}
]
},
"description": {
"kind": "gamesConfiguration#localizedStringBundle",
"translations": [
{
"kind": "gamesConfiguration#localizedString",
"locale": "en-US",
"value": "Description"
}
]
},
"pointValue": 5,
"iconUrl": "Icon url",
"sortRank": 1
}
}
]
}
Json.NET does not serialize private members by default. Thus you need to make AchievementConfigurationListResponse.items be public:
public List<AchievementConfigurationResource> items = new List<AchievementConfigurationResource>();
Alternatively, mark it with [JsonProperty] which enables serialization of private members:
[JsonProperty]
List<AchievementConfigurationResource> items = new List<AchievementConfigurationResource>();