dictionary to json with key names - c#

I have a dictionary Dictionary<int, string> of ints and strings, where ints are ids and strings are usernames, and when I convert it to JSON using Json.NET I get something like the following:
{"3":"jack","2":"john"}
I convert it like so:
Dictionary<int, string> dictFriends = new Dictionary<int, string>();
foreach (var id in resultList)
{
var user = db.Users.Find(id);
string friend = user.Username;
dictFriends.Add(id, friend);
}
string json = JsonConvert.SerializeObject(dictFriends);
But I am hoping to get something like so:
[
{ "id": "3", "user": "jack"},
{ "id": "2", "user": "john"},
]
Is it possible?

As far as I know you'd have to transform the dictionary into something JSON.NET would recognise as being an IEnumerable:
// YOUR DICTIONARY
var dictFriends = new Dictionary<int, string>() {
{1,"Jack"},
{2,"John"},
{3,"Jeff"}
};
// TRANSFORM INTO IENUMERABLE
var transformed = from key in dictFriends.Keys
select new { id = key, user = dictFriends[key] };
// SERIALIZE
var json = JsonConvert.SerializeObject(transformed);
Output:
[
{"id":1, "user":"Jack"},
{"id":2, "user":"John"},
{"id":3, "user":"Jeff"}
]

You're trying to use a Dictionary as an Array/List, writing to an existing key will overwrite it. Also your current key type is int therefore you would have JSON output such as
{1: "jack", 2: "john"}
Instead set your object type to List<Dictionary<string, Object>>
List<Dictionary<string, object>> friends = new List<Dictionary<string, Object>>();
foreach (var id in resultList)
{
var user = db.Users.Find(id);
string friend = user.Username;
Dictionary<string, object> dictFriend = new Dictionary<string, Object>();
dictFriend.Add("id", id);
dictFriend.Add("name" , friend);
friends.Add(dictFriend);
}
string json = JsonConvert.SerializeObject(friends);

You could use the DataContractJsonSerializer: https://msdn.microsoft.com/en-us/library/system.runtime.serialization.json.datacontractjsonserializer(v=vs.110).aspx
The below will produce output in the form you're after; only instead of id and user your fields would be named key and value. The reason being those are the property names on the dictionary.
If you needed to change those names also (i.e. it's not just the structure you're interested in), you'd need to override the dictionary with a custom class, where you could add attributes such as [JsonProperty(PropertyName = "User")] to the properties to change how they're parsed... See http://www.newtonsoft.com/json/help/html/SerializationAttributes.htm for more.
Dictionary<int, string> dictFriends = new Dictionary<int, string>();
dictFriends.Add(1, "Alice");
dictFriends.Add(2, "Bob");
string jsonString;
using (MemoryStream ms = new MemoryStream()) {
//NB: DataContractJsonSerializer is in assembly System.Runtime.Serialization.dll - and others; http://stackoverflow.com/a/2682197/361842
DataContractJsonSerializer dcjs = new DataContractJsonSerializer(dictFriends.GetType());
dcjs.WriteObject(ms, dictFriends);
ms.Position = 0;
using(StreamReader sr = new StreamReader(ms)) {
jsonString = sr.ReadToEnd();
}
}
Debug.WriteLine(jsonString);
Sample output:
[{"Key":1,"Value":"Alice"},{"Key":2,"Value":"Bob"}]

Related

Deserialized object other than original serialized object

I am using ASP Net Core 2.2
I seralize this dynamic object
var stuff1 = new
{
Name = "John",
Surname = "Smith",
Addresses = new[] {
new { City = "New York", State = "NY"},
new { City = "Milano", State = "IT" }
};
var stuff1Serialized = JsonConvert.SerializeObject(stuff1)
This is the serialized object:
{"Name":"John","Surname":"Smith"}
Now, I get this string and I deserialized it
dynamic stuff1Deserialized = JsonConvert.DeserializeObject(stuff1Serialized);
I expect that sutff1 and stuff1Deseralized has the same strucure, but they are different, why?
In Immediate window:
stuff1.name
"Jhon"
stuff1Deserialized.Name
{John}
First: '((Newtonsoft.Json.Linq.JToken)stuff1Deserialized.Name).First' threw an exception of type 'System.InvalidOperationException'
HasValues: false
Last: '((Newtonsoft.Json.Linq.JToken)stuff1Deserialized.Name).Last' threw an exception of type 'System.InvalidOperationException'
Next: null
Parent: {"Name": "John"}
Path: "Name"
Previous: null
Root: {{
"Name": "John",
"Surname": "Smith"
}}
Type: String
Value: "John"
Results View: Expanding the Results View will enumerate the IEnumerable
I use the object with this simple DotLiquid template:
Hello {{Name}} {{Surname}}. Number of Addresses: {{Addresses.size}} - {{Addresses[0].City}} - {{Addresses[1].City}}
With stuff1 object I got the exptected result:
Hello John Smith. Number of Addresses: 2 - New York - Milano
With stuff1Deserialized object I got this result:
Hello John Smith. Number of Addresses: 2 - -
Update as per comment
I find one way to do this:
1 - object dynamic sample:
dynamic dynamicStuff = new
{
Name = "John",
Surname = "Smith",
Obj = new { City = "New York", State = "NY" },// i add this to test object
Addresses = new[]
{
new { City = "New York", State = "NY"},
new { City = "Milano", State = "IT" }
}
};
2 - serializing and deserializing to build dynamic object:
dynamic dynamicStuffDeSerialized = JsonConvert.DeserializeObject(JsonConvert.SerializeObject(dynamicStuff));
3 - Converting dynamic object to JObject and building Dictionary Of (string, object) by converting JObject to Dictionary:
Dictionary<string, object> keyValuePairs = ConvertJObject(JObject.FromObject(dynamicStuffDeSerialized));
private static Dictionary<string, object> ConvertJObject(JObject jObject)
{
Dictionary<string, object> keyValuePairs = new Dictionary<string, object>();
foreach (var property in jObject)
{
if (property.Value.Type == JTokenType.Array)
keyValuePairs.Add(property.Key, ConvertJArray(property.Value.Select(o=>(JObject)o)));
else if (property.Value.Type == JTokenType.Object)
keyValuePairs.Add(property.Key, ConvertJObject((JObject)property.Value));
else
keyValuePairs.Add(property.Key, property.Value.ToString());
}
return keyValuePairs;
}
private static List<Dictionary<string, object>> ConvertJArray(IEnumerable<JObject> jObjects)
{
return jObjects.Select(o => ConvertJObject(o)).ToList();
}
Note That, you can use ToObject to convert JObject To Dictionary, but it's convert just the simple value not object or array, like:
JObject jObject = JObject.FromObject(dynamicStuffDeSerialized);
Dictionary<string, object> dict = jObject.ToObject<Dictionary<string, object>>();
4 - use Hash.FromDictionary not Hash.FromAnonymousObject:
Template templatedynamicStuff = Template.Parse("Hello {{Name}} {{Surname}} City in Object {{Obj.City}}. Number of Addresses: {{Addresses.size}} - {{Addresses[0].City}} - {{Addresses[1].City}}");
string result = templatedynamicStuff.Render(Hash.FromDictionary(keyValuePairs));
Note that, i changed the template by adding City in Object {{Obj.City}}
5 - TEST
Console.WriteLine(result);
6 - OUTCOMES:
Hello John Smith City in Object New York. Number of Addresses: 2 - New York - Milano
Old answers
According to newtonsoft documentation, You can use DeserializeAnonymousType instead of DeserializeObject for deserializing Anonymous Object. but DeserializeAnonymousType needs a definition of Anonymous Type To get the same object.
Like the following code :
var stuff1 = new
{
Name = "John",
Surname = "Smith"
};
var stuff1Serialized = JsonConvert.SerializeObject(stuff1);
var definition = new { Name = "", Surname = "" };
dynamic stuff1Deserialized = JsonConvert.DeserializeAnonymousType(stuff1Serialized, definition);
Update as per comment
You can use JObject or ExpandoObject to get properties names and values, like the following code:
dynamic stuff1 = new
{
Name = "John",
Surname = "Smith"
};
var stuff1Serialized = JsonConvert.SerializeObject(stuff1);
dynamic stuff1DeSerialized1 = JsonConvert.DeserializeObject(stuff1Serialized);
foreach (JProperty property in JObject.FromObject(stuff1DeSerialized1))
{
Console.WriteLine($"Key:{property.Name}, Value:{property.Value}");
}
ExpandoObject stuff1DeSerialized2 = JsonConvert.DeserializeObject<ExpandoObject>(stuff1Serialized, new ExpandoObjectConverter());
foreach(KeyValuePair<string, object> keyValue in stuff1DeSerialized2.ToList())
{
Console.WriteLine($"Key:{keyValue.Key}, Value:{keyValue.Value}");
}
I hope to find other solution and share it with you.

C# : How to save Dictionary<string, string> in datatable and dataset in XML file locally

How can I store a dictionary object of type <string, string> using the datatable and dataset in XML file? I am able to save text field value but not able to store and retrieve dictionary data.
Try to use linq2xml.
For example, you have dictionary:
var dict = new Dictionary<string, string>
{
{ "1", "aa" }, { "2", "bb" }, { "3", "cc" }
};
Save it to xml file:
var doc = new XElement("dict");
foreach (var pair in dict)
doc.Add(new XElement("pair",
new XElement("key", pair.Key), new XElement("value", pair.Value)
));
doc.Save("test.xml");
Load from xml file to dictionary:
var xml = XElement.Load("test.xml");
dict = xml.Elements("pair")
.ToDictionary(e => e.Element("key").Value, e => e.Element("value").Value);

Calling a method with a Dictionary argument

I have a method starting with this line
public string CustomerInfo(Dictionary<string, object> arglist)
I am trying to call it with this code
string testval = CustomerInfo(Dictionary< string, object>);
The error is
Dictionary is a type but used as a variable.
Thanks for any suggestions.
There's an issue in your code. The dictionary being passed is not initialized
you should try
String testval = CustomerInfo(new Dictionary< string, object>());
or
var dictionary = new Dictionary< string, object>();
string testval = CustomerInfo(dictionary);
You may do it this way
string testval = CustomerInfo(new Dictionary<string, object>());
C# 6 Dictionary Initializers
string testval = CustomerInfo(new Dictionary<string, object>() {
{ "1",1 } , {"2",2 }, {"3",new object() }
});
Or pass a dictionary object
var arglist = new Dictionary<string, object>() {
{ "1",1 } , {"2",2 }, {"3",new object() }
};
string testval = CustomerInfo(arglist);

JSON string to object using Enums

I have JSON string, something like:
{"1":{"1":"driver","2":"New York, NY"},"2":{"3":"male","2":"Alabama"}}
I have two enums:
public enum StoragePrimaryKeys
{
Login = 1,
Account = 2
};
public enum StorageSecondaryKeys
{
JobTitle = 1,
JobId = 2,
JobLocation = 3,
RenewDate = 4,
ExpirationDate = 5
};
How can I deserialize this JSON to an object?
I thought to do the next thing:
var jss = new JavaScriptSerializer();
Dictionary<string, string> sData = jss.Deserialize<Dictionary<string, string>>(value);
string output = string.empty;
foreach (KeyValuePair<string, string> entry in sData)
{
if (Convert.ToInt32(entry.Key) == StorageSecondaryKeys.JobTitle) {
}
output += "\n key:" + entry.Key + ", value:" + entry.Value;
}
But maybe there is more efficient way?
I think It's a new question cause I have numbers in the keys that should be translated to the strings of the enums
Thanks.
It appears your data model should be as follows:
Dictionary<StoragePrimaryKeys, Dictionary<StorageSecondaryKeys, string>>
However, from experimentation, I found that JavaScriptSerializer does not support enums as dictionary keys, so you cannot deserialize to such an object directly. Thus you could deserialize to string-keyed dictionaries and convert using Linq:
var dict = new JavaScriptSerializer().Deserialize<Dictionary<string, Dictionary<string, string>>>(value)
.ToDictionary(
p => (StoragePrimaryKeys)Enum.Parse(typeof(StoragePrimaryKeys), p.Key),
p => p.Value.ToDictionary(p2 => (StorageSecondaryKeys)Enum.Parse(typeof(StorageSecondaryKeys), p2.Key), p2 => p2.Value));
This will produce the dictionary you want.
Alternatively, you could install json.net and deserialize directly to the desired dictionary, since Json.NET does support enum-keyed dictionaries:
var dict = JsonConvert.DeserializeObject<Dictionary<StoragePrimaryKeys, Dictionary<StorageSecondaryKeys, string>>>(value);

Json.net deserializing dictionary containing dictionary with value of dataTable

I am fairly new to programming (outside of a classroom environment).
I'm working on an application that has plugins. Each plugin packs/unpacks it's state (as a dictionary) and sends itself to be added to a dictionary containing all packed states. I'm using Json.Net to serialize/deserialize and pass off each plugin to it's own class to be packed/unpacked depending on if the project is being saved or opened.
The problem I'm having is when my first plugin gets its dictionary version of it's packed state to unpack, and I start going through the repopulating of each property, the first property (first item in the dictionary) is a DataTable. I'm getting an error saying:
Unable to cast object of type 'Newtonsoft.Json.Linq.JArray' to
type 'System.Data.DataTable'.
Here is my code for serializing.
IDictionary<string, IDictionary<string, object>> pluginStates =
new Dictionary<string, IDictionary<string, object>>();
signaller.RaiseSaveRequest(pluginStates); //gets all of the plugins' packedState
JsonSerializer serializer = new JsonSerializer();
serializer.ObjectCreationHandling = ObjectCreationHandling.Replace;
serializer.TypeNameHandling = TypeNameHandling.All;
using (StreamWriter sw = new StreamWriter(strPathName))
using (JsonWriter writer = new JsonTextWriter(sw))
{
serializer.Serialize(writer, pluginStates);
}
and deserializing.
IDictionary<string, IDictionary<string, object>> pluginStates =
new Dictionary<string, IDictionary<string, object>>();
JsonSerializer serializer = new JsonSerializer();
serializer.ObjectCreationHandling = ObjectCreationHandling.Replace;
serializer.TypeNameHandling = TypeNameHandling.All;
StreamReader sr = new StreamReader(fullName);
JsonTextReader reader = new JsonTextReader(sr);
string json = sr.ReadToEnd();
pluginStates = serializer.Deserialize<IDictionary<string, IDictionary<string, Object>>>(reader);
pluginStates = JsonConvert.DeserializeObject<IDictionary<string, IDictionary<string, Object>>>(json);
sr.Close();
reader.Close();
signaller.UnpackProjectState(pluginStates);
I've tried looking at the documentation on NewtonSoft.Json, but I barely understand it and how to make it work in my code. I'm thinking I need to do something with the Converters or Parsing once the plugin gets its packed state to unpack. When it was packed up, the plugin's 1st dictionary entry was saved as DataTable. Then, when in the Unpack, it's the actual dataTable in the value with the : separators.
I would provide screen shots, but I haven't figured out how to do that. Any ideas what I'm missing??
THANKS!
When a project is saved, the ProjMngr gets the packed pluginStates dictionary. I loop through each dictionary (plugin) within the pluginStates dictionary and create a dictionary holding the key, value(the json string version) and key, value(.net type). Add these to an array and put the array in the final projectState dictionary that gets serialized. Here's the code.
signaller.RaiseSaveRequest(pluginStates); <----has all plugin's packedState
//loop through plugins to get values and types
Dictionary<string, object> dictProjectState = new Dictionary<string, object>();
foreach (KeyValuePair<string,IDictionary<string,object>> plugin in pluginStates)
{
//holds jsonRepresented values
Dictionary<string, object> dictJsonRep = new Dictionary<string, object>();
//holds object types
Dictionary<string, object> dictObjRep = new Dictionary<string, object>();
object[] arrayDictHolder = new object[2]; //holds all of the dictionaries
string pluginKey = plugin.Key;
IDictionary<string, object> pluginValue = new Dictionary<string, object>();
pluginValue = plugin.Value;
foreach (KeyValuePair<string, object> element in pluginValue)
{
string jsonRepresentation = JsonConvert.SerializeObject(element.Value);
object objType = element.Value.GetType();
dictJsonRep.Add(element.Key, jsonRepresentation);
dictObjRep.Add(element.Key, objType);
}
arrayDictHolder[0] = dictJsonRep;
arrayDictHolder[1] = dictObjRep;
dictProjectState.Add(pluginKey, arrayDictHolder);
}
JsonSerializer serializer = new JsonSerializer();
using (StreamWriter sw = new StreamWriter(strPathName))
using (JsonWriter writer = new JsonTextWriter(sw))
{
serializer.Serialize(writer, dictProjectState);
}
Then when a project is opened, I did the same thing in reverse to get the pluginState back in it's original state to send off to each plugin. Used the type to make sure the type was right before sending. Realized I had to deserialize several times, which was surprising. I just couldn't get away from the Jarray or Jobject. But this works. Here's how I opened.
IDictionary<string, IDictionary<string, object>> pluginStates = new Dictionary<string, IDictionary<string, object>>();
StreamReader sr = new StreamReader(fullName);
JsonTextReader reader = new JsonTextReader(sr);
string json = sr.ReadToEnd();
var dictProjectState = JsonConvert.DeserializeObject<Dictionary<string, object>>(json);
sr.Close();
reader.Close();
foreach (var projectStatePair in dictProjectState)
{
string pluginKey = projectStatePair.Key; //key in pluginStates dict
Dictionary<string, object> dictJsonRep = new Dictionary<string, object>();
Dictionary<string, object> dictObjRep = new Dictionary<string, object>();
Dictionary<string, object> pluginValues = new Dictionary<string, object>();
string stpluginValue = projectStatePair.Value.ToString();
Newtonsoft.Json.Linq.JArray ja = (Newtonsoft.Json.Linq.JArray)JsonConvert.DeserializeObject(stpluginValue);
object[] arrayHolder = ja.ToObject<object[]>();
string strArray0 = arrayHolder[0].ToString();
string strArray1 = arrayHolder[1].ToString();
dictJsonRep = JsonConvert.DeserializeObject<Dictionary<string, object>>(strArray0);
dictObjRep = JsonConvert.DeserializeObject<Dictionary<string, object>>(strArray1);
foreach (var pair in dictJsonRep)
{
string strVariableKey = pair.Key;
object objType = dictObjRep[pair.Key];
string jsonRep = (string)pair.Value;
Type jsonType = Type.GetType(objType as string);
object jsonReprValue = null;
jsonReprValue = JsonConvert.DeserializeObject(jsonRep, jsonType);
pluginValues.Add(strVariableKey, jsonReprValue);
}
pluginStates.Add(pluginKey, pluginValues);
}
signaller.UnpackProjectState(pluginStates);
Hopes this helps anyone looking for an answer.

Categories