JSON .NET Not Deserializing Refs - c#

I have the following minimal example:
class Program
{
static void Main()
{
var plan = new Plan
{
Steps =
{
new Step
{
Contexts =
{
new Context
{
Name = "1"
},
new Context
{
Name = "2"
}
}
}
}
};
var settings = new JsonSerializerSettings
{ PreserveReferencesHandling = PreserveReferencesHandling.Objects, Formatting = Formatting.Indented };
var json = JsonConvert.SerializeObject(plan, settings);
var deserialized = JsonConvert.DeserializeObject<Plan>(json, settings);
}
}
class Plan
{
public IEnumerable AllContexts => Steps.SelectMany(i => i.Contexts);
[JsonProperty(Order = int.MaxValue)]
public ICollection<Step> Steps { get; set; } = new List<Step>();
}
class Step
{
public ICollection<Context> Contexts { get; set; } = new List<Context>();
}
class Context
{
public string Name { get; set; }
}
In this example deserialized has lost its references upon deserialization and deserialized.AllContexts is a collection of 2 null values.
I can get this working by changing [JsonProperty(Order = int.MaxValue)] to [JsonProperty(Order = int.MinValue)] so the Steps are serialized first - but in my scenario I want the actual JSON to have all its properties on the flat AllContexts array and for the Steps to only have $refs like this:
{
"$id": "1",
"AllContexts": [
{
"$id": "2",
"Name": "1"
},
{
"$id": "3",
"Name": "2"
}
],
"Steps": [
{
"$id": "4",
"Contexts": [
{
"$ref": "2"
},
{
"$ref": "3"
}
]
}
]
}
This seems like a bug in JSON .NET - is there a way to work around it?

Related

How do I create a List or Array of different data types from C# to be saved to JSON in Unity

I would like my output JSON to contain a simple array shown below
{
"attributes":[
{
"trait_type": "Background",
"value": "Green"
},
{
"trait_type": "Body",
"value": "Body_1"
},
{
"trait_type": "Outfit",
"value": "Beach_Singlet"
},
{
"display_type":"date",
"trait_type":"birthday",
"value":869270400
}
]
}
Notice how the last item is different from the previous items in the array. The variable named "value" is also an integer as compared to the previous entries as strings.
How do I go about in order to be able to output my JSON as shown above? I have tried creating a class that can store all the information, but I cannot reuse the name "value" for both an int and string declaration, and also do not wish to show the variables if their value is null
(Example shown below)
{
"attributes": [
{
"display_type": "",
"trait_type": "Background",
"value": "Green"
},
{
"display_type": "",
"trait_type": "Body",
"value": "Body_1"
},
{
"display_type": "",
"trait_type": "Outfit",
"value": "Beach_Singlet"
},
{
"display_type": "date",
"trait_type": "birthday",
"value": 869270400
}
]
}
You can use object type.
using Newtonsoft.Json;
var list = new AttributeList
{
attributes = new []{
new Attribute
{
trait_type = "Background",
value = "green"
},
new Attribute
{
display_type = "date",
trait_type = "birthday",
value = 869270400
}
}
};
var json = JsonConvert.SerializeObject(list, Formatting.Indented);
Console.WriteLine(json);
public class Attribute
{
public object value { get; set; }
public string trait_type { get; set; }
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
public string display_type { get; set; }
}
public class AttributeList
{
public Attribute[] attributes { get; set; }
}
Output:
{
"attributes": [
{
"value": "green",
"trait_type": "Background"
},
{
"value": 869270400,
"trait_type": "birthday",
"display_type": "date"
}
]
}
try this
var attributes=new List<Attribute>{
new AttributeString{
trait_type="Background",
value="green"
},
new AttributeInt{
display_type ="date",
trait_type="birthday",
value=869270400
}
};
var jsonSerializerSettings = new JsonSerializerSettings()
{
TypeNameHandling = TypeNameHandling.Objects,
NullValueHandling=NullValueHandling.Ignore,
Formatting=Newtonsoft.Json.Formatting.Indented
};
var json = JsonConvert.SerializeObject(attributes,jsonSerializerSettings);
classes
public class Attribute
{
public string trait_type { get; set; }
public string display_type { get; set; }
}
public class AttributeString:Attribute
{
public string value { get; set; }
}
public class AttributeInt:Attribute
{
public int value { get; set; }
}
public class AttributeList
{
public List<Attribute> attributes { get; set; }
}

Json.NET Not Respecting PreserveReferencesHandling on Deserialization

I have a list of Team that I am trying to deserialise.
class Team
{
public string TeamName {get; set;};
private List<FootballPlayer> _fPlayers = new List<FootballPlayer>();
public List<FootballPlayer> FPlayers
{
get => _fPlaters;
}
}
class FootballPlayer
{
private Team _team;
public string Name { get; set; }
public Team Team
{
get => _team;
}
[JsonConstructor]
public FootballPlayer(Team team)
{
_team = team;
}
}
I have the following JSON settings:
JsonSerializerSettings serializerSettings = new JsonSerializerSettings()
{
PreserveReferencesHandling = PreserveReferencesHandling.Objects,
Formatting = Formatting.Indented
};
When I look at the serialised output, it appears correct, and the references between nodes are properly represented.
{
"$id": "1",
"TeamName": "Test",
"FPlayers": [
{
"$id": "2",
"Team": {
"$ref": "1"
},
"Name": "Leo Messi"
}
]
}
When the data is deserialised, the property "Team" in the player "Leo Messi" is null.
How can I deserialise this JSON in such a way that the property "Team" of "Leo Messi" is not null?
JsonConvert.DeserializeObject<List<Team>>(JsonString, serializerSettings);

How to configure the Json serializer, to allow Circular References in Azure Functions (V2)?

Suppose, I have a object that has a sub property that references itself.
public class Person
{
public Person Parent { get; set; }
public string Name { get; set; }
public ObservableCollection<Person> Children { get; set; } = new ObservableCollection<Person>();
}
When I try to return it,
var pp = new Person();
pp.Name = "TONY";
pp.Children.Add(new Person()
{
Parent = pp,
Name = "ESTHER"
});
return new JsonResult(pp);
it comes truncated, some Exception happens while serializing it.
{"parent":null,"name":"TONY","children":[{
SyntaxError: JSON.parse: end of data while reading object contents at line 1 column 43 of the JSON data
On ASP Net we could do this:
config.Formatters.JsonFormatter.SerializerSettings.ReferenceLoopHandling
= Newtonsoft.Json.ReferenceLoopHandling.Serialize;
config.Formatters.JsonFormatter.SerializerSettings.PreserveReferencesHandling
= Newtonsoft.Json.PreserveReferencesHandling.Objects;
How can I configure Azure Function Json Serializer, to allow it?
Looking at the overloaded methods, I found:
then I used it with this code:
var serializerSettings = new Newtonsoft.Json.JsonSerializerSettings()
{
ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Serialize,
PreserveReferencesHandling = Newtonsoft.Json.PreserveReferencesHandling.All
};
return new JsonResult(p, serializerSettings);
And it worked.
{
"$id": "1",
"Parent": null,
"Name": "TONY",
"Children": {
"$id": "2",
"$values": [
{
"$id": "3",
"Parent": {
"$ref": "1"
},
"Name": "ESTHER",
"Children": {
"$id": "4",
"$values": []
}
}
]
}
}
You can also get to config using:
var config = req.GetConfiguration();
config.Formatters.JsonFormatter.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Serialize;
config.Formatters.JsonFormatter.SerializerSettings.PreserveReferencesHandling = Newtonsoft.Json.PreserveReferencesHandling.Objects;
The only downside is that you need to create on each function but you could add a custom attribute to make that easier.

Serialize as array with JSON.NET

How can I make Json.NET serializer to serialize instance into array of objects?
Basically I need something like this:
[
{
"name":"Page1.html",
"size":1,
"outlinks":[
"Page2.html",
"Page3.html",
"Page4.html"
]
},
{
"name":"Page2.html",
"size":2,
"outlinks":[
"Page3.html"
]
},
{
"name":"Page3.html",
"size":3,
"outlinks":[
"Page1.html",
"Page2.html",
"Page3.html",
"Page4.html"
]
},
{
"name":"Page4.html",
"size":4,
"outlinks":[]
}
]
with:
Dictionary<string, string[]> UrlsCollection = new Dictionary<string, string[]>();
List<string> OutLinks = new List<string>();
OutLinks.Add("Page2.html");
OutLinks.Add("Page3.html");
OutLinks.Add("Page4.html");
UrlsCollection.Add("Page1.html", OutLinks.ToArray());
OutLinks.Clear();
OutLinks.Add("Page3.html");
UrlsCollection.Add("Page2.html", OutLinks.ToArray());
OutLinks.Clear();
OutLinks.Add("Page1.html");
OutLinks.Add("Page2.html");
OutLinks.Add("Page3.html");
OutLinks.Add("Page4.html");
UrlsCollection.Add("Page3.html", OutLinks.ToArray());
OutLinks.Clear();
UrlsCollection.Add("Page4.html", OutLinks.ToArray());
OutLinks.Clear();
string jsonUrlsCollection = JsonConvert.SerializeObject(UrlsCollection.ToList(), Formatting.Indented);
I get:
[
{
"Key": "Page1.html",
"Value": [
"Page2.html",
"Page3.html",
"Page4.html"
]
},
{
"Key": "Page2.html",
"Value": [
"Page3.html"
]
},
{
"Key": "Page3.html",
"Value": [
"Page1.html",
"Page2.html",
"Page3.html",
"Page4.html"
]
},
{
"Key": "Page4.html",
"Value": []
}
]
There must be a way/something to get a simple JSON Object?
Modifying the solution to reflect Deblaton Jean-Philippe's suggestion in the comments.
public class UrlDef
{
public UrlDef() { outlinks = new List<string>(); }
public string name { get; set; }
public int size { get; set; }
public List<string> outlinks { get; set; }
}
List<UrlDef> UrlsCollection = new List<UrlDef>();
UrlDef urldef;
urldef = new UrlDef();
urldef.name = "Page1.html";
urldef.size = 1;
urldef.outlinks.Add("Page2.html");
urldef.outlinks.Add("Page3.html");
urldef.outlinks.Add("Page4.html");
UrlsCollection.Add(urldef);
urldef = new UrlDef();
urldef.name = "Page2.html";
urldef.size = 2;
urldef.outlinks.Add("Page3.html");
UrlsCollection.Add(urldef);
urldef = new UrlDef();
urldef.name = "Page3.html";
urldef.size = 3;
urldef.outlinks.Add("Page1.html");
urldef.outlinks.Add("Page2.html");
urldef.outlinks.Add("Page3.html");
urldef.outlinks.Add("Page4.html");
UrlsCollection.Add(urldef);
urldef = new UrlDef();
urldef.name = "Page4.html";
urldef.size = 4;
UrlsCollection.Add(urldef);
string jsonUrlsCollection = JsonConvert.SerializeObject(UrlsCollection, Formatting.Indented);
You need to serialize a list of this object
public class Url
{
public string name { get; set; }
public int size { get; set; }
public List<string> outlinks { get; set; }
}
For this answer, I used a website I often use when I know what I expect from JS, but I'm not sure of what I need to feed into the CS : http://json2csharp.com/

Json Deserialization, Create duplicate objects

It's easier to show a mock up of the problem rather than trying to explain it first.
internal class Program
{
private static void Main(string[] args)
{
Class1 class1 = new Class1() { Name = "Scott" };
Class2 class2 = new Class2() { Name = "Steve", Objects = new List<Class1>() { class1 } };
Class2 class22 = new Class2() { Name = "Atanas", Objects = new List<Class1>() { class1 } };
List<Class2> list = new List<Class2>() { class2, class22 };
string jSonString = JsonConvert.SerializeObject(list,Formatting.Indented,
new JsonSerializerSettings()
{
ReferenceLoopHandling = ReferenceLoopHandling.Ignore
});
List<Class2> result = (List<Class2>) JsonConvert.DeserializeObject(jSonString, typeof(List<Class2>));
if (result[0].Objects[0] == result[1].Objects[0])
{
Console.WriteLine("Correct, its the same object");
}
else
{
Console.WriteLine("Bah!, its a new object");
}
}
}
public class Class1
{
public string Name { get; set; }
}
public class Class2
{
public Class2()
{
Objects = new List<Class1>();
}
public List<Class1> Objects { get; set; }
public string Name { get; set; }
}
The problem is that when the string is deserialized, the "Shared Object" is now duplicated. Before being serialized, the same object (by reference) was in two separate lists. After de serializing both the lists contain separate objects.
Is it possible to have json behave so it doesn't duplicate?
Hope that makes sense
Steve
Yes, if you setup your serializer as follow:
JsonSerializerSettings settings = new JsonSerializerSettings
{
PreserveReferencesHandling = PreserveReferencesHandling.All
};
Json string will be:
{
"$id": "1",
"$values": [
{
"$id": "2",
"Objects": {
"$id": "3",
"$values": [
{
"$id": "4",
"Name": "Scott"
}
]
},
"Name": "Steve"
},
{
"$id": "5",
"Objects": {
"$id": "6",
"$values": [
{
"$ref": "4"
}
]
},
"Name": "Atanas"
}
]
}
And you will see in console:
Correct, its the same object
See http://james.newtonking.com/projects/json/help/index.html?topic=html/T_Newtonsoft_Json_PreserveReferencesHandling.htm

Categories

Resources