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);
Related
I want to create a single object (possibly Dictionary) with string keys that will have different variable types as the value (string, int, bool, Dictionary<string,string> etc). Is this possible?
*I understand this might just be a fundamental difference of two languages AKA square peg round hole
You can use dynamic as values type, that match better than object to the question and you need no future castings:
var dictionary = new Dictionary<string, dynamic>();
dictionary.Add("1", 10);
dictionary.Add("2", "test");
dictionary.Add("3", true);
foreach ( var item in dictionary )
Console.WriteLine($"{item.Key} is type: {item.Value.GetType().Name} = {item.Value}");
Console.WriteLine();
int v = dictionary["1"] + 10;
Console.WriteLine(v);
string s = dictionary["2"] + " one";
Console.WriteLine(s);
bool b = !dictionary["3"];
Console.WriteLine(b);
Output
1 is type: Int32 = 10
2 is type: String = test
3 is type: Boolean = True
20
test one
False
https://learn.microsoft.com/dotnet/csharp/programming-guide/types/using-type-dynamic
A Dictionary<string, object> is roughly equivalent to an object in JavaScript.
Example:
var dictionary = new Dictionary<string, object>
{
"myString" = "helloWorld",
"myChild" = new Dictionary<string, object>
{
"myName" = "bobby tables"
}
};
var myString = (string)dictionary["myString"];
var myName = (string)((Dictionary<string, object>)dictionary["myChild"])["myName"];
You can also use the dynamic keyword and ExpandoObject.
dynamic obj = new ExpandoObject();
obj.MyString = "helloWorld";
obj.MyChild = new ExpandoObject();
obj.MyChild.MyName = "bobby tables";
string myString = obj.MyString;
string myName = obj.MyChild.MyName;
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.
I have the following code:
var tuple = new Tuple<string, string>("MyKey", "MyValue");
var list = new List<string>();
var str = tuple.ToString();
list.Add(str);
// str has the value "(MyKey, MyValue)"
I have a predefined object where I need to use a list of strings.
I decided to use a Tuple but I am not sure how I can cast the str value back to a Tuple.
How can I store a key value in a List so that I can use lambda to query it e.g. by the key?
All this code:
var tuple = new Tuple<string, string>("MyKey", "MyValue");
var list = new List<string>();
var str = tuple.ToString();
list.Add(str);
// str has the value "(MyKey, MyValue)"
Could be replaced by a dictionary:
Dictionary<string, string> values = new Dictionary<string, string>();
values.Add("MyKey", "MyValue");
Then you can use linq to query the dictionary if you'd like to do so:
value = values.Where(x => x.ContainsKey("MyKey"));
You can get a list with all the keys as follows:
List<string> keys = values.Keys;
So no need to have a separate list for that.
If you want a list of string with two values separated by a coma, the dictionary will do too:
List<string> keysValues = (from item in values
select item.Key + "," + item.Value).ToList();
Use Dictionary.
var dictionary = new Dictionary<string, string>();
dictionary.Add("myKey", "myVal");
if (dictionary.ContainsKey("myKey"))
dictionary["myKey"] = "myVal1";
I suggest you use a Dictionary. But if you really need to do it this way:
To transform from the string back to Tuple (assuming that the Key itself will never contain a commma+space):
var tuple = Tuple.Create("MyKey", "MyValue");
var list = new List<string>();
var str = tuple.ToString();
list.Add(str);
// str has the value "(MyKey, MyValue)"
Console.WriteLine(str);
int comma = str.IndexOf(", ");
string key = str.Substring(1,comma-1);
string valuee = str.Substring(comma+2,str.Length-key.Length-4);
var tuple2 = Tuple.Create(key, valuee);
// 'tuple2' is now equal to the orignal 'tuple'
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"}]
In the following code, I have a dictionary "nissi_params_fields" which I have populated with parameters:
Dictionary<string, string> nissi_params_fields = new Dictionary<string, string>();
string[] separator = { "," };
string[] dfields = form_fields.Split(separator, StringSplitOptions.RemoveEmptyEntries);
string[] ffields = db_fields.Split(separator, StringSplitOptions.RemoveEmptyEntries);
foreach (var field in ffields)
{
NissiMain nm = new NissiMain();
object field_object = nm.nissi_get_object_by_name(field);
string fieldvalue = nm.nissi_get_object_value_by_name(field_object);
nissi_params_fields[field] = fieldvalue;
this.nissiSetStorageItem(save_page, field, fieldvalue);
}
nissi_params_fields["company_id"] = this.nissiGetStorageItem("nissi_base", "ni_companyID");
string nissi_params_id = "";
if (save_type == "edit")
{
nissi_params_fields["id"] = this.nissiGetStorageItem(save_page, "id");
nissi_params_id = this.nissiGetStorageItem(save_page, "id");
}
I now want to create an anonymous type that contains the above "nissi_params_fields" dictionary as a single field "fields", so I first try to convert "nissi_params_fields" to an object "nissi_params_fields_object" that I can use in the Newtonsoft JObject "nissi_params_object":
object nissi_params_fields_object = nissi_params_fields.ToArray();
The challenge is how to convert the dictionary to an object ...how do I do this?
I now want to include the converted object "nissi_params_fields_object" in an anonymous type and then serialize the entire thing to JSON using the Newtonsoft JObject:
JObject nissi_params_object = JObject.FromObject(new
{
apikey = this.nissiGetStorageItem("nissi_base", "ni_apiKey"),
company_id = this.nissiGetStorageItem("nissi_base", "ni_companyID"),
id = nissi_params_id,
fields = nissi_params_fields_object,
});
If you just want to JSON serialize the object you can do:
string jsonString = JsonConvert.SerializeObject(nissi_params_object);
and then append jsonString to the URL.