Reputation: 16502
Is there a way to deserialize JSON content into a C# dynamic type? It would be nice to skip creating a bunch of classes in order to use the DataContractJsonSerializer
.
Upvotes: 1201
Views: 1174899
Reputation: 908
I really like System.Web.Helpers,
dynamic data = Json.Decode(json);
as it supports usage like
var val = data.Members.NumberTen;
or
var val data.Members["10"];
The reference to System.Web.Helpers.DLL is really crazy, it is not even console and desktop app friendly. Here is my attempt to extract the same functionalities as a standalone file directly from https://github.com/mono/aspnetwebstack/tree/master/src/System.Web.Helpers (Share this as for education purpose only)
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
using System.Collections.Generic;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Dynamic;
using System.Linq.Expressions;
using System.Runtime.CompilerServices;
using Microsoft.CSharp.RuntimeBinder;
using System.Web.Script.Serialization;
using System.IO;
using System.Collections;
using System.Linq;
using System.Globalization;
namespace System.Web.Helpers
{
public static class Json
{
private static readonly JavaScriptSerializer _serializer = CreateSerializer();
public static string Encode(object value)
{
// Serialize our dynamic array type as an array
DynamicJsonArray jsonArray = value as DynamicJsonArray;
if (jsonArray != null)
{
return _serializer.Serialize((object[])jsonArray);
}
return _serializer.Serialize(value);
}
public static void Write(object value, TextWriter writer)
{
writer.Write(_serializer.Serialize(value));
}
public static dynamic Decode(string value)
{
return WrapObject(_serializer.DeserializeObject(value));
}
public static dynamic Decode(string value, Type targetType)
{
return WrapObject(_serializer.Deserialize(value, targetType));
}
public static T Decode<T>(string value)
{
return _serializer.Deserialize<T>(value);
}
private static JavaScriptSerializer CreateSerializer()
{
JavaScriptSerializer serializer = new JavaScriptSerializer();
serializer.RegisterConverters(new[] { new DynamicJavaScriptConverter() });
return serializer;
}
internal class DynamicJavaScriptConverter : JavaScriptConverter
{
public override IEnumerable<Type> SupportedTypes
{
get
{
yield return typeof(IDynamicMetaObjectProvider);
yield return typeof(DynamicObject);
}
}
public override object Deserialize(IDictionary<string, object> dictionary, Type type, JavaScriptSerializer serializer)
{
throw new NotSupportedException();
}
public override IDictionary<string, object> Serialize(object obj, JavaScriptSerializer serializer)
{
Dictionary<string, object> dictionary = new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase);
IEnumerable<string> memberNames = DynamicHelper.GetMemberNames(obj);
foreach (string item in memberNames)
{
dictionary[item] = DynamicHelper.GetMemberValue(obj, item);
}
return dictionary;
}
}
internal static dynamic WrapObject(object value)
{
// The JavaScriptSerializer returns IDictionary<string, object> for objects
// and object[] for arrays, so we wrap those in different dynamic objects
// so we can access the object graph using dynamic
var dictionaryValues = value as IDictionary<string, object>;
if (dictionaryValues != null)
{
return new DynamicJsonObject(dictionaryValues);
}
var arrayValues = value as object[];
if (arrayValues != null)
{
return new DynamicJsonArray(arrayValues);
}
return value;
}
}
// REVIEW: Consider implementing ICustomTypeDescriptor and IDictionary<string, object>
public class DynamicJsonObject : DynamicObject
{
private readonly IDictionary<string, object> _values;
public DynamicJsonObject(IDictionary<string, object> values)
{
Debug.Assert(values != null);
_values = values.ToDictionary(p => p.Key, p => Json.WrapObject(p.Value),
StringComparer.OrdinalIgnoreCase);
}
public override bool TryConvert(ConvertBinder binder, out object result)
{
result = null;
if (binder.Type.IsAssignableFrom(_values.GetType()))
{
result = _values;
}
else
{
throw new InvalidOperationException(String.Format(CultureInfo.CurrentCulture, "HelpersResources.Json_UnableToConvertType", binder.Type));
}
return true;
}
public override bool TryGetMember(GetMemberBinder binder, out object result)
{
result = GetValue(binder.Name);
return true;
}
public override bool TrySetMember(SetMemberBinder binder, object value)
{
_values[binder.Name] = Json.WrapObject(value);
return true;
}
public override bool TrySetIndex(SetIndexBinder binder, object[] indexes, object value)
{
string key = GetKey(indexes);
if (!String.IsNullOrEmpty(key))
{
_values[key] = Json.WrapObject(value);
}
return true;
}
public override bool TryGetIndex(GetIndexBinder binder, object[] indexes, out object result)
{
string key = GetKey(indexes);
result = null;
if (!String.IsNullOrEmpty(key))
{
result = GetValue(key);
}
return true;
}
private static string GetKey(object[] indexes)
{
if (indexes.Length == 1)
{
return (string)indexes[0];
}
// REVIEW: Should this throw?
return null;
}
public override IEnumerable<string> GetDynamicMemberNames()
{
return _values.Keys;
}
private object GetValue(string name)
{
object result;
if (_values.TryGetValue(name, out result))
{
return result;
}
return null;
}
}
[SuppressMessage("Microsoft.Naming", "CA1710:IdentifiersShouldHaveCorrectSuffix", Justification = "This class isn't meant to be used directly")]
public class DynamicJsonArray : DynamicObject, IEnumerable<object>
{
private readonly object[] _arrayValues;
public DynamicJsonArray(object[] arrayValues)
{
Debug.Assert(arrayValues != null);
_arrayValues = arrayValues.Select(Json.WrapObject).ToArray();
}
public int Length
{
get { return _arrayValues.Length; }
}
public dynamic this[int index]
{
get { return _arrayValues[index]; }
set { _arrayValues[index] = Json.WrapObject(value); }
}
public override bool TryConvert(ConvertBinder binder, out object result)
{
if (_arrayValues.GetType().IsAssignableFrom(binder.Type))
{
result = _arrayValues;
return true;
}
return base.TryConvert(binder, out result);
}
public override bool TryGetMember(GetMemberBinder binder, out object result)
{
// Testing for members should never throw. This is important when dealing with
// services that return different json results. Testing for a member shouldn't throw,
// it should just return null (or undefined)
result = null;
return true;
}
public IEnumerator GetEnumerator()
{
return _arrayValues.GetEnumerator();
}
private IEnumerable<object> GetEnumerable()
{
return _arrayValues.AsEnumerable();
}
IEnumerator<object> IEnumerable<object>.GetEnumerator()
{
return GetEnumerable().GetEnumerator();
}
[SuppressMessage("Microsoft.Usage", "CA2225:OperatorOverloadsHaveNamedAlternates", Justification = "This class isn't meant to be used directly")]
public static implicit operator object[](DynamicJsonArray obj)
{
return obj._arrayValues;
}
[SuppressMessage("Microsoft.Usage", "CA2225:OperatorOverloadsHaveNamedAlternates", Justification = "This class isn't meant to be used directly")]
public static implicit operator Array(DynamicJsonArray obj)
{
return obj._arrayValues;
}
}
/// <summary>
/// Helper to evaluate different method on dynamic objects
/// </summary>
public static class DynamicHelper
{
// We must pass in "object" instead of "dynamic" for the target dynamic object because if we use dynamic, the compiler will
// convert the call to this helper into a dynamic expression, even though we don't need it to be. Since this class is internal,
// it cannot be accessed from a dynamic expression and thus we get errors.
// Dev10 Bug 914027 - Changed the first parameter from dynamic to object, see comment at top for details
public static bool TryGetMemberValue(object obj, string memberName, out object result)
{
try
{
result = GetMemberValue(obj, memberName);
return true;
}
catch (RuntimeBinderException)
{
}
catch (RuntimeBinderInternalCompilerException)
{
}
// We catch the C# specific runtime binder exceptions since we're using the C# binder in this case
result = null;
return false;
}
// Dev10 Bug 914027 - Changed the first parameter from dynamic to object, see comment at top for details
[SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "We want to swallow exceptions that happen during runtime binding")]
public static bool TryGetMemberValue(object obj, GetMemberBinder binder, out object result)
{
try
{
// VB us an instance of GetBinderAdapter that does not implement FallbackGetMemeber. This causes lookup of property expressions on dynamic objects to fail.
// Since all types are private to the assembly, we assume that as long as they belong to CSharp runtime, it is the right one.
if (typeof(Binder).Assembly.Equals(binder.GetType().Assembly))
{
// Only use the binder if its a C# binder.
result = GetMemberValue(obj, binder);
}
else
{
result = GetMemberValue(obj, binder.Name);
}
return true;
}
catch
{
result = null;
return false;
}
}
// Dev10 Bug 914027 - Changed the first parameter from dynamic to object, see comment at top for details
public static object GetMemberValue(object obj, string memberName)
{
var callSite = GetMemberAccessCallSite(memberName);
return callSite.Target(callSite, obj);
}
// Dev10 Bug 914027 - Changed the first parameter from dynamic to object, see comment at top for details
public static object GetMemberValue(object obj, GetMemberBinder binder)
{
var callSite = GetMemberAccessCallSite(binder);
return callSite.Target(callSite, obj);
}
// dynamic d = new object();
// object s = d.Name;
// The following code gets generated for this expression:
// callSite = CallSite<Func<CallSite, object, object>>.Create(Binder.GetMember(CSharpBinderFlags.None, "Name", typeof(Program), new CSharpArgumentInfo[] { CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null) }));
// callSite.Target(callSite, d);
// typeof(Program) is the containing type of the dynamic operation.
// Dev10 Bug 914027 - Changed the callsite's target parameter from dynamic to object, see comment at top for details
public static CallSite<Func<CallSite, object, object>> GetMemberAccessCallSite(string memberName)
{
var binder = Binder.GetMember(CSharpBinderFlags.None, memberName, typeof(DynamicHelper), new[] { CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null) });
return GetMemberAccessCallSite(binder);
}
// Dev10 Bug 914027 - Changed the callsite's target parameter from dynamic to object, see comment at top for details
public static CallSite<Func<CallSite, object, object>> GetMemberAccessCallSite(CallSiteBinder binder)
{
return CallSite<Func<CallSite, object, object>>.Create(binder);
}
// Dev10 Bug 914027 - Changed the first parameter from dynamic to object, see comment at top for details
public static IEnumerable<string> GetMemberNames(object obj)
{
var provider = obj as IDynamicMetaObjectProvider;
Debug.Assert(provider != null, "obj doesn't implement IDynamicMetaObjectProvider");
Expression parameter = Expression.Parameter(typeof(object));
return provider.GetMetaObject(parameter).GetDynamicMemberNames();
}
}
}
Upvotes: 4
Reputation: 8449
I came here to find an answer for .NET Core, without any third-party or additional references. It works fine if you use ExpandoObject
with the standard JsonSerializer
class. Here is the example that worked for me:
using System.Text.Json;
using System.Dynamic;
dynamic json = JsonSerializer.Deserialize<ExpandoObject>(jsonText);
Console.WriteLine(json.name);
This code prints out the string value of a name
property that exists within the JSON text passed into the Deserialize
method. Voila - no additional libraries, no nothing. Just .NET core.
Edit: May have a problem for several levels of json with nested elements. Worked for a single-level flat object.
Upvotes: 46
Reputation: 205
what i needed was to return a json model with varying fields. My model is like this but it can change.
{
"employees":
[
{ "name": "Darth", "surname": "Vader", "age": "27", "department": "finance"},
{ "name": "Luke", "surname": "Skywalker", "age": "25", "department": "IT"},
{ "name": "Han", "surname": "Solo", "age": "26", "department": "credit"}
]
}
To get a list of data values
JObject array = JObject.Parse(model.JsonData);
var tableData = new List<JsonDynamicModel>();
foreach (var objx in array.Descendants().OfType<JProperty>().Where(p => p.Value.Type != JTokenType.Array && p.Value.Type != JTokenType.Object))
{
var name = ((JValue)objx.Name).Value;
var value = ((JValue)objx.Value).Value;
if (tableData.FirstOrDefault(x => x.ColumnName == name.ToString()) == null)
{
tableData.Add(new JsonDynamicModel
{
ColumnName = name.ToString(),
Values = new List<string> { value.ToString() },
});
}
else
{
tableData.FirstOrDefault(x=>x.ColumnName == name.ToString()).Values.Add(value.ToString());
}
}
The output will be as follows. Then I converted the resulting model into an html table, I used this method to create an html table
// output
tableData[0].ColumnName -> "name";
tableData[0].Values -> {"Darth", "Luke", "Han" }
tableData[1].ColumnName -> "surname";
tableData[1].Values -> {"Vader", "Skywalker", "Solo" }
...
Upvotes: 0
Reputation: 6330
With Cinchoo ETL - an open source library available to parse JSON into a dynamic object:
string json = @"{
""key1"": [
{
""action"": ""open"",
""timestamp"": ""2018-09-05 20:46:00"",
""url"": null,
""ip"": ""66.102.6.98""
}
]
}";
using (var p = ChoJSONReader.LoadText(json)
.WithJSONPath("$..key1")
)
{
foreach (var rec in p)
{
Console.WriteLine("Action: " + rec.action);
Console.WriteLine("Timestamp: " + rec.timestamp);
Console.WriteLine("URL: " + rec.url);
Console.WriteLine("IP address: " + rec.ip);
}
}
Output:
Action: open
Timestamp: 2018-09-05 20:46:00
URL: http://www.google.com
IP address: 66.102.6.98
Sample fiddle: https://dotnetfiddle.net/S0ehSV
For more information, please visit codeproject articles
Disclaimer: I'm the author of this library.
Upvotes: 3
Reputation: 2381
You can achieve that with the help of Newtonsoft.Json. Install it from NuGet and then:
using Newtonsoft.Json;
dynamic results = JsonConvert.DeserializeObject<dynamic>(YOUR_JSON);
Upvotes: 48
Reputation: 1862
try this way!
JSON example:
[{
"id": 140,
"group": 1,
"text": "xxx",
"creation_date": 123456,
"created_by": "[email protected]",
"tags": ["xxxxx"]
}, {
"id": 141,
"group": 1,
"text": "xxxx",
"creation_date": 123456,
"created_by": "[email protected]",
"tags": ["xxxxx"]
}]
C# code:
var jsonString = (File.ReadAllText(Path.Combine(Directory.GetCurrentDirectory(),"delete_result.json")));
var objects = JsonConvert.DeserializeObject<dynamic>(jsonString);
foreach(var o in objects)
{
Console.WriteLine($"{o.id.ToString()}");
}
Upvotes: 2
Reputation: 982
I want to do this programmatically in unit tests, I do have the luxury of typing it out.
My solution is:
var dict = JsonConvert.DeserializeObject<ExpandoObject>(json) as IDictionary<string, object>;
Now I can assert that
dict.ContainsKey("ExpectedProperty");
Upvotes: 6
Reputation: 178
Creating dynamic objects with Newtonsoft.Json works really great.
//json is your string containing the JSON value
dynamic data = JsonConvert.DeserializeObject<dynamic>(json);
Now you can access the data
object just like if it was a regular object. This is the JSON object we currently have as an example:
{ "ID":123,"Name":"Jack","Numbers":[1, 2, 3] }
This is how you access it after deserialization:
data.ID //Retrieve the int
data.Name //Retrieve the string
data.Numbers[0] //Retrieve the first element in the array
Upvotes: 14
Reputation: 311315
If you are happy to have a dependency upon the System.Web.Helpers
assembly, then you can use the Json
class:
dynamic data = Json.Decode(json);
It is included with the MVC framework as an additional download to the .NET 4 framework. Be sure to give Vlad an upvote if that's helpful! However if you cannot assume the client environment includes this DLL, then read on.
An alternative deserialisation approach is suggested here. I modified the code slightly to fix a bug and suit my coding style. All you need is this code and a reference to System.Web.Extensions
from your project:
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Dynamic;
using System.Linq;
using System.Text;
using System.Web.Script.Serialization;
public sealed class DynamicJsonConverter : JavaScriptConverter
{
public override object Deserialize(IDictionary<string, object> dictionary, Type type, JavaScriptSerializer serializer)
{
if (dictionary == null)
throw new ArgumentNullException("dictionary");
return type == typeof(object) ? new DynamicJsonObject(dictionary) : null;
}
public override IDictionary<string, object> Serialize(object obj, JavaScriptSerializer serializer)
{
throw new NotImplementedException();
}
public override IEnumerable<Type> SupportedTypes
{
get { return new ReadOnlyCollection<Type>(new List<Type>(new[] { typeof(object) })); }
}
#region Nested type: DynamicJsonObject
private sealed class DynamicJsonObject : DynamicObject
{
private readonly IDictionary<string, object> _dictionary;
public DynamicJsonObject(IDictionary<string, object> dictionary)
{
if (dictionary == null)
throw new ArgumentNullException("dictionary");
_dictionary = dictionary;
}
public override string ToString()
{
var sb = new StringBuilder("{");
ToString(sb);
return sb.ToString();
}
private void ToString(StringBuilder sb)
{
var firstInDictionary = true;
foreach (var pair in _dictionary)
{
if (!firstInDictionary)
sb.Append(",");
firstInDictionary = false;
var value = pair.Value;
var name = pair.Key;
if (value is string)
{
sb.AppendFormat("{0}:\"{1}\"", name, value);
}
else if (value is IDictionary<string, object>)
{
new DynamicJsonObject((IDictionary<string, object>)value).ToString(sb);
}
else if (value is ArrayList)
{
sb.Append(name + ":[");
var firstInArray = true;
foreach (var arrayValue in (ArrayList)value)
{
if (!firstInArray)
sb.Append(",");
firstInArray = false;
if (arrayValue is IDictionary<string, object>)
new DynamicJsonObject((IDictionary<string, object>)arrayValue).ToString(sb);
else if (arrayValue is string)
sb.AppendFormat("\"{0}\"", arrayValue);
else
sb.AppendFormat("{0}", arrayValue);
}
sb.Append("]");
}
else
{
sb.AppendFormat("{0}:{1}", name, value);
}
}
sb.Append("}");
}
public override bool TryGetMember(GetMemberBinder binder, out object result)
{
if (!_dictionary.TryGetValue(binder.Name, out result))
{
// return null to avoid exception. caller can check for null this way...
result = null;
return true;
}
result = WrapResultObject(result);
return true;
}
public override bool TryGetIndex(GetIndexBinder binder, object[] indexes, out object result)
{
if (indexes.Length == 1 && indexes[0] != null)
{
if (!_dictionary.TryGetValue(indexes[0].ToString(), out result))
{
// return null to avoid exception. caller can check for null this way...
result = null;
return true;
}
result = WrapResultObject(result);
return true;
}
return base.TryGetIndex(binder, indexes, out result);
}
private static object WrapResultObject(object result)
{
var dictionary = result as IDictionary<string, object>;
if (dictionary != null)
return new DynamicJsonObject(dictionary);
var arrayList = result as ArrayList;
if (arrayList != null && arrayList.Count > 0)
{
return arrayList[0] is IDictionary<string, object>
? new List<object>(arrayList.Cast<IDictionary<string, object>>().Select(x => new DynamicJsonObject(x)))
: new List<object>(arrayList.Cast<object>());
}
return result;
}
}
#endregion
}
You can use it like this:
string json = ...;
var serializer = new JavaScriptSerializer();
serializer.RegisterConverters(new[] { new DynamicJsonConverter() });
dynamic obj = serializer.Deserialize(json, typeof(object));
So, given a JSON string:
{
"Items":[
{ "Name":"Apple", "Price":12.3 },
{ "Name":"Grape", "Price":3.21 }
],
"Date":"21/11/2010"
}
The following code will work at runtime:
dynamic data = serializer.Deserialize(json, typeof(object));
data.Date; // "21/11/2010"
data.Items.Count; // 2
data.Items[0].Name; // "Apple"
data.Items[0].Price; // 12.3 (as a decimal)
data.Items[1].Name; // "Grape"
data.Items[1].Price; // 3.21 (as a decimal)
Upvotes: 739
Reputation: 684
Please add reference of System.Web.Extensions and add this namespace using System.Web.Script.Serialization;
at top:
public static void EasyJson()
{
var jsonText = @"{
""some_number"": 108.541,
""date_time"": ""2011-04-13T15:34:09Z"",
""serial_number"": ""SN1234""
}";
var jss = new JavaScriptSerializer();
var dict = jss.Deserialize<dynamic>(jsonText);
Console.WriteLine(dict["some_number"]);
Console.ReadLine();
}
Please add reference of System.Web.Extensions and add this namespace using System.Web.Script.Serialization;
at top:
public static void ComplexJson()
{
var jsonText = @"{
""some_number"": 108.541,
""date_time"": ""2011-04-13T15:34:09Z"",
""serial_number"": ""SN1234"",
""more_data"": {
""field1"": 1.0,
""field2"": ""hello""
}
}";
var jss = new JavaScriptSerializer();
var dict = jss.Deserialize<dynamic>(jsonText);
Console.WriteLine(dict["some_number"]);
Console.WriteLine(dict["more_data"]["field2"]);
Console.ReadLine();
}
Upvotes: 4
Reputation: 716
Another option is to "Paste JSON as classes" so it can be deserialised quick and easy.
Here is a better explanation n piccas... ‘Paste JSON As Classes’ in ASP.NET and Web Tools 2012.2 RC
Upvotes: 8
Reputation: 461
I use http://json2csharp.com/ to get a class representing the JSON object.
Input:
{
"name":"John",
"age":31,
"city":"New York",
"Childs":[
{
"name":"Jim",
"age":11
},
{
"name":"Tim",
"age":9
}
]
}
Output:
public class Child
{
public string name { get; set; }
public int age { get; set; }
}
public class Person
{
public string name { get; set; }
public int age { get; set; }
public string city { get; set; }
public List<Child> Childs { get; set; }
}
After that I use Newtonsoft.Json to fill the class:
using Newtonsoft.Json;
namespace GitRepositoryCreator.Common
{
class JObjects
{
public static string Get(object p_object)
{
return JsonConvert.SerializeObject(p_object);
}
internal static T Get<T>(string p_object)
{
return JsonConvert.DeserializeObject<T>(p_object);
}
}
}
You can call it like this:
Person jsonClass = JObjects.Get<Person>(stringJson);
string stringJson = JObjects.Get(jsonClass);
PS:
If your JSON variable name is not a valid C# name (name starts with $
) you can fix that like this:
public class Exception
{
[JsonProperty(PropertyName = "$id")]
public string id { get; set; }
public object innerException { get; set; }
public string message { get; set; }
public string typeName { get; set; }
public string typeKey { get; set; }
public int errorCode { get; set; }
public int eventId { get; set; }
}
Upvotes: 12
Reputation: 182
Try this:
var units = new { Name = "Phone", Color= "White" };
var jsonResponse = JsonConvert.DeserializeAnonymousType(json, units);
Upvotes: 6
Reputation: 6459
Use DataSet(C#) with JavaScript. A simple function for creating a JSON stream with DataSet input. Create JSON content like (multi table dataset):
[[{a:1,b:2,c:3},{a:3,b:5,c:6}],[{a:23,b:45,c:35},{a:58,b:59,c:45}]]
Just client side, use eval. For example,
var d = eval('[[{a:1,b:2,c:3},{a:3,b:5,c:6}],[{a:23,b:45,c:35},{a:58,b:59,c:45}]]')
Then use:
d[0][0].a // out 1 from table 0 row 0
d[1][1].b // out 59 from table 1 row 1
// Created by Behnam Mohammadi And Saeed Ahmadian
public string jsonMini(DataSet ds)
{
int t = 0, r = 0, c = 0;
string stream = "[";
for (t = 0; t < ds.Tables.Count; t++)
{
stream += "[";
for (r = 0; r < ds.Tables[t].Rows.Count; r++)
{
stream += "{";
for (c = 0; c < ds.Tables[t].Columns.Count; c++)
{
stream += ds.Tables[t].Columns[c].ToString() + ":'" +
ds.Tables[t].Rows[r][c].ToString() + "',";
}
if (c>0)
stream = stream.Substring(0, stream.Length - 1);
stream += "},";
}
if (r>0)
stream = stream.Substring(0, stream.Length - 1);
stream += "],";
}
if (t>0)
stream = stream.Substring(0, stream.Length - 1);
stream += "];";
return stream;
}
Upvotes: 4
Reputation: 1524
The simplest way is:
Just include this DLL file.
Use the code like this:
dynamic json = new JDynamic("{a:'abc'}");
// json.a is a string "abc"
dynamic json = new JDynamic("{a:3.1416}");
// json.a is 3.1416m
dynamic json = new JDynamic("{a:1}");
// json.a is
dynamic json = new JDynamic("[1,2,3]");
/json.Length/json.Count is 3
// And you can use json[0]/ json[2] to get the elements
dynamic json = new JDynamic("{a:[1,2,3]}");
//json.a.Length /json.a.Count is 3.
// And you can use json.a[0]/ json.a[2] to get the elements
dynamic json = new JDynamic("[{b:1},{c:1}]");
// json.Length/json.Count is 2.
// And you can use the json[0].b/json[1].c to get the num.
Upvotes: 8
Reputation: 3202
Simple "string JSON data" to object without any third-party DLL file:
WebClient client = new WebClient();
string getString = client.DownloadString("https://graph.facebook.com/zuck");
JavaScriptSerializer serializer = new JavaScriptSerializer();
dynamic item = serializer.Deserialize<object>(getString);
string name = item["name"];
//note: JavaScriptSerializer in this namespaces
//System.Web.Script.Serialization.JavaScriptSerializer
Note: You can also using your custom object.
Personel item = serializer.Deserialize<Personel>(getString);
Upvotes: 91
Reputation: 7781
It's pretty simple using Json.NET:
dynamic stuff = JsonConvert.DeserializeObject("{ 'Name': 'Jon Smith', 'Address': { 'City': 'New York', 'State': 'NY' }, 'Age': 42 }");
string name = stuff.Name;
string address = stuff.Address.City;
Also using Newtonsoft.Json.Linq
:
dynamic stuff = JObject.Parse("{ 'Name': 'Jon Smith', 'Address': { 'City': 'New York', 'State': 'NY' }, 'Age': 42 }");
string name = stuff.Name;
string address = stuff.Address.City;
Documentation: Querying JSON with dynamic
Upvotes: 766
Reputation: 4032
.NET 4.0 has a built-in library to do this:
using System.Web.Script.Serialization;
JavaScriptSerializer jss = new JavaScriptSerializer();
var d = jss.Deserialize<dynamic>(str);
This is the simplest way.
Upvotes: 89
Reputation: 201
I made a new version of the DynamicJsonConverter that uses Expando Objects. I used expando objects, because I wanted to Serialize the dynamic back into JSON using Json.NET.
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Dynamic;
using System.Web.Script.Serialization;
public static class DynamicJson
{
public static dynamic Parse(string json)
{
JavaScriptSerializer jss = new JavaScriptSerializer();
jss.RegisterConverters(new JavaScriptConverter[] { new DynamicJsonConverter() });
dynamic glossaryEntry = jss.Deserialize(json, typeof(object)) as dynamic;
return glossaryEntry;
}
class DynamicJsonConverter : JavaScriptConverter
{
public override object Deserialize(IDictionary<string, object> dictionary, Type type, JavaScriptSerializer serializer)
{
if (dictionary == null)
throw new ArgumentNullException("dictionary");
var result = ToExpando(dictionary);
return type == typeof(object) ? result : null;
}
private static ExpandoObject ToExpando(IDictionary<string, object> dictionary)
{
var result = new ExpandoObject();
var dic = result as IDictionary<String, object>;
foreach (var item in dictionary)
{
var valueAsDic = item.Value as IDictionary<string, object>;
if (valueAsDic != null)
{
dic.Add(item.Key, ToExpando(valueAsDic));
continue;
}
var arrayList = item.Value as ArrayList;
if (arrayList != null && arrayList.Count > 0)
{
dic.Add(item.Key, ToExpando(arrayList));
continue;
}
dic.Add(item.Key, item.Value);
}
return result;
}
private static ArrayList ToExpando(ArrayList obj)
{
ArrayList result = new ArrayList();
foreach (var item in obj)
{
var valueAsDic = item as IDictionary<string, object>;
if (valueAsDic != null)
{
result.Add(ToExpando(valueAsDic));
continue;
}
var arrayList = item as ArrayList;
if (arrayList != null && arrayList.Count > 0)
{
result.Add(ToExpando(arrayList));
continue;
}
result.Add(item);
}
return result;
}
public override IDictionary<string, object> Serialize(object obj, JavaScriptSerializer serializer)
{
throw new NotImplementedException();
}
public override IEnumerable<Type> SupportedTypes
{
get { return new ReadOnlyCollection<Type>(new List<Type>(new[] { typeof(object) })); }
}
}
}
Upvotes: 20
Reputation: 7794
There is a lightweight JSON library for C# called SimpleJson.
It supports .NET 3.5+, Silverlight and Windows Phone 7.
It supports dynamic for .NET 4.0
It can also be installed as a NuGet package
Install-Package SimpleJson
Upvotes: 4
Reputation: 31809
JsonFx can deserialize JSON content into dynamic objects.
Serialize to/from dynamic types (default for .NET 4.0):
var reader = new JsonReader(); var writer = new JsonWriter();
string input = @"{ ""foo"": true, ""array"": [ 42, false, ""Hello!"", null ] }";
dynamic output = reader.Read(input);
Console.WriteLine(output.array[0]); // 42
string json = writer.Write(output);
Console.WriteLine(json); // {"foo":true,"array":[42,false,"Hello!",null]}
Upvotes: 30
Reputation: 922
The object you want DynamicJSONObject is included in the System.Web.Helpers.dll from the ASP.NET Web Pages package, which is part of WebMatrix.
Upvotes: 4
Reputation: 1565
You can use using Newtonsoft.Json
var jRoot =
JsonConvert.DeserializeObject<dynamic>(Encoding.UTF8.GetString(resolvedEvent.Event.Data));
resolvedEvent.Event.Data
is my response getting from calling core Event .
Upvotes: 6
Reputation: 25940
Look at the article I wrote on CodeProject, one that answers the question precisely:
There is way too much for re-posting it all here, and even less point since that article has an attachment with the key/required source file.
Upvotes: 5
Reputation: 4542
I am using like this in my code and it's working fine
using System.Web.Script.Serialization;
JavaScriptSerializer oJS = new JavaScriptSerializer();
RootObject oRootObject = new RootObject();
oRootObject = oJS.Deserialize<RootObject>(Your JSon String);
Upvotes: 5
Reputation: 4021
Deserializing in JSON.NET can be dynamic using the JObject
class, which is included in that library. My JSON string represents these classes:
public class Foo {
public int Age {get;set;}
public Bar Bar {get;set;}
}
public class Bar {
public DateTime BDay {get;set;}
}
Now we deserialize the string WITHOUT referencing the above classes:
var dyn = JsonConvert.DeserializeObject<JObject>(jsonAsFooString);
JProperty propAge = dyn.Properties().FirstOrDefault(i=>i.Name == "Age");
if(propAge != null) {
int age = int.Parse(propAge.Value.ToString());
Console.WriteLine("age=" + age);
}
//or as a one-liner:
int myage = int.Parse(dyn.Properties().First(i=>i.Name == "Age").Value.ToString());
Or if you want to go deeper:
var propBar = dyn.Properties().FirstOrDefault(i=>i.Name == "Bar");
if(propBar != null) {
JObject o = (JObject)propBar.First();
var propBDay = o.Properties().FirstOrDefault (i => i.Name=="BDay");
if(propBDay != null) {
DateTime bday = DateTime.Parse(propBDay.Value.ToString());
Console.WriteLine("birthday=" + bday.ToString("MM/dd/yyyy"));
}
}
//or as a one-liner:
DateTime mybday = DateTime.Parse(((JObject)dyn.Properties().First(i=>i.Name == "Bar").First()).Properties().First(i=>i.Name == "BDay").Value.ToString());
See post for a complete example.
Upvotes: 5
Reputation: 1728
To get an ExpandoObject:
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
Container container = JsonConvert.Deserialize<Container>(jsonAsString, new ExpandoObjectConverter());
Upvotes: 4
Reputation: 8221
You can do this using System.Web.Helpers.Json - its Decode method returns a dynamic object which you can traverse as you like.
It's included in the System.Web.Helpers assembly (.NET 4.0).
var dynamicObject = Json.Decode(jsonString);
Upvotes: 312
Reputation: 1031
Another way using Newtonsoft.Json:
dynamic stuff = Newtonsoft.Json.JsonConvert.DeserializeObject("{ color: 'red', value: 5 }");
string color = stuff.color;
int value = stuff.value;
Upvotes: 26
Reputation: 111
You can extend the JavaScriptSerializer to recursively copy the dictionary it created to expando object(s) and then use them dynamically:
static class JavaScriptSerializerExtensions
{
public static dynamic DeserializeDynamic(this JavaScriptSerializer serializer, string value)
{
var dictionary = serializer.Deserialize<IDictionary<string, object>>(value);
return GetExpando(dictionary);
}
private static ExpandoObject GetExpando(IDictionary<string, object> dictionary)
{
var expando = (IDictionary<string, object>)new ExpandoObject();
foreach (var item in dictionary)
{
var innerDictionary = item.Value as IDictionary<string, object>;
if (innerDictionary != null)
{
expando.Add(item.Key, GetExpando(innerDictionary));
}
else
{
expando.Add(item.Key, item.Value);
}
}
return (ExpandoObject)expando;
}
}
Then you just need to having a using statement for the namespace you defined the extension in (consider just defining them in System.Web.Script.Serialization... another trick is to not use a namespace, then you don't need the using statement at all) and you can consume them like so:
var serializer = new JavaScriptSerializer();
var value = serializer.DeserializeDynamic("{ 'Name': 'Jon Smith', 'Address': { 'City': 'New York', 'State': 'NY' }, 'Age': 42 }");
var name = (string)value.Name; // Jon Smith
var age = (int)value.Age; // 42
var address = value.Address;
var city = (string)address.City; // New York
var state = (string)address.State; // NY
Upvotes: 6