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.
Related
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.
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
Is there an automagic (automapper?) way to map an entity to a runtime created dynamic object with properties passed as parameters? I want to do an API where the clients can select the properties of the entities they want to fetch.
I mean:
class Patient
{
public int PatientId{ get; set; }
public string Name{ get; set; }
public string LastName{ get; set; }
public string Address{ get; set; }
...
}
getPatient(string[] properties)
{
//Return an object that has the properties passed as parameters
}
Imagine you only want to fetch a PatientDTO with PatientId and Name:
getPatient(new string[]{"PatientId", "Name"}
should return
{
"PatientId": "1234",
"Name": "Martin",
}
and so on.
For now I'm doing it with Dictionary, but probably there is a better way. This is my approach:
For a single object:
public static Dictionary<string, object> getDTO(string[] properties, T entity)
{
var dto = new Dictionary<string, object>();
foreach (string s in properties)
{
dto.Add(s, typeof(T).GetProperty(s).GetValue(entity));
}
return dto;
}
For a list of objects:
public static List<Dictionary<string, object>> getDTOList(string[] properties, List<T> TList)
{
var dtoList = new List<Dictionary<string, object>>();
foreach(T entity in TList)
{
dtoList.Add(getDTO(properties, entity));
}
return dtoList;
}
Thank you.
How about creating a new dynamic object based solely on the specified property fields and returning the dynamic?
You will need to add using statements for: System.Dynamic and System.ComponentModel for the following to work.
public static dynamic getDTO(object entity, string[] properties)
{
IDictionary<string, object> expando = new ExpandoObject();
foreach (var p in properties)
{
foreach (PropertyDescriptor property in TypeDescriptor.GetProperties(entity.GetType()))
{
if (property.Name == p)
{
expando.Add(p, property.GetValue(entity));
break;
}
}
}
return expando as ExpandoObject;
}
Calling this method would look something like this:
var patient = new Patient() { PatientId = 1, Name = "Joe", LastName = "Smith", Address = "123 Some Street\nIn Some Town, FL 32333" };
var propList = new string[] { "PatientId", "Name", "Address" };
dynamic result = getDTO(patient, propList);
Console.WriteLine("Id:{0} Name: {1}\nAddress: {2}", result.PatientId, result.Name, result.Address);
Console.ReadLine();
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);
I'm attempting to read a big list of data into a flat CSV. One field of each row is XML data - with the XML dictating additional Properties in each row. Therefore each row could have slightly different Properties.
I've got my list in an initial structured class:
private class Response {
public Response() {
Values = new Dictionary<string, string>();
}
public string Owner { get; set; }
public string Author { get; set; }
public string Email { get; set; }
public string Data { get; set; } // XML data in here
public Dictionary<string, string> Values { get; set; }
public DateTime Created { get; set; }
}
I then thought to make my list dynamic to handle the varied Properties:
var responses = new List<dynamic>();
foreach (var response in query) {
if (!string.IsNullOrEmpty(response.Data))
{
var doc = new XmlDocument();
doc.LoadXml(response.Data);
foreach (XmlNode node in doc.GetElementsByTagName("field")) {
try
{
response.Values.Add(node.FirstChild.InnerText, node.LastChild.InnerText);
}
catch (Exception ex) {
// log
}
}
}
dynamic fullResponse = new ExpandoObject();
fullResponse.Owner = response.Owner;
fullResponse.Author = response.Author;
fullResponse.Email = response.Email;
fullResponse.Created = response.Created;
IDictionary<string, object> map = fullResponse;
foreach (var value in response.Values) {
if (map.ContainsKey(value.Key)) {
map[value.Key] = value.Value;
}
else {
map.Add(value.Key, value.Value);
}
}
responses.Add(fullResponse);
}
... which also works fine. But now I want to basically flatten this list and export it as a CSV, knowing that each row of my dynamic list might have slightly different properties.
Grabbing the PropertyInfo, a dynamic type, obviously comes back with nothing. Am I just going to have to loop through my list to extract the unique properties manually into something like a DataTable? Or are there some calls I can make with Reflection to get this done more efficiently?
I ended up using a plain old DataTable to get it sorted:
using (var dt = new DataTable())
{
var keys = responses.SelectMany(x => ((IDictionary<string, object>)x).Keys).Distinct();
var columns = keys.Select(x => new DataColumn(x)).ToArray();
dt.Columns.AddRange(columns);
foreach(IDictionary<string, object> response in responses)
{
var row = dt.NewRow();
foreach (var kvp in response)
{
row[kvp.Key] = kvp.Value;
}
dt.Rows.Add(row);
}
// write to CSV
}
Though I feel like I could've done something a lot cooler with Reflection to achieve the same result.