Json.Net Is it faster to deserialize to JObject or Dictionary? - c#

I'm trying to model a Json for deserialization where one of the properties is an object with a long list of keys and values.
{
"key1": "value1",
"key2": "value2",
//this guy
"longlist": {
"6060": 123,
"6061": 664,
...
"6200": 43
}
}
In my application, I don't need to look inside longlist, I only want to be able to append one longlist to another.
Is it better for me to model longlist as a Dictionary<string, int> or as a JObject, considering the performance of deserialization for each?
edit: order of keys in longlist doesn't matter.

public class RootObject
{
public string key1 { get; set; }
public string key2 { get; set; }
public Dictionary<string, int> longlist { get; set; }
}
JObject jsonResponse = JObject.Parse(r);
JObject objResponse = (JObject)jsonResponse["longlist"];
RootObject _Data = Newtonsoft.Json.JsonConvert.DeserializeObject<RootObject>(jsonResponse.ToString());
foreach (KeyValuePair<string, int> kvp in _Data.longlist)
{
Console.WriteLine(string.Format("Key: {0} Value: {1}", kvp.Key, kvp.Value));
}
fiddle: https://dotnetfiddle.net/9ZyKwN

Related

Convert json string from one type to another with .net core c#

I am struggling to convert below input json to output json as this is what is the required format to call
hubspot api to submit a form. I am writing this using .net core within Azure function.
Input Json
{
"Email":"myemail#test.com",
"Phone":"12345678",
"Address":"address 1"
}
Output json
{
"fields": [
{
"name": "Email",
"value": "myemail#test.com"
},
{
"name": "Phone",
"value": "12345678"
},
{
"name": "Address",
"value": "address 1"
}
]
}
I converted the input json to dictionary using
IDictionary<string, string> dictionary = JsonConvert.DeserializeObject<IDictionary<string, string>>(inputJson);
but that gives me key value pair instead of name value pair.
I would like the output as detailed above.
Any help/example code would be highly appreciated.
You could create your own "NameValuePair" class/struct if you don't want "Key" as the field name:
public class FieldContainer
{
[JsonProperty("fields")]
public IEnumerable<NameValuePair> Fields { get; set; }
}
public struct NameValuePair
{
[JsonProperty("name")]
public string Name { get; set; }
[JsonProperty("value")]
public string Value { get; set; }
public NameValuePair(string name, string value)
{
Name = name;
Value = value;
}
}
And then do like you've already done, but converting the KeyValuePairs into your own struct:
var inJson = #"{
""Email"":""myemail#test.com"",
""Phone"":""12345678"",
""Address"":""address 1""
}";
var dict = JsonConvert.DeserializeObject<Dictionary<string, string>>(inJson);
var container = new FieldContainer
{
Fields = dict.Select(pair => new NameValuePair(pair.Key, pair.Value))
};
var outJson = JsonConvert.SerializeObject(container);
See this fiddle for a demonstration.
Easiest way to do this would be to take the json and convert it to Dictionary<string, string>. Loop over each KeyValuePair and create a list of Fields using LINQ. Once you have the List of fields, create your RootObject.
public class RootObject
{
[JsonProperty("fields")]
public List<Field> Fields { get; set; }
}
public class Field
{
[JsonProperty("name")]
public string Name { get; set; }
[JsonProperty("value")]
public string Value { get; set; }
}
// Create a dictionary
var dict = JsonConvert.DeserializeObject<Dictionary<string, string>>(jsonStr);
// Create a list of Fields
List<Field> fields = dict.Select(x => new Field() { Name = x.Key, Value = x.Value }).ToList();
// Create the final Object.
RootObject rootObj = JsonConvert.SerializeObject(new RootObject() { Fields = fields });
Alternative solution, using JObject.Parse() to parse the original JSON, then iterate its Properties to create an array of JObjects with different names and values.
The resulting IEnumerable<JObject> is then converted to a JArray, used to create the final fields object.
var jObj = JObject.Parse(json);
var newObjects = jObj.Properties().Select(p => new JObject {
new JProperty("name", p.Name),
new JProperty("value", p.Value)});
var fields = new JObject() {
{ "fields", JArray.FromObject(newObjects)}
};
Console.WriteLine(fields);

Create a Dictionary from another Dictionary and a List<T> on a matching values

I have the following function, which takes a Dictionary and a List, matches rows in each of those and returns another Dictionary based on matcing items.
Is there a better way (code and performance -wise) to achieve the same result?
public sealed class ProdIds
{
public List<ProdID> Items { get; set; }
}
public sealed class ProdID
{
public string SpecialId { get; set; }
public int ItemId { get; set; }
}
Simplified view of the entries:
names: {100, "Name1"}, {333, "Name3"}, {212, "Name55"}, {99, "NameABC"}, ...
ids: {"SP44", 212}, {"SP33", 333}, {"SP11", 100}, {"SP9", 99}, ...
private static Dictionary<string, string> CreateMatchedDictionary (IReadOnlyDictionary<int, string> names, List<ProdIds> ids)
{
var dic = new Dictionary<string, string>();
foreach (var name in names)
{
foreach (var id in ids)
{
if (name.Key == id.Items[0].ItemId)
{
dic.Add(id.Items[0].SpecialId, name.Value);
}
}
}
return dic;
}
What I want to be returned here, is a new Dictionary which would look similar to this:
dic: {"SP44", "Name55"}, {"SP33", "Name3"}, {"SP11", "Name1"}, {"SP9", "NameABC"}, ...
The main performance problem is that you're looping through the names dictionary instead of taking advantage of the built-in O(1) lookup:
private static Dictionary<string, string> CreateMatchedDictionary (IReadOnlyDictionary<int, string> names, List<ProdIds> ids)
{
var dic = new Dictionary<string, string>();
foreach (var id in ids)
{
string name = null;
if (names.TryGetValue(id.Items[0].ItemId, out name)
{
dic.Add(id.Items[0].SpecialId, name);
}
}
return dic;
}
You could use Linq to make the code more concise, but it's not going to improve performance and might make debugging harder.

How to iterate through nested Dictionary<string, object>?

I have a JSON file that I need to deserialize using the class System.Web.Script.Serialization. The following code:
string json = File.ReadAllText(#"C:\file.json");
JavaScriptSerializer ser = new JavaScriptSerializer();
var dict = ser.Deserialize<Dictionary<string, object>>(json);
creates a nested dictionary, something like this:
Dictionary<string, Object> outerDictionary;
Dictionary<string, Object> middleDictionary;
Dictionary<string, string> innerDictionary;
I now need to grab some of the values from the innerDictionary into a C# object class, like:
public class Location
{
public string Id { get; set; }
public string Name { get; set; }
public string Street { get; set; }
public string City { get; set; }
public string State { get; set; }
public string Zip { get; set; }
}
So my question is, how can I iterate over the nested disctionary to get the values I need at the innermost level?
UPDATE
With the help of Jonesopolis I now have the correct loop structure, but I am still unable to get the values from the innermost dictionary?
foreach (var outer in dict)
{
foreach (var middle in (Dictionary<string, object>)outer.Value)
{
foreach (var inner in (ArrayList)middle.Value)
{
foreach (var loc in (Dictionary<string, object>)inner)
{
}
}
}
}
If you don't like the nested foreach in Jonesopolis's answer, then you can use LINQ this way:
var data = from outer in dict
from middle in (Dictionary<string, object>) outer.Value
from inner in (Dictionary<string, string>) middle.Value
select new { outer, middle, inner };
foreach (var item in data) {
// do things with item.inner
}
if you really want to work with those objects:
foreach(var outer in dict)
{
foreach (var middle in (Dictionary<string, object>) outer.Value)
{
foreach (var inner in (Dictionary<string, string>) middle.Value)
{
var location = new Location();
location.Id = inner["Id"];
//etc..
}
}
}
though, it would be much better to create a class structure that you can deserialize your json to, that accurately represents your data, instead of casting Dictionaries.

C# - How to parse json

I have a json string as following
string json = "{\"Method\":\"LOGIN\",\"Skill\":{\"1\":\"SKILL-1\",\"2\":\"SKILL-2\"}}";
I am using JavaScriptSerializer to parse json
System.Web.Script.Serialization.JavaScriptSerializer oSerializer =
new System.Web.Script.Serialization.JavaScriptSerializer();
var dict = oSerializer.Deserialize<Dictionary<string,object>>(json);
I am getting Method = LOGIN using following line
MessageBox.Show("Method = "+dict["Method"].ToString());
But how to get Skill in a loop. like
Skill
1 = SKILL-1
2 = SKILL-2
The value mapping to your Skill key is actually another Dictionary<string, object>. You can iterate it by casting the object:
string json = "{\"Method\":\"LOGIN\",\"Skill\":{\"1\":\"SKILL-1\",\"2\":\"SKILL-2\"}}";
var oSerializer = new JavaScriptSerializer();
var dict = oSerializer.Deserialize<Dictionary<string,object>>(json);
var innerDict = dict["Skill"] as Dictionary<string, object>;
if (innerDict != null)
{
foreach (var kvp in innerDict)
{
Console.WriteLine ("{0} = {1}", kvp.Key, kvp.Value);
}
}
Or, the alternative would be to map your object into a proper class and deserialize to it instead of a generic Dictionary<string, object>.
Suppose you have following class
public class Data
{
public string Method { get; set; }
public Skills Skill { get; set; }
// If you don't want to use Skills class then you can use this
//public Dictionary<int, string> Skills { get; set; }
}
public class Skills
{
public int Id { get; set; }
public string Skill { get; set; }
}
So you can Deserialize json into Data Object like this
Data deserializedData = JsonConvert.DeserializeObject<Data>(json);
You should declare your own class:
public class YourClassName
{
public string Method { get; set; }
public Dictionary<int, string> Skill { get; set; }
}
and deserialize the Json string like this:
var obj = oSerializer.Deserialize<YourClassName>(json);

Newtonsoft Json Serializer/Deserializer - how to use generic objects instead of JObject?

I have JSON specified by a restful service I am consuming that looks like this as an example:
{
"id": "97",
"name": "Tom Production",
"description": null,
"parameters": [
{
"first_parameter_name": "First Parameter Value"
},
{
"second_parameter_name": "Second Parameter Value"
}
]
}
Note that the property names id, name, description, and parameters are all established as part of the specification. The collection of generic parameters, shown in my example as "first_parameter_name" and "second_parameter_name" are not specified.... could be anything and I want to map them to generically typed objects.
I have declared an object for this as:
[DataContract (Name = "MyClass")]
public class MyClass
{
[DataMember (Name = "id")]
public string Id { get; set; }
[DataMember(Name = "name")]
public string Name { get; set; }
[DataMember(Name = "description")]
public string Description { get; set; }
[DataMember(Name = "parameters")]
public List<object> Parameters { get; set; }
}
Serialization works fine, exactly as I expect:
var myObject = new MyClass();
myObject.Id = "97";
myObject.Name = "Tom Production";
myObject.Parameters = new List<object>();
myObject.Parameters.Add(new { first_parameter_name = "First Parameter Value" });
myObject.Parameters.Add(new { second_parameter_name = "Second Parameter Value" });
string json = JsonConvert.SerializeObject(myObject);
Console.WriteLine(json);
yields the JSON I am looking for, exactly as at the top of this posting.
HOWEVER.
Deserialization does NOT work fine. If it worked the way I hope it to, which would be to create generic types just like I had created, and the following code should work.... but instead it throws a reflection exception:
var myNewObject = JsonConvert.DeserializeObject<MyClass>(json);
foreach (object o in myNewObject.Parameters)
{
Type t = o.GetType();
Console.WriteLine("\tType is {0}", t);
foreach (PropertyInfo pi in t.GetProperties(BindingFlags.Instance | BindingFlags.Public))
{
Console.WriteLine("\t\tName is {0}", pi.Name);
Console.WriteLine("\t\tValue is {0}", pi.GetValue(o, null));
}
}
Instead, I have to write code that is Newtonsoft-specific (ick) to use a kind of fake Newtonsoft reflection:
var myNewObject = JsonConvert.DeserializeObject<MyClass>(json);
foreach (object o in myNewObject.Parameters)
{
var jo = o as JObject;
if (jo != null)
{
foreach (JProperty prop in jo.Properties())
{
Console.WriteLine("\t\tName is {0}", prop.Name);
Console.WriteLine("\t\tValue is {0}", prop.Value);
}
}
}
Is there a way that I can control the Deserializer so that it will generate the proper generic types rather than the JObject type with the JProperties?
Many thanks in advance.
JObjects map most directly to Dictionary<string, object>s, since they're each simply a collection of keys to values. If you know that the value is always a string, you can make it a Dictionary<string, string>.
[DataMember(Name = "parameters")]
public List<Dictionary<string, object>> Parameters { get; set; }
// or
[DataMember(Name = "parameters")]
public List<Dictionary<string, string>> Parameters { get; set; }
// e.g.
var myNewObject = JsonConvert.DeserializeObject<MyClass>(json);
foreach (var dict in myNewObject.Parameters)
{
foreach (var pair in dict)
{
Console.WriteLine("\t\tKey is {0}", pair.Key);
Console.WriteLine("\t\tValue is {0}", pair.Value);
}
}

Categories

Resources