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.
Related
For some of my unit tests I want the ability to build up particular JSON values (record albums in this case) that can be used as input for the system under test.
I have the following code:
var jsonObject = new JObject();
jsonObject.Add("Date", DateTime.Now);
jsonObject.Add("Album", "Me Against The World");
jsonObject.Add("Year", 1995);
jsonObject.Add("Artist", "2Pac");
This works fine, but I have never really like the "magic string" syntax and would prefer something closer to the expando-property syntax in JavaScript like this:
jsonObject.Date = DateTime.Now;
jsonObject.Album = "Me Against The World";
jsonObject.Year = 1995;
jsonObject.Artist = "2Pac";
Well, how about:
dynamic jsonObject = new JObject();
jsonObject.Date = DateTime.Now;
jsonObject.Album = "Me Against the world";
jsonObject.Year = 1995;
jsonObject.Artist = "2Pac";
You can use the JObject.Parse operation and simply supply single quote delimited JSON text.
JObject o = JObject.Parse(#"{
'CPU': 'Intel',
'Drives': [
'DVD read/writer',
'500 gigabyte hard drive'
]
}");
This has the nice benefit of actually being JSON and so it reads as JSON.
Or you have test data that is dynamic you can use JObject.FromObject operation and supply a inline object.
JObject o = JObject.FromObject(new
{
channel = new
{
title = "James Newton-King",
link = "http://james.newtonking.com",
description = "James Newton-King's blog.",
item =
from p in posts
orderby p.Title
select new
{
title = p.Title,
description = p.Description,
link = p.Link,
category = p.Categories
}
}
});
Json.net documentation for serialization
Neither dynamic, nor JObject.FromObject solution works when you have JSON properties that are not valid C# variable names e.g. "#odata.etag". I prefer the indexer initializer syntax in my test cases:
JObject jsonObject = new JObject
{
["Date"] = DateTime.Now,
["Album"] = "Me Against The World",
["Year"] = 1995,
["Artist"] = "2Pac"
};
Having separate set of enclosing symbols for initializing JObject and for adding properties to it makes the index initializers more readable than classic object initializers, especially in case of compound JSON objects as below:
JObject jsonObject = new JObject
{
["Date"] = DateTime.Now,
["Album"] = "Me Against The World",
["Year"] = 1995,
["Artist"] = new JObject
{
["Name"] = "2Pac",
["Age"] = 28
}
};
With object initializer syntax, the above initialization would be:
JObject jsonObject = new JObject
{
{ "Date", DateTime.Now },
{ "Album", "Me Against The World" },
{ "Year", 1995 },
{ "Artist", new JObject
{
{ "Name", "2Pac" },
{ "Age", 28 }
}
}
};
There are some environment where you cannot use dynamic (e.g. Xamarin.iOS) or cases in where you just look for an alternative to the previous valid answers.
In these cases you can do:
using Newtonsoft.Json.Linq;
JObject jsonObject =
new JObject(
new JProperty("Date", DateTime.Now),
new JProperty("Album", "Me Against The World"),
new JProperty("Year", "James 2Pac-King's blog."),
new JProperty("Artist", "2Pac")
)
More documentation here:
http://www.newtonsoft.com/json/help/html/CreatingLINQtoJSON.htm
Sooner or later you will have property with a special character. e.g. Create-Date. The hyphen won't be allowed in property name. This will break your code. In such scenario, You can either use index or combination of index and property.
dynamic jsonObject = new JObject();
jsonObject["Create-Date"] = DateTime.Now; //<-Index use
jsonObject.Album = "Me Against the world"; //<- Property use
jsonObject["Create-Year"] = 1995; //<-Index use
jsonObject.Artist = "2Pac"; //<-Property use
Simple way of creating newtonsoft JObject from Properties.
This is a Sample User Properties
public class User
{
public string Name;
public string MobileNo;
public string Address;
}
and i want this property in newtonsoft JObject is:
JObject obj = JObject.FromObject(new User()
{
Name = "Manjunath",
MobileNo = "9876543210",
Address = "Mumbai, Maharashtra, India",
});
Output will be like this:
{"Name":"Manjunath","MobileNo":"9876543210","Address":"Mumbai, Maharashtra, India"}
May I suggest using the nameof expression combined with a model for the structure you're trying to build?
Example:
record RecordAlbum(string Album, string Artist, int Year);
var jsonObject = new JObject
{
{ nameof(RecordAlbum.Album), "Me Against The World" },
{ nameof(RecordAlbum.Artist), "2Pac" },
{ nameof(RecordAlbum.Year), 1995 }
};
As an added benefit to removing the "magic string" aspect - this also will give you a little bit of refactor-ability. You can easily rename any given property name for the record and it should update the value returned by the nameof() expression.
You can use Newtonsoft library and use it as follows
using Newtonsoft.Json;
public class jb
{
public DateTime Date { set; get; }
public string Artist { set; get; }
public int Year { set; get; }
public string album { set; get; }
}
var jsonObject = new jb();
jsonObject.Date = DateTime.Now;
jsonObject.Album = "Me Against The World";
jsonObject.Year = 1995;
jsonObject.Artist = "2Pac";
System.Web.Script.Serialization.JavaScriptSerializer oSerializer =
new System.Web.Script.Serialization.JavaScriptSerializer();
string sJSON = oSerializer.Serialize(jsonObject );
I have a JObject such as :
JObject obj = new JObject();
obj.Add(new JProperty("Name","Olivier"));
obj.Add(new JProperty("Surname","Big"));
obj.Add(new JProperty("FatherName","Johnatan"));
I want to convert obj above to object
If I use the this code below
var result1 = Newtonsoft.Json.JsonConvert.DeserializeObject<object>(obj.ToString());
the result is like this
But the result that wanted is like below
var TheResultIWant = new { Name = "Olivier", Surname = "Big", FatherName = "Johnatan" };
Is there any kind of way I can obtain the object like the second image. I cannot code like it because I don't know the property name.
Well, you could use method DeserializeAnonymousType for that:
JObject obj = new JObject();
obj.Add(new JProperty("Name", "Olivier"));
obj.Add(new JProperty("Surname", "Big"));
obj.Add(new JProperty("FatherName", "Johnatan"));
var result = new
{
Name = "",
Surname = "",
FatherName = ""
};
result = JsonConvert.DeserializeAnonymousType(obj.ToString(), result);
Another option is to use dynamic and third option which is by far most used is to create your own type and use it:
public class Person
{
public string Name { get; set; }
...
}
Person result = JsonConvert.DeserializeObject<Person>(obj.ToString());
A JObject is an already deserialized object. It can be used as a dynamic object so there's no need to serialize to a string and get back another object.
dynamic TheResultIWant = obj;
var name=TheResultIWant.Name;
It's already possible to access properties by key, like a dictionary:
var name=obj["Name"];
This returns a JToken. If the type of the value is known, Value< T> or Values<T> can be used to retrieve it:
var name=obj["Name"].Value<string>();
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"}]
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);
List<User> list = LoadUsers();
JObject json = new JObject();
json["users"] = new JValue(list);
Doesn't seem to be working?
Error:
Could not determine JSON object type for type System.Collections.Generic.List`1
A JValue can only contain simple values like strings, ints, booleans, dates and the like. It cannot contain a complex object. I suspect what you really want is this:
List<User> list = LoadUsers();
JObject json = new JObject();
json["users"] = JToken.FromObject(list);
The above will convert the list of User objects into a JArray of JObjects representing the users, then assign that to the users property on the new JObject. You can confirm this by examining the Type property of json["users"] and see that it is Array.
In contrast, if you do json["users"] = new JValue(JsonConvert.SerializeObject(list)) as was suggested in another answer to this question (now deleted), you will probably not get the result you are looking for. That approach will serialize the list of users to a string, create a simple JValue from that, and then assign the JValue to the users property on the JObject. If you examine the Type property of json["users"], you will see that it is String. What this means is, if you later try to convert the JObject to JSON by using json.ToString(), you will get double-serialized output instead of the JSON you probably expect.
Here is a short demo to illustrate the difference:
class Program
{
static void Main(string[] args)
{
List<User> list = new List<User>
{
new User { Id = 1, Username = "john.smith" },
new User { Id = 5, Username = "steve.martin" }
};
JObject json = new JObject();
json["users"] = JToken.FromObject(list);
Console.WriteLine("First approach (" + json["users"].Type + "):");
Console.WriteLine();
Console.WriteLine(json.ToString(Formatting.Indented));
Console.WriteLine();
Console.WriteLine(new string('-', 30));
Console.WriteLine();
json["users"] = new JValue(JsonConvert.SerializeObject(list));
Console.WriteLine("Second approach (" + json["users"].Type + "):");
Console.WriteLine();
Console.WriteLine(json.ToString(Formatting.Indented));
}
class User
{
public int Id { get; set; }
public string Username { get; set; }
}
}
Output:
First approach (Array):
{
"users": [
{
"Id": 1,
"Username": "john.smith"
},
{
"Id": 5,
"Username": "steve.martin"
}
]
}
------------------------------
Second approach (String):
{
"users": "[{\"Id\":1,\"Username\":\"john.smith\"},{\"Id\":5,\"Username\":\"steve.martin\"}]"
}
I had this issue, you can now use JArray to get this done, if you just want the array items with no root name.
var json = JArray.FromObject(LoadUsers());
If you want the root name of the json array to be "users", you can use
var json = new JObject { ["users"] = JToken.FromObject(LoadUsers()) };