How to get object json when deserializing array - c#

I have an incoming JSON, which consists array of some objects, say, Foo. I deserialize them with
result = JsonConvert.DeserializeObject<List<Foo>>(message);
Now i want to add a string property to Foo, which will store it's JSON (which i received), so that Foo'll look like:
public class Foo
{
public int MyInt { get; set; }
public bool MyBool { get; set; }
public string JSON { get; set; }
}
But i don't know how can i say JSON.Net the way it can populate such a field..
UPD
I'll clearify what i want. Say i receive JSON:
[{"MyInt":1,"MyBool":0},{"MyInt":2,"MyBool":0},{"MyInt":3,"MyBool":1}]
Here is array of 3 objects and i want, when deserializing, to add corresponding part of json to object, so that:
First object will contain {"MyInt":1,"MyBool":0}
Second object will contain {"MyInt":2,"MyBool":0}
Third object will contain {"MyInt":3,"MyBool":1}
in their JSON Property
I'll be gratefull for any help!

This is one way to do it, but it doesn't maintain the exact original JSON - but it does provide a static record of the original JSON (but without the exact format of the original values - i.e. Bool maybe be 0/1 or true/false):
var message = #"[{""MyInt"":1,""MyBool"":0},{""MyInt"":2,""MyBool"":0},{""MyInt"":3,""MyBool"":1}]";
var foos = JsonConvert.DeserializeObject<List<Foo>>(message);
var t = JsonConvert.SerializeObject(foos[0]);
foos = foos.Select(s => new Foo() { MyBool = s.MyBool, MyInt = s.MyInt, JSON = JsonConvert.SerializeObject(s) }).ToList();
If you are dealing with a lot of Foos, then you might want to find a more efficient way. There might be a way to 'update' using linq, rather than creating a new list.

Okay, i found an answer. I didn't know that i can deserialize message into JArray and then enumerate it (good job, newtonsoft:) ). Here is what i endede up with:
if (tokenType is JArray)
{
var arr = JsonConvert.DeserializeObject(message) as JArray;
foreach (var item in arr)
{
try
{
var agentParameter = item.ToObject<Foo>();
agentParameter.JSON = item.ToString();
result.Add(agentParameter);
}
catch (Exception)
{
LogProvider.Error(string.Format("Failed to Deserialize message. Message text: \r\n {0}", item.ToString()));
}
}
}

Related

How to get values from dynamic array?

I have deserialized the string by using the dynamic object.
Because property names dynamically changed. so can't able to deserialize with DTO objects.
Please find the code snippet:
var result = "[{\"series1\":\"{\\\"Category1\\\":4.3,\\\"Category2\\\":2.5,\\\"Category3\\\":3.5}\"},{\"series2\":\"{\\\"Category1\\\":2.4,\\\"Category2\\\":4.4,\\\"Category3\\\":1.8}\"},{\"series3\":\"{\\\"Category1\\\":2,\\\"Category2\\\":2,\\\"Category3\\\":3}\"}]");
var jsonResult = JsonConvert.DeserializeObject<dynamic[]>(jsonText);
How to retrieve the series1 and category1, 2, 3 results?
Could you please help me to solve this?
The problem you will have is you have json stuffed within json - obvious from the fact that you have double escape sequences there. So to get series1 is fairly straightforward:
var jsonResult = JsonConvert.DeserializeObject<dynamic[]>(result);
Console.WriteLine(jsonResult[0]["series1"]);
But that itself is another json string. So you'll need to then parse that again to get Category1 etc:
var jsonResult = JsonConvert.DeserializeObject<dynamic[]>(result);
var series1Result = JsonConvert.DeserializeObject<dynamic>(jsonResult[0]["series1"].ToString());
Console.WriteLine(series1Result["Category1"]); // 4.3
Live example: https://dotnetfiddle.net/hcACrM
As #Jamiec mentioned, there is inline JSON string to consider; so, you will have to deserialize twice.
For this answer, we'll avoid using dynamic altogether (without creating a custom JsonConverter) and avoid JObject (i.e. IDictionary<string, JToken>);
We'll define a Type for Categories. (For the second, iterative Deserialization)
public class Categories
{
public double Category1 { get; set; }
public double Category2 { get; set; }
public double Category3 { get; set; }
}
We'll replace dynamic[] with IEnumerable<IDictionary<string, string>>. Each dictionary has only one entry actually, so we'll simply join the Keys and Values using string.Join() in our iteration handling.
var jsonText = "[{\"series1\":\"{\\\"Category1\\\":4.3,\\\"Category2\\\":2.5,\\\"Category3\\\":3.5}\"},{\"series2\":\"{\\\"Category1\\\":2.4,\\\"Category2\\\":4.4,\\\"Category3\\\":1.8}\"},{\"series3\":\"{\\\"Category1\\\":2,\\\"Category2\\\":2,\\\"Category3\\\":3}\"}]";
var jsonResult = JsonConvert.DeserializeObject<IEnumerable<IDictionary<string, string>>>(jsonText);
var r = jsonResult.Select(i =>
{
(string Series, Categories Categories) result = (string.Join(string.Empty, i.Keys), JsonConvert.DeserializeObject<Categories>(string.Join(string.Empty, i.Values)));
return result;
}).ToArray();
(the last part uses a Deconstruct to ValueTuple)
dynamic here was actually a JObject which implements IDictionary<string, JToken>. JToken is fairly flexible (infact it works with the snippet above - including string.Join usage), but as a matter of scope and preference we deserialized to a primitive string.
Try jsonResult["series1"]["Category"]

How to map json and skip parent property?

I have this json string, which contains two elements each with a Number and a Status:
var jsonString = "{\"Errors\":[{\"Number\":9,\"Status\":\"BadRequest\"}, {\"Number\":3,\"Status\":\"BadConnection\"}]}";
As you see it has a parent property called Errors.
I have prepared this model:
public class ExceptionStructure
{
public int Number { get; set; }
public string Status { get; set; }
}
Using NewtonSoft.Json I would like to deserialize the json string into an array of ExceptionStructure objects, without also having to create a model for the parent property (as I don't really need it).
Can I do this (perhaps with some json attribute on the model class)?
I was hoping to do something like this to deserialize:
var exceptionArr = JsonConvert.DeserializeObject<ExceptionStructure>(jsonString);
JSON.NET allows you to deserialize parts of a json file. You can do this by first deserialzing the json string to a JObject, extract the relevant parts, and then deserialize those to your actual object.
JObject errors = JObject.Parse(jsonString);
IList<JToken> results = errors["Errors"].Children().ToList();
IList<ExceptionStructure> exceptions = new List<ExceptionStructure>();
foreach (JToken result in results)
{
ExceptionStructure exception= result.ToObject<ExceptionStructure>();
exceptions.Add(exception);
}
Honestly though, in your case it might be easier to just build a Errors parent class
More information can be found at http://www.newtonsoft.com/json/help/html/SerializingJSONFragments.htm
this is may be helpful you.
string s = "{\"Errors\":[{\"Number\":9,\"Status\":\"BadRequest\"}, {\"Number\":3,\"Status\":\"BadConnection\"}]}";
var jobj = JObject.Parse(s);
List<ExceptionStructure> list = jobj["Errors"].ToObject<List<ExceptionStructure>>();
OR:
string s = "{\"Errors\":[{\"Number\":9,\"Status\":\"BadRequest\"}, {\"Number\":3,\"Status\":\"BadConnection\"}]}";
List<ExceptionStructure> list = JObject.Parse(s)
.SelectToken("Errors")
.ToObject<List<ExceptionStructure>>();

How to parse non-array JSON?

I am trying to read json from a local .json file and parse the contents using StreamReader and Json.NET. Json & my code:
contents of .json file: {"rate":50,"information":{"height":70,"ssn":43,"name":"andrew"}}
using (var sr = new StreamReader(pathToJsonFile))
{
dynamic jsonArray = JsonConvert.DeserializeObject(sr.ReadToEnd());
foreach(var item in jsonArray)
{
Console.WriteLine(item.rate);
Console.WriteLine(item.ssn);
}
}
This gives me an error on the line foreach(var item in array): Object reference not set to an instance of an object. I am guessing this is because my json is not actually an array but that is how I am trying to parse it. How can I parse this json in order to pull out fields such as rate or ssn?
NB - please do not flag this question as a duplicate of Read and parse a Json File in C#, as that is where I got my original code from.
EDIT: As has been pointed out in other answers, jsonArray is null. That explains my error but still does not answer my question. How else can I parse this json in order to extract the desired fields?
A couple things:
If you want to manually parse out the values, you should try using JObject rather than JsonConvert.DeserializeObject. The following code should work:
dynamic jsonObject = JObject.Parse("{'rate':50,'information':{'height':70,'ssn':43,'name':'andrew'}}");
Console.WriteLine(jsonObject["rate"]);
Console.WriteLine(jsonObject["information"]["ssn"]);
However, if you know how the json is structured, you should create a .net class like:
public class Person
{
public int rate {get;set;}
public Information information {get;set;}
}
public class Information
{
public int height {get;set;}
public int ssn {get;set;}
public string name {get;set;}
}
and then use:
var person = JsonConvert.DeserializeObject<Person>(thestringtodeserialize);
That way you can have a strongly typed object.
In any case, I would check for null (DeserializeObject can obviously return null):
using (var sr = new StreamReader(pathToJsonFile))
{
dynamic jsonArray = JsonConvert.DeserializeObject(sr.ReadToEnd());
if(jsonArray != null) //new check here
{
foreach(var item in jsonArray)
{
Console.WriteLine(item.rate);
Console.WriteLine(item.ssn);
}
}
I am guessing this is because my json is not actually an array
True, the returned object is dynamic, so make use of dynamic:
var json = "{\"rate\":50,\"information\":{\"height\":70,\"ssn\":43,\"name\":\"andrew\"}}";
dynamic obj = JsonConvert.DeserializeObject(json);
Console.WriteLine("rate: {0}. ssn: {1}", obj.rate, obj.information.ssn);
See live sample here: https://dotnetfiddle.net/nQYuyX
Are you sure it's an array?
If that's the format the you expect from Json, maybe you should consider defining a class.
For example:
class SomeJsonObject
{
public int rate {get;set;}
[JsonProperty("information")] //if you want to name your property something else
public InformationObject Information {get;set;}
}
class InformationObject
{
[JsonProperty("height", NullValueHandling = NullValueHandling.Ignore)] //some other things you can do with Json
public int Height {get;set;}
public int ssn {get;set;}
public string name {get;set;}
}
This way you can just deserialize it to an object:
SomeJsonObject jsonArray = JsonConvert.DeserializeObject<SomeJsonObject>(sr.ReadToEnd());
I think your question is similar to this Deserialize JSON with C# . you can use JavaScriptSerializer
I don't get a null reference (with Json.net 6.0.3) but your code has one obvious bug:
static void Main(string[] args)
{
string s = "{'rate':50,'information':{'height':70,'ssn':43,'name':'andrew'}}".Replace('\'', '\"');
var obj = JsonConvert.DeserializeObject(s);
dynamic jsonArray = obj;
foreach (var item in jsonArray)
{
Console.WriteLine(item.rate);
Console.WriteLine(item.ssn);
}
}
The bug is Console.WriteLine(item.rate) will throw.
Your 'array' jsonArray is not actually an array, it is a dictionary!
Therefore, item=the first Key-Value-pair in the dictionary, = {"rate":50}.
You can prevent the code from throwing by getting rid of your foreach loop.
i would fire up nuget and get the JSON.net package
https://www.nuget.org/packages/Newtonsoft.Json/
http://james.newtonking.com/json
it is well documented and can save you a tonne of work.
see also http://json2csharp.com/
EDIT: you are already using this

Determining object "type" during json deserialization

While trying to de-serialize a complex JSON object (JIRA issue) into an object containing a dictionary of type string-Field I've hit a bit of a bump.
While I can de-serialize various pre-determined object types (standard), I'm having a bit of a harder time with the custom fields, which could be of various types (they all begin with customfield_ followed by a set of numbers).
The custom fields can be floats, strings, booleans, objects and arrays of objects. The latter of these is causing me issues since I can't seem to determine what the object is before I de-serialize it.
I've searched for a way to perhaps "peek" at the data in the object before de-serializing as one of the fields contains information specific to it's type. This is all so I can determine the type of the object and tell Json.Net what to de-serialize it as.
I've considered parsing the JSON string before serialization to get the information, or maybe just when hitting this particular case, but maybe there is a better way?
Thanks in advance for any advice on this.
You can deserialize to an object with Json.Net. Here's a quick and dirty example:
using System;
using Newtonsoft.Json;
namespace Sandbox
{
class Program
{
private static void Main(string[] args)
{
var nestDto = new Dto
{
customfield_1 = 20,
customfield_2 = "Test2"
};
var dto = new Dto
{
customfield_1 = 10,
customfield_3 = new[] { nestDto },
customfield_2 = "Test"
};
var jsonString = JsonConvert.SerializeObject(dto);
Console.WriteLine(jsonString);
var fromJsonString = JsonConvert.DeserializeObject<Dto>(jsonString);
Console.WriteLine(fromJsonString.customfield_3[0].customfield_2); //Outputs Test2
Console.ReadKey();
}
}
class Dto
{
public int customfield_1 { get; set; }
public string customfield_2 { get; set; }
public Dto[] customfield_3 { get; set; }
}
}
Instead of peaking, you can deserialize as the same type as JSON.net uses for ExtensionData explicitly. For example:
if (reader.TokenType == JsonToken.StartArray)
{
var values = serializer.Deserialize<List<Dictionary<string, JToken>>>(reader);
objectContainer = ClassifyAndReturn(values);
}
private ObjectType ClassifyAndReturn(List<Dictionary<string, JToken>> values)
{
if (values.First().ContainsKey("self"))
{
string self = values.First()["self"].Value<string>();
if (self.Contains("customFieldOption"))
//... Then go into a series of if else cases to determine the object.
The representation of the objects are given as a Dictionary of string to JToken, which can then easily be checked and assigned manually or in some cases automatically deserialized (in the case one of the fields is another object).
Here is what an object constructor could look like:
internal myobject(Dictionary<string, JToken> source)
{
Self = source["self"].Value<string>();
Id = source["id"].Value<string>();
Value = source["value"].Value<string>();
}

Json.net deserializing list gives duplicate items

I have just started using Newtonsoft.Json (Json.net). In my first simple test, I ran into a problem when deserializing generic lists. In my code sample below I serialize an object, containing three types of simple integer lists (property, member var and array).
The resulting json looks fine (the lists are converted into json-arrays). However, when I deserialize the json back to a new object of the same type, all list items are duplicated, expect for the array. I've illustrated that by serializing it a second time.
From searching around, I've read that there may be a "private" backing field to the lists that the deserializer also fills.
So my question is: Is there a (preferably simple) way to avoid duplicate items in following case?
Code
using System;
using System.Collections.Generic;
using Newtonsoft.Json;
namespace JsonSerializeExample
{
public class Program
{
static void Main()
{
var data = new SomeData();
var json = JsonConvert.SerializeObject(data);
Console.WriteLine("First : {0}", json);
var data2 = JsonConvert.DeserializeObject<SomeData>(json);
var json2 = JsonConvert.SerializeObject(data2);
Console.WriteLine("Second: {0}", json2);
}
}
public class SomeData
{
public string SimpleField;
public int[] IntArray;
public IList<int> IntListProperty { get; set; }
public IList<int> IntListMember;
public SomeData()
{
SimpleField = "Some data";
IntArray = new[] { 7, 8, 9 };
IntListProperty = new List<int> { 1, 2, 3 };
IntListMember = new List<int> { 4, 5, 6 };
}
}
}
Resulting output
First : {"SimpleField":"Some data","IntArray":[7,8,9],"IntListMember":[4,5,6],"IntListProperty":[1,2,3]}
Second: {"SimpleField":"Some data","IntArray":[7,8,9],"IntListMember":[4,5,6,4,5,6],"IntListProperty":[1,2,3,1,2,3]}
There may be some overlap here with Json.Net duplicates private list items. However, I think my problem is even simpler, and I still haven't figured it out.
That is because you are adding items in the constructor. A common approach in deserializers when processing a list is basically:
read the list via the getter
if the list is null: create a new list and assign via the property setter, if one
deserialize each item in turn, and append (Add) to the list
this is because most list members don't have setters, i.e.
public List<Foo> Items {get {...}} // <=== no set
Contrast to arrays, which must have a setter to be useful; hence the approach is usually:
deserialize each item in turn, and append (Add) to a temporary list
convert the list to an array (ToArray), and assign via the setter
Some serializers give you options to control this behavior (others don't); and some serializers give you the ability to bypass the constructor completely (others don't).
I'm pretty sure that this post is not relevant anymore, but for future reference, here a working solution.
Just need to specify that ObjectCreationHandling is set to Replace, i.e. Always create new objects and not to Auto (which is the default) i.e. Reuse existing objects, create new objects when needed.
var data = new SomeData();
var json = JsonConvert.SerializeObject(data);
Console.WriteLine("First : {0}", json);
var data2 = JsonConvert.DeserializeObject<SomeData>(json, new JsonSerializerSettings() { ObjectCreationHandling = ObjectCreationHandling.Replace });
var json2 = JsonConvert.SerializeObject(data2);
Console.WriteLine("Second: {0}", json2);
I encountered a similar issue with a different root cause. I was serializing and deserializing a class that looked like this:
public class Appointment
{
public List<AppointmentRevision> Revisions { get; set; }
public AppointmentRevision CurrentRevision
{
get { return Revision.LastOrDefault(); }
}
public Appointment()
{
Revisions = new List<AppointmentRevision>();
}
}
public class AppointmentRevision
{
public List<Attendee> Attendees { get; set; }
}
When I serialized this, CurrentRevision was being serialized too. I'm not sure how, but when it was deserializing it was correctly keeping a single instance of the AppointmentRevision but creating duplicates in the Attendees list. The solution was to use the JsonIgnore attribute on the CurrentRevision property.
public class Appointment
{
public List<AppointmentRevision> Revisions { get; set; }
[JsonIgnore]
public AppointmentRevision CurrentRevision
{
get { return Revision.LastOrDefault(); }
}
public Appointment()
{
Revisions = new List<AppointmentRevision>();
}
}
How to apply ObjectCreationHandling.Replace to selected properties when deserializing JSON?
Turns out (I'm in 2019), you can set the list items in your constructor as you were doing in your question. I added the ObjectCreationHandling.Replace attribute above my declaration of the list, then serialising should replace anything stored in the list with the JSON.

Categories