Consider this code:
JObject obj = JObject.Parse(json);
Dictionary<string,object> dict = new Dictionary<string, object>();
List<string> parameters = new List<string>{"Car", "Truck", "Van"};
foreach (var p in parameters)
{
JToken token = obj.SelectToken(string.Format("$.results[?(#.paramName == '{0}')]['value']", p));
dict[p] = token.Value<object>();
}
string jsonOutput = JsonConvert.SerializeObject(dict);
where json contains, in part:
{
"paramName": "Car",
"value": 68.107
},
{
"paramName": "Truck",
"value": 48.451
},
{
"paramName": "Van",
"value": 798300
}
While debugging this, I inspected the dictionary and found the values were not of type object but actual numeric types like integer and float. Since the dictionary was declared as Dictionary<string, object> dict = new Dictionary<string, object>(); I expected the values to be of type object and that I would need to cast them upon use.
The JSON output string is {"Car":68.107,"Truck":48.451,"Van":798300}.
How does the dictionary know the type of the value and why do I get the actual type instead of the base type object?
When you call
JsonConvert.SerializeObject(dict);
this takes an object, which then figures out the type, and stores it accordingly.
Therefore for each item in the dictionary entry. it first checks the type and then deserializes it according to its type.
If you wanted to use the object outside of JSON, you would have to check yourself with something like
var o = dict["Car"];
if(o is int) return (int)o; // or whatever you want to do with an int
if(o is decimal) return (decimal)o; // or whatever you want to do with an decimal
When you inspect an instance in the debugger, the debugger just shows you the output of the .ToString() for the item. Run the following code:
namespace ConsoleApplication1
{
public class Program
{
private static void Main(string[] args)
{
var dic = new Dictionary<string, object>
{
{ "One", "1" }, { "Two", 2 },
{ "Three", 3.0 }, { "Four", new Person() },
{ "Five", new SimplePerson() },
};
foreach (var thisItem in dic)
{
// thisItem.Value will show "1", 2, 3, "Test"
// and ConsoleApplication1.SimplePerson
Console.WriteLine($"{ thisItem.Key } : { thisItem.Value }");
}
var obj = JsonConvert.SerializeObject(dic);
}
}
public class SimplePerson
{
}
public class Person
{
public override string ToString()
{
return "Test";
}
}
}
When you hover over the this.Value, it will show the result of ToString(). So it will show the following:
"1"
2
3
"Test" // since Person class overrides the ToString()
// since by default when ToString() is called it will print out the object.
ConsoleApplication1.SimplePerson
Serialization
For serialization, it will produce the following:
{
"One": "1",
"Two": 2,
"Three": 3.0,
"Four": {
},
"Five": {
}
}
They are all boxed as object types but when the underlying type is whatever the type is. So in our case String",Int,Double,PersonandSimplePerson`. Therefore, during serialization it is unboxed.
Help me to deserialize the Dictionary object.
By example I have my class
[Serializable]
public class MyClass
{
/// <summary>
/// some class variables
/// </summary>
public string variable_A;
public decimal variable_B;
/// <summary>
/// constructor for example
/// </summary>
public MyClass(string s, decimal d)
{
variable_A = s;
variable_B = d;
}
}
and I create Dictionary - with string as a key, and MyClass object as a value:
Dictionary<string, MyClass> myDictionary = new Dictionary<string, MyClass>
{
{ "key1", new MyClass("some string value", 5) },
{ "key2", new MyClass("some string value", 3) },
{ "key3", new MyClass("some string value", 10) }
};
Here I serialize this data to trasfer to other place:
string myObjectJson = new JavaScriptSerializer().Serialize(myDictionary);
Console.WriteLine(myObjectJson);
But how can I do reverse operation - to deserialize this data back to my Dictionary object?
I tried to use DeserializeObject like this:
JavaScriptSerializer js = new JavaScriptSerializer();
Dictionary<string, MyClass> dict = (Dictionary<string, Object>)js.DeserializeObject(myObjectJson);
//// Also tried this method, but it describes deserialize to Dictionary<string, string>, but I have my object in value, not string
//// http://stackoverflow.com/questions/4942624/how-to-convert-dictionarystring-object-to-dictionarystring-string-in-c-sha
//// p.s.: don't want to use third-party dll's, like Json.Net
//// http://stackoverflow.com/questions/19023696/deserialize-dictionarystring-t
You should use the generic overload:
var dict = new JavaScriptSerializer().Deserialize<Dictionary<string, MyClass>>(myObjectJson);
Also make sure that MyClass type has a default constructor.
I have the following code:
///<summary>
///In this case you can set any other valid attribute for the editable element.
///For example, if the element is edittype:'text', we can set size, maxlength,
///etc. attributes. Refer to the valid attributes for the element
///</summary>
public object OtherOptions { get; set; }
public override string ToString()
{
return this.ToJSON();
}
I need to get the anonymous object from the OtherOptions property and serialize each property of the anonymous object as it were from the main object.
E.g.:
OtherOptions = new { A = "1", B = "2" }
If I serialize it, it will be (or something like this):
OtherOptions: {
A: "1",
B: "2"
}
Is it possible to have A and B at the same level of OtherOptions without explicitly removing it.
Ok this is just ugly and I don't recommend doing it but it does what you want...
Essentially, it creates a Dictionary of just the properties you want and then serializes that dictionary.
static void Main(string[] args)
{
JavaScriptSerializer serializer = new JavaScriptSerializer();
var obj = new {Prop1 = "val1", OtherOptions = new {A = "1", B = "2"}};
IDictionary<string, object> result = new Dictionary<string, object>();
foreach (var kv in GetProps(obj))
{
if (!kv.Key.Equals("OtherOptions"))
result.Add(kv);
}
foreach (var kv in GetProps(obj.OtherOptions))
{
result.Add(kv);
}
var serialized = serializer.Serialize(result);
}
static IEnumerable<KeyValuePair<string, object>> GetProps(object obj)
{
var props = TypeDescriptor.GetProperties(obj);
return
props.Cast<PropertyDescriptor>()
.Select(prop => new KeyValuePair<string, object>(prop.Name, prop.GetValue(obj)));
}
serialized becomes
{"Prop1":"val1","A":"1","B":"2"}
You could use an attribute on the field you want to ignore and then check for that attribute in the GetProps method and not return if exists.
Again, I do not recommend doing this.
I am looking to use JSON.net to deserialize a JSON structure into a Dictionary. The trick is that the JSON document is a hierarchy of nested objects but I'd like to only look at the top-level property+value pairs.
Eg.
{
"prop1": 142,
"prop2": "Some description",
"object_prop": {
"abc": 2,
"def": {
"foo": "hello",
"bar": 4
}
}
}
Based on the above example, I'd like to have my deserialized dictionary have 3 items in it: "prop1", "prop2", and "object_prop". "object_prop" should just be a string (which I will deserialize to an object at some later point in time.
Note: I'm looking to do this because I want to create a re-usable library that just knows about top-level key/value pairs and where clients consuming the library can define the type of the values at a later point in time. (ie. I don't want my re-usable library bound to the object types ... namely "object_prop").
How about something like this?
class Program
{
static void Main(string[] args)
{
string json = #"
{
""prop1"": 142,
""prop2"": ""Some description"",
""object_prop"": {
""abc"": 2,
""def"": {
""foo"": ""hello"",
""bar"": 4
}
},
""prop3"": 3.14
}";
Dictionary<string, string> dict = new Dictionary<string, string>();
JObject jo = JObject.Parse(json);
foreach (JProperty prop in jo.Properties())
{
if (prop.Value.Type == JTokenType.Array ||
prop.Value.Type == JTokenType.Object)
{
// JSON string for complex object
dict.Add(prop.Name, prop.Value.ToString(Formatting.None));
}
else
{
// primitive value converted to string
object value = ((JValue)prop.Value).Value;
dict.Add(prop.Name, value != null ? value.ToString() : null);
}
}
foreach (KeyValuePair<string, string> kvp in dict)
{
Console.WriteLine(kvp.Key + " = " + kvp.Value);
}
}
}
Output:
prop1 = 142
prop2 = Some description
object_prop = {"abc":2,"def":{"foo":"hello","bar":4}}
prop3 = 3.14
I really like the ExpandoObject while compiling a server-side dynamic object at runtime, but I am having trouble flattening this thing out during JSON serialization. First, I instantiate the object:
dynamic expando = new ExpandoObject();
var d = expando as IDictionary<string, object>;
expando.Add("SomeProp", SomeValueOrClass);
So far so good. In my MVC controller, I want to then send this down as a JsonResult, so I do this:
return new JsonResult(expando);
This serializes the JSON into the below, to be consumed by the browser:
[{"Key":"SomeProp", "Value": SomeValueOrClass}]
BUT, what I'd really like is to see this:
{SomeProp: SomeValueOrClass}
I know I can achieve this if I use dynamic instead of ExpandoObject -- JsonResult is able to serialize the dynamic properties and values into a single object (with no Key or Value business), but the reason I need to use ExpandoObject is because I don't know all of the properties I want on the object until runtime, and as far as I know, I cannot dynamically add a property to a dynamic without using an ExpandoObject.
I may have to sift through the "Key", "Value" business in my javascript, but I was hoping to figure this out prior to sending it to the client. Thanks for your help!
Using JSON.NET you can call SerializeObject to "flatten" the expando object:
dynamic expando = new ExpandoObject();
expando.name = "John Smith";
expando.age = 30;
var json = JsonConvert.SerializeObject(expando);
Will output:
{"name":"John Smith","age":30}
In the context of an ASP.NET MVC Controller, the result can be returned using the Content-method:
public class JsonController : Controller
{
public ActionResult Data()
{
dynamic expando = new ExpandoObject();
expando.name = "John Smith";
expando.age = 30;
var json = JsonConvert.SerializeObject(expando);
return Content(json, "application/json");
}
}
You could also, make a special JSONConverter that works only for ExpandoObject and then register it in an instance of JavaScriptSerializer. This way you could serialize arrays of expando,combinations of expando objects and ... until you find another kind of object that is not getting serialized correctly("the way u want"), then you make another Converter, or add another type to this one. Hope this helps.
using System.Web.Script.Serialization;
public class ExpandoJSONConverter : JavaScriptConverter
{
public override object Deserialize(IDictionary<string, object> dictionary, Type type, JavaScriptSerializer serializer)
{
throw new NotImplementedException();
}
public override IDictionary<string, object> Serialize(object obj, JavaScriptSerializer serializer)
{
var result = new Dictionary<string, object>();
var dictionary = obj as IDictionary<string, object>;
foreach (var item in dictionary)
result.Add(item.Key, item.Value);
return result;
}
public override IEnumerable<Type> SupportedTypes
{
get
{
return new ReadOnlyCollection<Type>(new Type[] { typeof(System.Dynamic.ExpandoObject) });
}
}
}
Using converter
var serializer = new JavaScriptSerializer();
serializer.RegisterConverters(new JavaScriptConverter[] { new ExpandoJSONConverter()});
var json = serializer.Serialize(obj);
Here's what I did to achieve the behavior you're describing:
dynamic expando = new ExpandoObject();
expando.Blah = 42;
expando.Foo = "test";
...
var d = expando as IDictionary<string, object>;
d.Add("SomeProp", SomeValueOrClass);
// After you've added the properties you would like.
d = d.ToDictionary(x => x.Key, x => x.Value);
return new JsonResult(d);
The cost is that you're making a copy of the data before serializing it.
I solved this by writing an extension method that converts the ExpandoObject into a JSON string:
public static string Flatten(this ExpandoObject expando)
{
StringBuilder sb = new StringBuilder();
List<string> contents = new List<string>();
var d = expando as IDictionary<string, object>;
sb.Append("{");
foreach (KeyValuePair<string, object> kvp in d) {
contents.Add(String.Format("{0}: {1}", kvp.Key,
JsonConvert.SerializeObject(kvp.Value)));
}
sb.Append(String.Join(",", contents.ToArray()));
sb.Append("}");
return sb.ToString();
}
This uses the excellent Newtonsoft library.
JsonResult then looks like this:
return JsonResult(expando.Flatten());
And this is returned to the browser:
"{SomeProp: SomeValueOrClass}"
And I can use it in javascript by doing this (referenced here):
var obj = JSON.parse(myJsonString);
I hope this helps!
I was able to solve this same problem using JsonFx.
dynamic person = new System.Dynamic.ExpandoObject();
person.FirstName = "John";
person.LastName = "Doe";
person.Address = "1234 Home St";
person.City = "Home Town";
person.State = "CA";
person.Zip = "12345";
var writer = new JsonFx.Json.JsonWriter();
return writer.Write(person);
output:
{ "FirstName": "John", "LastName": "Doe", "Address": "1234 Home St",
"City": "Home Town", "State": "CA", "Zip": "12345" }
I took the flattening process one step further and checked for list objects, which removes the key value nonsense. :)
public string Flatten(ExpandoObject expando)
{
StringBuilder sb = new StringBuilder();
List<string> contents = new List<string>();
var d = expando as IDictionary<string, object>;
sb.Append("{ ");
foreach (KeyValuePair<string, object> kvp in d)
{
if (kvp.Value is ExpandoObject)
{
ExpandoObject expandoValue = (ExpandoObject)kvp.Value;
StringBuilder expandoBuilder = new StringBuilder();
expandoBuilder.Append(String.Format("\"{0}\":[", kvp.Key));
String flat = Flatten(expandoValue);
expandoBuilder.Append(flat);
string expandoResult = expandoBuilder.ToString();
// expandoResult = expandoResult.Remove(expandoResult.Length - 1);
expandoResult += "]";
contents.Add(expandoResult);
}
else if (kvp.Value is List<Object>)
{
List<Object> valueList = (List<Object>)kvp.Value;
StringBuilder listBuilder = new StringBuilder();
listBuilder.Append(String.Format("\"{0}\":[", kvp.Key));
foreach (Object item in valueList)
{
if (item is ExpandoObject)
{
String flat = Flatten(item as ExpandoObject);
listBuilder.Append(flat + ",");
}
}
string listResult = listBuilder.ToString();
listResult = listResult.Remove(listResult.Length - 1);
listResult += "]";
contents.Add(listResult);
}
else
{
contents.Add(String.Format("\"{0}\": {1}", kvp.Key,
JsonSerializer.Serialize(kvp.Value)));
}
//contents.Add("type: " + valueType);
}
sb.Append(String.Join(",", contents.ToArray()));
sb.Append("}");
return sb.ToString();
}
JsonResult uses JavaScriptSerializer which actually deserializes (the concrete) Dictionary<string, object> as you want.
There's an overload of the Dictionary<string, object> constructor which takes IDictionary<string, object>.
ExpandoObject implements IDictionary<string, object> (I think you can see where I am going here...)
Single level ExpandoObject
dynamic expando = new ExpandoObject();
expando.hello = "hi";
expando.goodbye = "cya";
var dictionary = new Dictionary<string, object>(expando);
return this.Json(dictionary); // or new JsonResult { Data = dictionary };
One line of code, using all built-in types :)
Nested ExpandoObjects
Of course if you are nesting ExpandoObjects then you will need to recursively convert them all into Dictionary<string, object>s:
public static Dictionary<string, object> RecursivelyDictionary(
IDictionary<string, object> dictionary)
{
var concrete = new Dictionary<string, object>();
foreach (var element in dictionary)
{
var cast = element.Value as IDictionary<string, object>;
var value = cast == null ? element.Value : RecursivelyDictionary(cast);
concrete.Add(element.Key, value);
}
return concrete;
}
your final code becoming
dynamic expando = new ExpandoObject();
expando.hello = "hi";
expando.goodbye = "cya";
expando.world = new ExpandoObject();
expando.world.hello = "hello world";
var dictionary = RecursivelyDictionary(expando);
return this.Json(dictionary);
This may not be useful to you, but I had a similar requirement, but used a SerializableDynamicObject
I changed the name of the dictionary to "Fields" and then this serializes with Json.Net to produce json which looks like:
{"Fields":{"Property1":"Value1", "Property2":"Value2" etc.
where Property1 and Property2 are Dynamically added properties - i.e. Dictionary Keys
It would be perfect if I could get rid of the extra "Fields" property which encapsulates the rest, but I've worked around that limitation.
Answer moved from this question on request
This is a late answer, but I had the same problem, and this question helped me solve them.
As a summary, I thought I should post my results, in hopes that it speeds up the implementation for others.
First the ExpandoJsonResult, which you can return an instance of in your action. Or you can override the Json method in your controller and return it there.
public class ExpandoJsonResult : JsonResult
{
public override void ExecuteResult(ControllerContext context)
{
HttpResponseBase response = context.HttpContext.Response;
response.ContentType = !string.IsNullOrEmpty(ContentType) ? ContentType : "application/json";
response.ContentEncoding = ContentEncoding ?? response.ContentEncoding;
if (Data != null)
{
JavaScriptSerializer serializer = new JavaScriptSerializer();
serializer.RegisterConverters(new JavaScriptConverter[] { new ExpandoConverter() });
response.Write(serializer.Serialize(Data));
}
}
}
Then the converter (which supports both serialization and de-serialization. See below for an example of how to de-serialize).
public class ExpandoConverter : JavaScriptConverter
{
public override object Deserialize(IDictionary<string, object> dictionary, Type type, JavaScriptSerializer serializer)
{ return DictionaryToExpando(dictionary); }
public override IDictionary<string, object> Serialize(object obj, JavaScriptSerializer serializer)
{ return ((ExpandoObject)obj).ToDictionary(x => x.Key, x => x.Value); }
public override IEnumerable<Type> SupportedTypes
{ get { return new ReadOnlyCollection<Type>(new Type[] { typeof(System.Dynamic.ExpandoObject) }); } }
private ExpandoObject DictionaryToExpando(IDictionary<string, object> source)
{
var expandoObject = new ExpandoObject();
var expandoDictionary = (IDictionary<string, object>)expandoObject;
foreach (var kvp in source)
{
if (kvp.Value is IDictionary<string, object>) expandoDictionary.Add(kvp.Key, DictionaryToExpando((IDictionary<string, object>)kvp.Value));
else if (kvp.Value is ICollection)
{
var valueList = new List<object>();
foreach (var value in (ICollection)kvp.Value)
{
if (value is IDictionary<string, object>) valueList.Add(DictionaryToExpando((IDictionary<string, object>)value));
else valueList.Add(value);
}
expandoDictionary.Add(kvp.Key, valueList);
}
else expandoDictionary.Add(kvp.Key, kvp.Value);
}
return expandoObject;
}
}
You can see in the ExpandoJsonResult class how to use it for serialization. To de-serialize, create the serializer and register the converter in the same way, but use
dynamic _data = serializer.Deserialize<ExpandoObject>("Your JSON string");
A big thank you, to all participants here that helped me.
Using returning dynamic ExpandoObject from WebApi in ASP.Net 4, the default JSON formatter seems to flatten ExpandoObjects into simple JSON object.
It seems like the serializer is casting the Expando to a Dictionary and then serializing it (thus the Key/Value business). Have you tried Deserializing as a Dictionary and then casting that back to an Expando?
I just had the same problem and figured out something pretty weird.
If I do:
dynamic x = new ExpandoObject();
x.Prop1 = "xxx";
x.Prop2 = "yyy";
return Json
(
new
{
x.Prop1,
x.Prop2
}
);
It works, but only if my method use HttpPost attribute. If I use HttpGet i get error.
So my answer works only on HttpPost. In my case it was an Ajax Call so i could change HttpGet by HttpPost.