JSON.NET deserialize a specific property - c#

I have the following JSON text:
{
"PropOne": {
"Text": "Data"
}
"PropTwo": "Data2"
}
I want to deserialize PropOne into type PropOneClass without the overhead of deserializing any other properties on the object. Can this be done using JSON.NET?

The JSON isn't too large, so I'll take Matt Johnson's suggestion and deserialize the whole thing. Thanks to jcwrequests answer, I was able to use this method:
var jObject = JObject.Parse(json);
var jToken = jObject.GetValue("PropTwo");
PropTwoClass value = jToken.ToObject(typeof(PropTwoClass));

public T GetFirstInstance<T>(string propertyName, string json)
{
using (var stringReader = new StringReader(json))
using (var jsonReader = new JsonTextReader(stringReader))
{
while (jsonReader.Read())
{
if (jsonReader.TokenType == JsonToken.PropertyName
&& (string)jsonReader.Value == propertyName)
{
jsonReader.Read();
var serializer = new JsonSerializer();
return serializer.Deserialize<T>(jsonReader);
}
}
return default(T);
}
}
public class MyType
{
public string Text { get; set; }
}
public void Test()
{
string json = "{ \"PropOne\": { \"Text\": \"Data\" }, \"PropTwo\": \"Data2\" }";
MyType myType = GetFirstInstance<MyType>("PropOne", json);
Debug.WriteLine(myType.Text); // "Data"
}
This approach avoids having to deserialize the entire object. But note that this will only improve performance if the json is significantly large, and the property you are deserializing is relatively early in the data. Otherwise, you should just deserialize the whole thing and pull out the parts you want, like jcwrequests answer shows.

A simpler solution to Omar's answer would be to have a wrapper.
class Wrapper
{
public PropOneClass PropOne;
}
JsonConvert.Deserialize<Wrapper>(json).PropOne
My tests found it to be about 30% faster.

var json = "{ "PropOne": { "Text": "Data" } "PropTwo": "Data2" }";
JObject o = JObject.Parse(json);
var val = o.PropTwo;
Using JSON Linq provider you do not need to deserialize the object into a known type.

Matt's answer is by far the fastest solution though it has a bug.
This is my attempt in fixing that.
This method will only return a matching property at the root level.
There is still a naive approach in counting start and end tokens though for valid JSON it will probably work.
Matt, feel free to copy this into your answer.
public T GetFirstInstance<T>(string propertyName, string json)
{
using (var stringReader = new StringReader(json))
using (var jsonReader = new JsonTextReader(stringReader))
{
int level = 0;
while (jsonReader.Read())
{
switch (jsonReader.TokenType)
{
case JsonToken.PropertyName:
if (level != 1)
break;
if ((string)jsonReader.Value == propertyName)
{
jsonReader.Read();
return (T)jsonReader.Value;
}
break;
case JsonToken.StartArray:
case JsonToken.StartConstructor:
case JsonToken.StartObject:
level++;
break;
case JsonToken.EndArray:
case JsonToken.EndConstructor:
case JsonToken.EndObject:
level--;
break;
}
}
return default(T);
}
}

Use JsonIgnore - this will cause the property to be completely ignored by Json.Net, both for serializing and deserializing.
Also, check this link.

Related

Accepting raw JSON Asp.net core

I have a asp.net core method, I want it to accept RAW json, I do not and will not always know the schema of the json object, so I am using dynamic types with dot notation.
This method works when I string the json escaping each character. I have tried to use the json body directly, but this did not work. So it seems my option were to Serialize and then Deserialize the json. ( very redundant) but it seems to throw error any other way if I try to use the JSON body directly.
In the debugger, everything seems to work with the Serialize and Deserialize of the object / string, but throws an error on the id(property) when I try to cast the object to string and gives the error. (In the debugger I am able to see the Id correctly though).
({Microsoft.CSharp.RuntimeBinder.RuntimeBinderException: Cannot convert type 'System.Text.Json.JsonElement' to 'string')}
I really do not see why it gives the type as a string yet cannot convert it. I have even tried to remove the casting, and still receive this error.
public IActionResult Post([FromBody] ExpandoObject requestInput)
{
try
{
//Makes a JSON String
var stringObject = (string) JsonSerializer.Serialize(requestInput);
DateTime time = DateTime.UtcNow;
// Recreated the Json Object
dynamic requestObject = JsonSerializer.Deserialize<ExpandoObject>(stringObject);
// Throws Error here, yet it shows Value as the correct Id number (Value: Type String)
string reqObject = (string) requestObject.Id;
So there is no support for ExpandoObject in .NET Core, yet. MS says that maybe it will be added in .NET 5.0. Until then, you can use this JsonConverter I found on a thread. I will post the code here in case that thread goes away.
You can use it like this:
[HttpPost, Route("testPost")]
public IActionResult TestPost([FromBody] object obj) // just use "object"
{
// object is: { "hello":"world" }
var myDynamic = JsonSerializer.Deserialize<dynamic>(
JsonSerializer.Serialize(obj), new JsonSerializerOptions
{
Converters = { new DynamicJsonConverter() }
});
var test = (string)myDynamic.hello;
// test will equal "world"
return Ok();
}
Here is the converter:
/// <summary>
/// Temp Dynamic Converter
/// by:tchivs#live.cn
/// </summary>
public class DynamicJsonConverter : JsonConverter<dynamic>
{
public override dynamic Read(ref Utf8JsonReader reader,
Type typeToConvert,
JsonSerializerOptions options)
{
if (reader.TokenType == JsonTokenType.True)
{
return true;
}
if (reader.TokenType == JsonTokenType.False)
{
return false;
}
if (reader.TokenType == JsonTokenType.Number)
{
if (reader.TryGetInt64(out long l))
{
return l;
}
return reader.GetDouble();
}
if (reader.TokenType == JsonTokenType.String)
{
if (reader.TryGetDateTime(out DateTime datetime))
{
return datetime;
}
return reader.GetString();
}
if (reader.TokenType == JsonTokenType.StartObject)
{
using JsonDocument documentV = JsonDocument.ParseValue(ref reader);
return ReadObject(documentV.RootElement);
}
// Use JsonElement as fallback.
// Newtonsoft uses JArray or JObject.
JsonDocument document = JsonDocument.ParseValue(ref reader);
return document.RootElement.Clone();
}
private object ReadObject(JsonElement jsonElement)
{
IDictionary<string, object> expandoObject = new ExpandoObject();
foreach (var obj in jsonElement.EnumerateObject())
{
var k = obj.Name;
var value = ReadValue(obj.Value);
expandoObject[k] = value;
}
return expandoObject;
}
private object? ReadValue(JsonElement jsonElement)
{
object? result = null;
switch (jsonElement.ValueKind)
{
case JsonValueKind.Object:
result = ReadObject(jsonElement);
break;
case JsonValueKind.Array:
result = ReadList(jsonElement);
break;
case JsonValueKind.String:
//TODO: Missing Datetime&Bytes Convert
result = jsonElement.GetString();
break;
case JsonValueKind.Number:
//TODO: more num type
result = 0;
if (jsonElement.TryGetInt64(out long l))
{
result = l;
}
break;
case JsonValueKind.True:
result = true;
break;
case JsonValueKind.False:
result = false;
break;
case JsonValueKind.Undefined:
case JsonValueKind.Null:
result = null;
break;
default:
throw new ArgumentOutOfRangeException();
}
return result;
}
private object? ReadList(JsonElement jsonElement)
{
IList<object?> list = new List<object?>();
foreach (var item in jsonElement.EnumerateArray())
{
list.Add(ReadValue(item));
}
return list.Count == 0 ? null : list;
}
public override void Write(Utf8JsonWriter writer,
object value,
JsonSerializerOptions options)
{
// writer.WriteStringValue(value.ToString());
}
}
Edited To Add:
Here is a much slicker way to handle dynamic using the converter above as pointed out by Aluan in the comments. In your Startup.cs class, add this:
services.AddControllers().AddJsonOptions(options =>
options.JsonSerializerOptions.Converters.Add(new DynamicJsonConverter()));
Then you don't have to do any goofy stuff in your controller. You can just set the body parameter as dynamic and it magically works:
[HttpPost, Route("testPost")]
public IActionResult TestPost([FromBody] dynamic obj)
{
// object is: { "hello":"world" }
var test = (string)obj.hello;
// test will equal "world"
return Ok();
}
Way nicer!

How do you read a simple value out of some json using System.Text.Json?

I have this json
{"id":"48e86841-f62c-42c9-ae20-b54ba8c35d6d"}
How do I get the 48e86841-f62c-42c9-ae20-b54ba8c35d6d out of it? All examples I can find show to do something like
var o = System.Text.Json.JsonSerializer.Deserialize<some-type>(json);
o.id // <- here's the ID!
But I don't have a type that fits this definition and I don't want to create one. I've tried deserializing to dynamic but I was unable to get that working.
var result = System.Text.Json.JsonSerializer.Deserialize<dynamic>(json);
result.id // <-- An exception of type 'Microsoft.CSharp.RuntimeBinder.RuntimeBinderException' occurred in System.Linq.Expressions.dll but was not handled in user code: ''System.Text.Json.JsonElement' does not contain a definition for 'id''
Can anyone give any suggestions?
edit:
I just figured out I can do this:
Guid id = System.Text.Json.JsonDocument.Parse(json).RootElement.GetProperty("id").GetGuid();
This does work - but is there a better way?
you can deserialize to a Dictionary:
var dict = System.Text.Json.JsonSerializer.Deserialize<Dictionary<string, string>>(json)
Or just deserialize to Object which will yield a JsonElement that you can call GetProperty on.
Support for JsonObject has been added in .NET 6 using System.Text.Json.Nodes.
Example:
const string Json = "{\"MyNumber\":42, \"MyArray\":[10,11]}";
// dynamic
{
dynamic obj = JsonNode.Parse(Json);
int number = (int)obj["MyNumber"];
Debug.Assert(number == 42);
obj["MyString"] = "Hello";
Debug.Assert((string)obj["MyString"] == "Hello");
}
// JsonObject
{
JsonObject obj = JsonNode.Parse(Json).AsObject();
int number = (int)obj["MyNumber"];
Debug.Assert(number == 42);
obj["MyString"] = "Hello";
Debug.Assert((string)obj["MyString"] == "Hello");
}
Sources:
https://github.com/dotnet/runtime/issues/53195
https://github.com/dotnet/runtime/issues/45188
I've recently migrated a project from ASP.NET Core 2.2 to 3, and I'm having this inconvenience. In our team we value lean dependencies, so we are trying to avoid including Newtonsoft.JSON back and try using System.Text.Json. We also decided not to use a ton of POCO objects just for JSON serialization, because our backend models are more complex than needed for Web APIs. Also, because of nontrivial behaviour encapsulation, the backend models cannot be easily used to serialize/deserialize JSON strings.
I understand that System.Text.Json is supposed to be faster than Newtonsoft.JSON, but I believe this has a lot to do with ser/deser from/to specific POCO classes. Anyway, speed was not on our list of pros/cons for this decision, so YMMV.
Long story short, for the time being I wrote a small dynamic object wrapper that unpacks the JsonElements from System.Text.Json and tries to convert/cast as best as possible. The typical usage is to read the request body as a dynamic object. Again, I'm pretty sure this approach kills any speed gains, but that was not a concern for our use case.
This is the class:
public class ReflectionDynamicObject : DynamicObject {
public JsonElement RealObject { get; set; }
public override bool TryGetMember (GetMemberBinder binder, out object result) {
// Get the property value
var srcData = RealObject.GetProperty (binder.Name);
result = null;
switch (srcData.ValueKind) {
case JsonValueKind.Null:
result = null;
break;
case JsonValueKind.Number:
result = srcData.GetDouble ();
break;
case JsonValueKind.False:
result = false;
break;
case JsonValueKind.True:
result = true;
break;
case JsonValueKind.Undefined:
result = null;
break;
case JsonValueKind.String:
result = srcData.GetString ();
break;
case JsonValueKind.Object:
result = new ReflectionDynamicObject {
RealObject = srcData
};
break;
case JsonValueKind.Array:
result = srcData.EnumerateArray ()
.Select (o => new ReflectionDynamicObject { RealObject = o })
.ToArray ();
break;
}
// Always return true; other exceptions may have already been thrown if needed
return true;
}
}
and this is an example usage, to parse the request body - one part is in a base class for all my WebAPI controllers, that exposes the body as a dynamic object:
[ApiController]
public class WebControllerBase : Controller {
// Other stuff - omitted
protected async Task<dynamic> JsonBody () {
var result = await JsonDocument.ParseAsync (Request.Body);
return new ReflectionDynamicObject {
RealObject = result.RootElement
};
}
}
and can be used in the actual controller like this:
//[...]
[HttpPost ("")]
public async Task<ActionResult> Post () {
var body = await JsonBody ();
var name = (string) body.Name;
//[...]
}
//[...]
If needed, you can integrate parsing for GUIDs or other specific data types as needed - while we all wait for some official / framework-sanctioned solution.
Actual way to parse string in System.Text.Json (.NET Core 3+)
var jsonStr = "{\"id\":\"48e86841-f62c-42c9-ae20-b54ba8c35d6d\"}";
using var doc = JsonDocument.Parse(jsonStr);
var root = doc.RootElement;
var id = root.GetProperty("id").GetGuid();
You can use the following extension method to query data like "xpath"
public static string? JsonQueryXPath(this string value, string xpath, JsonSerializerOptions? options = null) => value.Deserialize<JsonElement>(options).GetJsonElement(xpath).GetJsonElementValue();
public static JsonElement GetJsonElement(this JsonElement jsonElement, string xpath)
{
if (jsonElement.ValueKind is JsonValueKind.Null or JsonValueKind.Undefined)
return default;
string[] segments = xpath.Split(new[] {'.'}, StringSplitOptions.RemoveEmptyEntries);
foreach (var segment in segments)
{
if (int.TryParse(segment, out var index) && jsonElement.ValueKind == JsonValueKind.Array)
{
jsonElement = jsonElement.EnumerateArray().ElementAtOrDefault(index);
if (jsonElement.ValueKind is JsonValueKind.Null or JsonValueKind.Undefined)
return default;
continue;
}
jsonElement = jsonElement.TryGetProperty(segment, out var value) ? value : default;
if (jsonElement.ValueKind is JsonValueKind.Null or JsonValueKind.Undefined)
return default;
}
return jsonElement;
}
public static string? GetJsonElementValue(this JsonElement jsonElement) => jsonElement.ValueKind != JsonValueKind.Null &&
jsonElement.ValueKind != JsonValueKind.Undefined
? jsonElement.ToString()
: default;
Simple to use as follows
string raw = #"{
""data"": {
""products"": {
""edges"": [
{
""node"": {
""id"": ""gid://shopify/Product/4534543543316"",
""featuredImage"": {
""originalSrc"": ""https://cdn.shopify.com/s/files/1/0286/pic.jpg"",
""id"": ""gid://shopify/ProductImage/146345345339732""
}
}
},
{
""node"": {
""id"": ""gid://shopify/Product/123456789"",
""featuredImage"": {
""originalSrc"": ""https://cdn.shopify.com/s/files/1/0286/pic.jpg"",
""id"": [
""gid://shopify/ProductImage/123456789"",
""gid://shopify/ProductImage/666666666""
]
},
""1"": {
""name"": ""Tuanh""
}
}
}
]
}
}
}";
System.Console.WriteLine(raw2.QueryJsonXPath("data.products.edges.0.node.featuredImage.id"));
I wrote an extension method for this purpose. You can safely use as following:
var jsonElement = JsonSerializer.Deserialize<JsonElement>(json);
var guid = jsonElement.TryGetValue<Guid>("id");
This is the extension class.
public static class JsonElementExtensions
{
private static readonly JsonSerializerOptions options = new() { PropertyNameCaseInsensitive = true };
public static T? TryGetValue<T>(this JsonElement element, string propertyName)
{
if (element.ValueKind != JsonValueKind.Object)
{
return default;
}
element.TryGetProperty(propertyName, out JsonElement property);
if (property.ValueKind == JsonValueKind.Undefined ||
property.ValueKind == JsonValueKind.Null)
{
return default;
}
try
{
return property.Deserialize<T>(options);
}
catch (JsonException)
{
return default;
}
}
}
Reason
The reason behind using this extension instead of JsonNode class is because if you need a Controller method accepts just an object without exposing it's model class Asp.Net Core model binding uses JsonElement struct to map the json string. At this point (as far as I know) there is no simple way to convert the JsonElement to JsonNode and when your object can be anything the JsonElement methods will throw exceptions for undefined fields while JsonNode don't.
[HttpPost]
public IActionResult Post(object setupObject)
{
var setup = (JsonElement)setupObject;
var id = setup.TryGetValue<Guid>("id");
var user = setup.TryGetValue<User?>("user");
var account = setup.TryGetValue<Account?>("account");
var payments = setup.TryGetValue<IEnumerable<Payments>?>("payments");
// ...
return Ok();
}
update to .NET Core 3.1 to support
public static dynamic FromJson(this string json, JsonSerializerOptions options = null)
{
if (string.IsNullOrEmpty(json))
return null;
try
{
return JsonSerializer.Deserialize<ExpandoObject>(json, options);
}
catch
{
return null;
}
}
You can also deserialize your json to an object of your target class, and then read its properties as per normal:
var obj = DeSerializeFromStrToObj<ClassToSerialize>(jsonStr);
Console.WriteLine($"Property: {obj.Property}");
where DeSerializeFromStrToObj is a custom class that makes use of reflection to instantiate an object of a targeted class:
public static T DeSerializeFromStrToObj<T>(string json)
{
try
{
var o = (T)Activator.CreateInstance(typeof(T));
try
{
var jsonDict = JsonSerializer.Deserialize<Dictionary<string, string>>(json);
var props = o.GetType().GetProperties();
if (props == null || props.Length == 0)
{
Debug.WriteLine($"Error: properties from target class '{typeof(T)}' could not be read using reflection");
return default;
}
if (jsonDict.Count != props.Length)
{
Debug.WriteLine($"Error: number of json lines ({jsonDict.Count}) should be the same as number of properties ({props.Length})of our class '{typeof(T)}'");
return default;
}
foreach (var prop in props)
{
if (prop == null)
{
Debug.WriteLine($"Error: there was a prop='null' in our target class '{typeof(T)}'");
return default;
}
if (!jsonDict.ContainsKey(prop.Name))
{
Debug.WriteLine($"Error: jsonStr does not refer to target class '{typeof(T)}'");
return default;
}
var value = jsonDict[prop.Name];
Type t = Nullable.GetUnderlyingType(prop.PropertyType) ?? prop.PropertyType;
object safeValue = value ?? Convert.ChangeType(value, t);
prop.SetValue(o, safeValue, null); // initialize property
}
return o;
}
catch (Exception e2)
{
Debug.WriteLine(e2.Message);
return o;
}
}
catch (Exception e)
{
Debug.WriteLine(e.Message);
return default;
}
}
You can test your jsons for example here
Here you find a complete working example with different ways of serialization and deserialization that might be of interest for you and/or future readers:
using System;
using System.Collections.Generic;
using System.Text.Json;
using static Json_Tests.JsonHelpers;
namespace Json_Tests
{
public class Class1
{
public void Test()
{
var obj1 = new ClassToSerialize();
var jsonStr = obj1.ToString();
// if you have the class structure for the jsonStr (for example, if you have created the jsonStr yourself from your code):
var obj2 = DeSerializeFromStrToObj<ClassToSerialize>(jsonStr);
Console.WriteLine($"{nameof(obj2.Name)}: {obj2.Name}");
// if you do not have the class structure for the jsonStr (forexample, jsonStr comes from a 3rd party service like the web):
var obj3 = JsonSerializer.Deserialize<object>(jsonStr) as JsonElement?;
var propName = nameof(obj1.Name);
var propVal1 = obj3?.GetProperty("Name");// error prone
Console.WriteLine($"{propName}: {propVal1}");
JsonElement propVal2 = default;
obj3?.TryGetProperty("Name", out propVal2);// error prone
Console.WriteLine($"{propName}: {propVal2}");
var obj4 = DeSerializeFromStrToDict(jsonStr);
foreach (var pair in obj4)
Console.WriteLine($"{pair.Key}: {pair.Value}");
}
}
[Serializable]
public class ClassToSerialize
{
// important: properties must have at least getters
public string Name { get; } = "Paul";
public string Surname{ get; set; } = "Efford";
public override string ToString() => JsonSerializer.Serialize(this, new JsonSerializerOptions { WriteIndented = true });
}
public static class JsonHelpers
{
/// <summary>
/// to use if you do not have the class structure for the jsonStr (forexample, jsonStr comes from a 3rd party service like the web)
/// </summary>
public static Dictionary<string, string> DeSerializeFromStrToDict(string json)
{
try
{
return JsonSerializer.Deserialize<Dictionary<string, string>>(json);
}
catch (Exception e)
{
Console.WriteLine(e.Message);
return new Dictionary<string, string>(); // return empty
}
}
/// <summary>
/// to use if you have the class structure for the jsonStr (for example, if you have created the jsonStr yourself from your code)
/// </summary>
public static T DeSerializeFromStrToObj<T>(string json) // see this: https://json2csharp.com/#
{
try
{
var o = (T)Activator.CreateInstance(typeof(T));
try
{
var jsonDict = JsonSerializer.Deserialize<Dictionary<string, string>>(json);
var props = o.GetType().GetProperties();
if (props == null || props.Length == 0)
{
Console.WriteLine($"Error: properties from target class '{typeof(T)}' could not be read using reflection");
return default;
}
if (jsonDict.Count != props.Length)
{
Console.WriteLine($"Error: number of json lines ({jsonDict.Count}) should be the same as number of properties ({props.Length})of our class '{typeof(T)}'");
return default;
}
foreach (var prop in props)
{
if (prop == null)
{
Console.WriteLine($"Error: there was a prop='null' in our target class '{typeof(T)}'");
return default;
}
if (!jsonDict.ContainsKey(prop.Name))
{
Console.WriteLine($"Error: jsonStr does not refer to target class '{typeof(T)}'");
return default;
}
var value = jsonDict[prop.Name];
Type t = Nullable.GetUnderlyingType(prop.PropertyType) ?? prop.PropertyType;
object safeValue = value ?? Convert.ChangeType(value, t);
prop.SetValue(o, safeValue, null); // initialize property
}
return o;
}
catch (Exception e2)
{
Console.WriteLine(e2.Message);
return o;
}
}
catch (Exception e)
{
Console.WriteLine(e.Message);
return default;
}
}
}
}

Json Convert all elements as key value pair [duplicate]

I have a simple key/value list in JSON being sent back to ASP.NET via POST. Example:
{ "key1": "value1", "key2": "value2"}
I AM NOT TRYING TO DESERIALIZE INTO STRONGLY-TYPED .NET OBJECTS
I simply need a plain old Dictionary(Of String, String), or some equivalent (hash table, Dictionary(Of String, Object), old-school StringDictionary--hell, a 2-D array of strings would work for me.
I can use anything available in ASP.NET 3.5, as well as the popular Json.NET (which I'm already using for serialization to the client).
Apparently neither of these JSON libraries have this forehead-slapping obvious capability out of the box--they are totally focused on reflection-based deserialization via strong contracts.
Any ideas?
Limitations:
I don't want to implement my own JSON parser
Can't use ASP.NET 4.0 yet
Would prefer to stay away from the older, deprecated ASP.NET class for JSON
Json.NET does this...
string json = #"{""key1"":""value1"",""key2"":""value2""}";
var values = JsonConvert.DeserializeObject<Dictionary<string, string>>(json);
More examples: Serializing Collections with Json.NET
I did discover .NET has a built in way to cast the JSON string into a Dictionary<String, Object> via the System.Web.Script.Serialization.JavaScriptSerializer type in the 3.5 System.Web.Extensions assembly. Use the method DeserializeObject(String).
I stumbled upon this when doing an ajax post (via jquery) of content type 'application/json' to a static .net Page Method and saw that the method (which had a single parameter of type Object) magically received this Dictionary.
System.Text.Json
This can now be done using System.Text.Json which is built-in to .NET Core 3.0. It's now possible to deserialize JSON without using third-party libraries.
var json = #"{""key1"":""value1"",""key2"":""value2""}";
var values = JsonSerializer.Deserialize<Dictionary<string, string>>(json);
Also available in NuGet package System.Text.Json if using .NET Standard or .NET Framework.
Make sure to read and understand:
https://github.com/dotnet/runtime/issues/30452
For those searching the internet and stumbling upon this post, I wrote a blog post on how to use the JavaScriptSerializer class.
Read more...
http://procbits.com/2011/04/21/quick-json-serializationdeserialization-in-c/
Here is an example:
var json = "{\"id\":\"13\", \"value\": true}";
var jss = new JavaScriptSerializer();
var table = jss.Deserialize<dynamic>(json);
Console.WriteLine(table["id"]);
Console.WriteLine(table["value"]);
I had the same problem, so I wrote this my self. This solution is differentiated from other answers because it can deserialize in to multiple levels.
Just send JSON string in to deserializeToDictionary function it will return non strongly-typed Dictionary<string, object> object.
Old code
private Dictionary<string, object> deserializeToDictionary(string jo)
{
var values = JsonConvert.DeserializeObject<Dictionary<string, object>>(jo);
var values2 = new Dictionary<string, object>();
foreach (KeyValuePair<string, object> d in values)
{
// if (d.Value.GetType().FullName.Contains("Newtonsoft.Json.Linq.JObject"))
if (d.Value is JObject)
{
values2.Add(d.Key, deserializeToDictionary(d.Value.ToString()));
}
else
{
values2.Add(d.Key, d.Value);
}
}
return values2;
}
Ex: This will return Dictionary<string, object> object of a Facebook JSON response.
Test
private void button1_Click(object sender, EventArgs e)
{
string responsestring = "{\"id\":\"721055828\",\"name\":\"Dasun Sameera Weerasinghe\",\"first_name\":\"Dasun\",\"middle_name\":\"Sameera\",\"last_name\":\"Weerasinghe\",\"username\":\"dasun\",\"gender\":\"male\",\"locale\":\"en_US\", hometown: {id: \"108388329191258\", name: \"Moratuwa, Sri Lanka\",}}";
Dictionary<string, object> values = deserializeToDictionary(responsestring);
}
Note: hometown further deserilize into a Dictionary<string, object>
object.
Update
My old answer works great if there is no array on JSON string. This one further deserialize in to a List<object> if an element is an array.
Just send a JSON string in to deserializeToDictionaryOrList function it will return non strongly-typed Dictionary<string, object> object or List<object>.
private static object deserializeToDictionaryOrList(string jo,bool isArray=false)
{
if (!isArray)
{
isArray = jo.Substring(0, 1) == "[";
}
if (!isArray)
{
var values = JsonConvert.DeserializeObject<Dictionary<string, object>>(jo);
var values2 = new Dictionary<string, object>();
foreach (KeyValuePair<string, object> d in values)
{
if (d.Value is JObject)
{
values2.Add(d.Key, deserializeToDictionary(d.Value.ToString()));
}
else if (d.Value is JArray)
{
values2.Add(d.Key, deserializeToDictionary(d.Value.ToString(), true));
}
else
{
values2.Add(d.Key, d.Value);
}
}
return values2;
}else
{
var values = JsonConvert.DeserializeObject<List<object>>(jo);
var values2 = new List<object>();
foreach (var d in values)
{
if (d is JObject)
{
values2.Add(deserializeToDictionary(d.ToString()));
}
else if (d is JArray)
{
values2.Add(deserializeToDictionary(d.ToString(), true));
}
else
{
values2.Add(d);
}
}
return values2;
}
}
Tried to not use any external JSON implementation so i deserialised like this:
string json = "{\"id\":\"13\", \"value\": true}";
var serializer = new JavaScriptSerializer(); //using System.Web.Script.Serialization;
Dictionary<string, string> values = serializer.Deserialize<Dictionary<string, string>>(json);
I just needed to parse a nested dictionary, like
{
"x": {
"a": 1,
"b": 2,
"c": 3
}
}
where JsonConvert.DeserializeObject doesn't help. I found the following approach:
var dict = JObject.Parse(json).SelectToken("x").ToObject<Dictionary<string, int>>();
The SelectToken lets you dig down to the desired field. You can even specify a path like "x.y.z" to step further down into the JSON object.
If you're after a lightweight, no-added-references kind of approach, maybe this bit of code I just wrote will work (I can't 100% guarantee robustness though).
using System;
using System.Collections.Generic;
using System.Text;
using System.Text.RegularExpressions;
public Dictionary<string, object> ParseJSON(string json)
{
int end;
return ParseJSON(json, 0, out end);
}
private Dictionary<string, object> ParseJSON(string json, int start, out int end)
{
Dictionary<string, object> dict = new Dictionary<string, object>();
bool escbegin = false;
bool escend = false;
bool inquotes = false;
string key = null;
int cend;
StringBuilder sb = new StringBuilder();
Dictionary<string, object> child = null;
List<object> arraylist = null;
Regex regex = new Regex(#"\\u([0-9a-z]{4})", RegexOptions.IgnoreCase);
int autoKey = 0;
for (int i = start; i < json.Length; i++)
{
char c = json[i];
if (c == '\\') escbegin = !escbegin;
if (!escbegin)
{
if (c == '"')
{
inquotes = !inquotes;
if (!inquotes && arraylist != null)
{
arraylist.Add(DecodeString(regex, sb.ToString()));
sb.Length = 0;
}
continue;
}
if (!inquotes)
{
switch (c)
{
case '{':
if (i != start)
{
child = ParseJSON(json, i, out cend);
if (arraylist != null) arraylist.Add(child);
else
{
dict.Add(key, child);
key = null;
}
i = cend;
}
continue;
case '}':
end = i;
if (key != null)
{
if (arraylist != null) dict.Add(key, arraylist);
else dict.Add(key, DecodeString(regex, sb.ToString()));
}
return dict;
case '[':
arraylist = new List<object>();
continue;
case ']':
if (key == null)
{
key = "array" + autoKey.ToString();
autoKey++;
}
if (arraylist != null && sb.Length > 0)
{
arraylist.Add(sb.ToString());
sb.Length = 0;
}
dict.Add(key, arraylist);
arraylist = null;
key = null;
continue;
case ',':
if (arraylist == null && key != null)
{
dict.Add(key, DecodeString(regex, sb.ToString()));
key = null;
sb.Length = 0;
}
if (arraylist != null && sb.Length > 0)
{
arraylist.Add(sb.ToString());
sb.Length = 0;
}
continue;
case ':':
key = DecodeString(regex, sb.ToString());
sb.Length = 0;
continue;
}
}
}
sb.Append(c);
if (escend) escbegin = false;
if (escbegin) escend = true;
else escend = false;
}
end = json.Length - 1;
return dict; //theoretically shouldn't ever get here
}
private string DecodeString(Regex regex, string str)
{
return Regex.Unescape(regex.Replace(str, match => char.ConvertFromUtf32(Int32.Parse(match.Groups[1].Value, System.Globalization.NumberStyles.HexNumber))));
}
[I realise that this violates the OP Limitation #1, but technically, you didn't write it, I did]
Mark Rendle posted this as a comment, I wanted to post it as an answer since it's the only solution that has worked so far to return the success and the error-codes json results from the Google reCaptcha response.
string jsonReponseString= wClient.DownloadString(requestUrl);
IDictionary<string, object> dict = new JavaScriptSerializer().DeserializeObject(jsonReponseString) as IDictionary<string, object>;
Thanks again, Mark!
For anyone who is trying to convert JSON to dictionary just for retrieving some value out of it. There is a simple way using Newtonsoft.JSON
using Newtonsoft.Json.Linq
...
JObject o = JObject.Parse(#"{
'CPU': 'Intel',
'Drives': [
'DVD read/writer',
'500 gigabyte hard drive'
]
}");
string cpu = (string)o["CPU"];
// Intel
string firstDrive = (string)o["Drives"][0];
// DVD read/writer
IList<string> allDrives = o["Drives"].Select(t => (string)t).ToList();
// DVD read/writer
// 500 gigabyte hard drive
I've added upon the code submitted by jSnake04 and Dasun herein. I've added code to create lists of objects from JArray instances. It has two-way recursion but as it is functioning on a fixed, finite tree model, there is no risk of stack overflow unless the data is massive.
/// <summary>
/// Deserialize the given JSON string data (<paramref name="data"/>) into a
/// dictionary.
/// </summary>
/// <param name="data">JSON string.</param>
/// <returns>Deserialized dictionary.</returns>
private IDictionary<string, object> DeserializeData(string data)
{
var values = JsonConvert.DeserializeObject<Dictionary<string, object>>(data);
return DeserializeData(values);
}
/// <summary>
/// Deserialize the given JSON object (<paramref name="data"/>) into a dictionary.
/// </summary>
/// <param name="data">JSON object.</param>
/// <returns>Deserialized dictionary.</returns>
private IDictionary<string, object> DeserializeData(JObject data)
{
var dict = data.ToObject<Dictionary<String, Object>>();
return DeserializeData(dict);
}
/// <summary>
/// Deserialize any elements of the given data dictionary (<paramref name="data"/>)
/// that are JSON object or JSON arrays into dictionaries or lists respectively.
/// </summary>
/// <param name="data">Data dictionary.</param>
/// <returns>Deserialized dictionary.</returns>
private IDictionary<string, object> DeserializeData(IDictionary<string, object> data)
{
foreach (var key in data.Keys.ToArray())
{
var value = data[key];
if (value is JObject)
data[key] = DeserializeData(value as JObject);
if (value is JArray)
data[key] = DeserializeData(value as JArray);
}
return data;
}
/// <summary>
/// Deserialize the given JSON array (<paramref name="data"/>) into a list.
/// </summary>
/// <param name="data">Data dictionary.</param>
/// <returns>Deserialized list.</returns>
private IList<Object> DeserializeData(JArray data)
{
var list = data.ToObject<List<Object>>();
for (int i = 0; i < list.Count; i++)
{
var value = list[i];
if (value is JObject)
list[i] = DeserializeData(value as JObject);
if (value is JArray)
list[i] = DeserializeData(value as JArray);
}
return list;
}
Edit: This works, but the accepted answer using Json.NET is much more straightforward. Leaving this one in case someone needs BCL-only code.
It’s not supported by the .NET framework out of the box. A glaring oversight – not everyone needs to deserialize into objects with named properties. So I ended up rolling my own:
VB.NET:
<Serializable()> Public Class StringStringDictionary
Implements ISerializable
Public dict As System.Collections.Generic.Dictionary(Of String, String)
Public Sub New()
dict = New System.Collections.Generic.Dictionary(Of String, String)
End Sub
Protected Sub New(info As SerializationInfo, _
context As StreamingContext)
dict = New System.Collections.Generic.Dictionary(Of String, String)
For Each entry As SerializationEntry In info
dict.Add(entry.Name, DirectCast(entry.Value, String))
Next
End Sub
Public Sub GetObjectData(info As SerializationInfo, context As StreamingContext) Implements ISerializable.GetObjectData
For Each key As String in dict.Keys
info.AddValue(key, dict.Item(key))
Next
End Sub
End Class
same on C#:
public class StringStringDictionary : ISerializable
{
public System.Collections.Generic.Dictionary<string, string> dict;
public StringStringDictionary()
{
dict = new System.Collections.Generic.Dictionary<string, string>();
}
protected StringStringDictionary(SerializationInfo info, StreamingContext context)
{
dict = new System.Collections.Generic.Dictionary<string, string>();
foreach (SerializationEntry entry in info)
dict.Add(entry.Name, (string)entry.Value);
}
public void GetObjectData(SerializationInfo info, StreamingContext context)
{
foreach (string key in dict.Keys)
info.AddValue(key, dict[key]);
}
}
Called with:
string MyJsonString = "{ \"key1\": \"value1\", \"key2\": \"value2\"}";
System.Runtime.Serialization.Json.DataContractJsonSerializer dcjs = new
System.Runtime.Serialization.Json.DataContractJsonSerializer(
typeof(StringStringDictionary));
System.IO.MemoryStream ms = new
System.IO.MemoryStream(Encoding.UTF8.GetBytes(MyJsonString));
StringStringDictionary myfields = (StringStringDictionary)dcjs.ReadObject(ms);
Response.Write("Value of key2: " + myfields.dict["key2"]);
Sorry for the mix of C# and VB.NET…
I added a check for null values in the JSON to the other answer
I had same problem so I wrote this my self. This solution is
differentiated from other answers because it can deserialize in to
multiple levels.
Just send json string in to deserializeToDictionary function it
will return non strongly-typed Dictionary<string, object> object.
private Dictionary<string, object> deserializeToDictionary(string jo)
{
var values = JsonConvert.DeserializeObject<Dictionary<string, object>>(jo);
var values2 = new Dictionary<string, object>();
foreach (KeyValuePair<string, object> d in values)
{
if (d.Value != null && d.Value.GetType().FullName.Contains("Newtonsoft.Json.Linq.JObject"))
{
values2.Add(d.Key, deserializeToDictionary(d.Value.ToString()));
}
else
{
values2.Add(d.Key, d.Value);
}
}
return values2;
}
Ex: This will return Dictionary<string, object> object of a Facebook
JSON response.
private void button1_Click(object sender, EventArgs e)
{
string responsestring = "{\"id\":\"721055828\",\"name\":\"Dasun Sameera
Weerasinghe\",\"first_name\":\"Dasun\",\"middle_name\":\"Sameera\",\"last_name\":\"Weerasinghe\",\"username\":\"dasun\",\"gender\":\"male\",\"locale\":\"en_US\",
hometown: {id: \"108388329191258\", name: \"Moratuwa, Sri Lanka\",}}";
Dictionary<string, object> values = deserializeToDictionary(responsestring);
}
Note: hometown further deserialize into a Dictionary<string, object> object.
It seems all of these answers here just assume you can get that little string out of a bigger object... for people looking to simply deserealize a large object with such a dictionary somewhere inside the mapping, and who are using the System.Runtime.Serialization.Json DataContract system, here's a solution:
An answer on gis.stackexchange.com had this interesting link. I had to recover it with archive.org, but it offers a pretty much perfect solution: a custom IDataContractSurrogate class in which you implement exactly your own types. I was able to expand it easily.
I made a bunch of changes in it, though. Since the original source is no longer available, I'll post the entire class here:
using System;
using System.CodeDom;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Json;
using System.Text;
namespace JsonTools
{
/// <summary>
/// Allows using Dictionary<String,String> and Dictionary<String,Boolean> types, and any others you'd like to add.
/// Source: https://web.archive.org/web/20100317222656/my6solutions.com/post/2009/06/30/DataContractSerializer-DataContractJsonSerializer-JavaScriptSerializer-XmlSerializer-for-serialization.aspx
/// </summary>
public class JsonSurrogate : IDataContractSurrogate
{
/// <summary>
/// Deserialize an object with added support for the types defined in this class.
/// </summary>
/// <typeparam name="T">Contract class</typeparam>
/// <param name="json">JSON String</param>
/// <param name="encoding">Text encoding</param>
/// <returns>The deserialized object of type T</returns>
public static T Deserialize<T>(String json, Encoding encoding)
{
if (encoding == null)
encoding = new UTF8Encoding(false);
DataContractJsonSerializer deserializer = new DataContractJsonSerializer(
typeof(T), new Type[0], int.MaxValue, true, new JsonSurrogate(), false);
using (MemoryStream stream = new MemoryStream(encoding.GetBytes(json)))
{
T result = (T)deserializer.ReadObject(stream);
return result;
}
}
// make sure all values in this are classes implementing JsonSurrogateObject.
private static Dictionary<Type, Type> KnownTypes =
new Dictionary<Type, Type>()
{
{typeof(Dictionary<String, String>), typeof(SSDictionary)},
{typeof(Dictionary<String, Boolean>), typeof(SBDictionary)}
};
#region Implemented surrogate dictionary classes
[Serializable]
public class SSDictionary : SurrogateDictionary<String>
{
public SSDictionary() : base() {}
protected SSDictionary (SerializationInfo info, StreamingContext context) : base(info, context) {}
}
[Serializable]
public class SBDictionary : SurrogateDictionary<Boolean>
{
public SBDictionary() : base() {}
protected SBDictionary (SerializationInfo info, StreamingContext context) : base(info, context) {}
}
#endregion
/// <summary>Small interface to easily extract the final value from the object.</summary>
public interface JsonSurrogateObject
{
Object DeserializedObject { get; }
}
/// <summary>
/// Class for deserializing any simple dictionary types with a string as key.
/// </summary>
/// <typeparam name="T">Any simple type that will be deserialized correctly.</typeparam>
[Serializable]
public abstract class SurrogateDictionary<T> : ISerializable, JsonSurrogateObject
{
public Object DeserializedObject { get { return dict; } }
private Dictionary<String, T> dict;
public SurrogateDictionary()
{
dict = new Dictionary<String, T>();
}
// deserialize
protected SurrogateDictionary(SerializationInfo info, StreamingContext context)
{
dict = new Dictionary<String, T>();
foreach (SerializationEntry entry in info)
{
// This cast will only work for base types, of course.
dict.Add(entry.Name, (T)entry.Value);
}
}
// serialize
public void GetObjectData(SerializationInfo info, StreamingContext context)
{
foreach (String key in dict.Keys)
{
info.AddValue(key, dict[key]);
}
}
}
/// <summary>
/// Uses the KnownTypes dictionary to get the surrogate classes.
/// </summary>
/// <param name="type"></param>
/// <returns></returns>
public Type GetDataContractType(Type type)
{
Type returnType;
if (KnownTypes.TryGetValue(type, out returnType))
{
return returnType;
}
return type;
}
public object GetObjectToSerialize(object obj, Type targetType)
{
throw new NotImplementedException();
}
/// <summary>
/// Gets the object out of the surrogate datacontract object. This function is the reason all surrogate objects need to implement the JsonSurrogateObject class.
/// </summary>
/// <param name="obj">Result of the deserialization</param>
/// <param name="targetType">Expected target type of the deserialization</param>
/// <returns></returns>
public object GetDeserializedObject(object obj, Type targetType)
{
if (obj is JsonSurrogateObject)
{
return ((JsonSurrogateObject)obj).DeserializedObject;
}
return obj;
}
public Type GetReferencedTypeOnImport(string typeName, string typeNamespace, object customData)
{
return null;
}
#region not implemented
public object GetCustomDataToExport(MemberInfo memberInfo, Type dataContractType)
{
throw new NotImplementedException();
}
public object GetCustomDataToExport(Type clrType, Type dataContractType)
{
throw new NotImplementedException();
}
public void GetKnownCustomDataTypes(Collection<Type> customDataTypes)
{
throw new NotImplementedException();
}
public CodeTypeDeclaration ProcessImportedType(CodeTypeDeclaration typeDeclaration, CodeCompileUnit compileUnit)
{
throw new NotImplementedException();
}
#endregion
}
}
To add new supported types to the class, you just need to add your class, give it the right constructors and functions (look at SurrogateDictionary for an example), make sure it inherits JsonSurrogateObject, and add its type mapping to the KnownTypes dictionary. The included SurrogateDictionary can serve as basis for any Dictionary<String,T> types where T is any type that does deserialize correctly.
Calling it is really simple:
MyObjtype newObj = JsonSurrogate.Deserialize<MyObjtype>(jsonStr, encoding);
Note that for some reason this thing has trouble using key strings which contain spaces; they were simply not present in the final list. Might just be it's simply against json specs and the api I was calling was poorly implemented, mind you; I dunno. Anyway, I solved this by regex-replacing them with underscores in the raw json data and fixing the dictionary after the deserialization.
Based on comments above try JsonConvert.DeserializeObject<Dictionary<string,dynamic>>(json)
var json = #"{""key1"":1,""key2"":""value2"", ""object1"":{""property1"":""value1"",""property2"":[2,3,4,5,6,7]}}";
var parsedObject = JsonConvert.DeserializeObject<Dictionary<string,dynamic>>(json);
seems to work even for complex objects and lists.
My approach directly deserializes to IDictionary, without JObject or ExpandObject in between. The code uses converter, which is basically copied from ExpandoObjectConverter class found in JSON.NET sourcecode, but using IDictionary instead of ExpandoObject.
Usage:
var settings = new JsonSerializerSettings()
{
Converters = { new DictionaryConverter() },
};
var result = JsonConvert.DeserializeObject<IDictionary<string, object>>(json, settings);
Code:
// based on ExpandoObjectConverter, but using arrays instead of IList, to behave similar to System.Web.Script.Serialization.JavaScriptSerializer
public class DictionaryConverter : JsonConverter
{
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
return ReadValue(reader);
}
public override bool CanConvert(Type objectType)
{
return (objectType == typeof(IDictionary<string, object>));
}
public override bool CanWrite
{
get { return false; }
}
private object ReadValue(JsonReader reader)
{
while (reader.TokenType == JsonToken.Comment)
{
if (!reader.Read())
throw JsonSerializationExceptionCreate(reader, "Unexpected end when reading IDictionary<string, object>.");
}
switch (reader.TokenType)
{
case JsonToken.StartObject:
return ReadObject(reader);
case JsonToken.StartArray:
return ReadList(reader);
default:
if (IsPrimitiveToken(reader.TokenType))
return reader.Value;
throw JsonSerializationExceptionCreate(reader, string.Format(CultureInfo.InvariantCulture, "Unexpected token when converting IDictionary<string, object>: {0}", reader.TokenType));
}
}
private object ReadList(JsonReader reader)
{
List<object> list = new List<object>();
while (reader.Read())
{
switch (reader.TokenType)
{
case JsonToken.Comment:
break;
default:
object v = ReadValue(reader);
list.Add(v);
break;
case JsonToken.EndArray:
return list;
}
}
throw JsonSerializationExceptionCreate(reader, "Unexpected end when reading IDictionary<string, object>.");
}
private object ReadObject(JsonReader reader)
{
IDictionary<string, object> dictionary = new Dictionary<string, object>();
while (reader.Read())
{
switch (reader.TokenType)
{
case JsonToken.PropertyName:
string propertyName = reader.Value.ToString();
if (!reader.Read())
throw JsonSerializationExceptionCreate(reader, "Unexpected end when reading IDictionary<string, object>.");
object v = ReadValue(reader);
dictionary[propertyName] = v;
break;
case JsonToken.Comment:
break;
case JsonToken.EndObject:
return dictionary;
}
}
throw JsonSerializationExceptionCreate(reader, "Unexpected end when reading IDictionary<string, object>.");
}
//based on internal Newtonsoft.Json.JsonReader.IsPrimitiveToken
internal static bool IsPrimitiveToken(JsonToken token)
{
switch (token)
{
case JsonToken.Integer:
case JsonToken.Float:
case JsonToken.String:
case JsonToken.Boolean:
case JsonToken.Undefined:
case JsonToken.Null:
case JsonToken.Date:
case JsonToken.Bytes:
return true;
default:
return false;
}
}
// based on internal Newtonsoft.Json.JsonSerializationException.Create
private static JsonSerializationException JsonSerializationExceptionCreate(JsonReader reader, string message, Exception ex = null)
{
return JsonSerializationExceptionCreate(reader as IJsonLineInfo, reader.Path, message, ex);
}
// based on internal Newtonsoft.Json.JsonSerializationException.Create
private static JsonSerializationException JsonSerializationExceptionCreate(IJsonLineInfo lineInfo, string path, string message, Exception ex)
{
message = JsonPositionFormatMessage(lineInfo, path, message);
return new JsonSerializationException(message, ex);
}
// based on internal Newtonsoft.Json.JsonPosition.FormatMessage
internal static string JsonPositionFormatMessage(IJsonLineInfo lineInfo, string path, string message)
{
if (!message.EndsWith(Environment.NewLine))
{
message = message.Trim();
if (!message.EndsWith(".", StringComparison.Ordinal))
message += ".";
message += " ";
}
message += string.Format(CultureInfo.InvariantCulture, "Path '{0}'", path);
if (lineInfo != null && lineInfo.HasLineInfo())
message += string.Format(CultureInfo.InvariantCulture, ", line {0}, position {1}", lineInfo.LineNumber, lineInfo.LinePosition);
message += ".";
return message;
}
}
Annoyingly enough, if you want to use the default model binders, it looks like you will have to use numerical index values like a form POST.
See the following excerpt from this article http://msdn.microsoft.com/en-us/magazine/hh781022.aspx:
Though it’s somewhat counterintuitive, JSON requests have the same
requirements—they, too, must adhere to the form post naming syntax.
Take, for example, the JSON payload for the previous UnitPrice
collection. The pure JSON array syntax for this data would be
represented as:
[
{ "Code": "USD", "Amount": 100.00 },
{ "Code": "EUR", "Amount": 73.64 }
]
However, the default value providers and model binders require the
data to be represented as a JSON form post:
{
"UnitPrice[0].Code": "USD",
"UnitPrice[0].Amount": 100.00,
"UnitPrice[1].Code": "EUR",
"UnitPrice[1].Amount": 73.64
}
The complex object collection scenario is perhaps one of the most
widely problematic scenarios that developers run into because the
syntax isn’t necessarily evident to all developers. However, once you
learn the relatively simple syntax for posting complex collections,
these scenarios become much easier to deal with.
I just implemented this in RestSharp. This post was helpful to me.
Besides the code in the link, here is my code. I now get a Dictionary of results when I do something like this:
var jsonClient = new RestClient(url.Host);
jsonClient.AddHandler("application/json", new DynamicJsonDeserializer());
var jsonRequest = new RestRequest(url.Query, Method.GET);
Dictionary<string, dynamic> response = jsonClient.Execute<JObject>(jsonRequest).Data.ToObject<Dictionary<string, dynamic>>();
Be mindful of the sort of JSON you're expecting - in my case, I was retrieving a single object with several properties. In the attached link, the author was retrieving a list.
A bit late to the game, but non of the above solutions pointed me in the direction of a pure and simple .NET, no json.net solution. So here it is, ended up being very simple. Below a full running example of how it is done with standard .NET Json serialization, the example has dictionary both in the root object and in the child objects.
The golden bullet is this cat, parse the settings as second parameter to the serializer:
DataContractJsonSerializerSettings settings =
new DataContractJsonSerializerSettings();
settings.UseSimpleDictionaryFormat = true;
Full code below:
using System;
using System.Collections.Generic;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Json;
namespace Kipon.dk
{
public class JsonTest
{
public const string EXAMPLE = #"{
""id"": ""some id"",
""children"": {
""f1"": {
""name"": ""name 1"",
""subs"": {
""1"": { ""name"": ""first sub"" },
""2"": { ""name"": ""second sub"" }
}
},
""f2"": {
""name"": ""name 2"",
""subs"": {
""37"": { ""name"": ""is 37 in key""}
}
}
}
}
";
[DataContract]
public class Root
{
[DataMember(Name ="id")]
public string Id { get; set; }
[DataMember(Name = "children")]
public Dictionary<string,Child> Children { get; set; }
}
[DataContract]
public class Child
{
[DataMember(Name = "name")]
public string Name { get; set; }
[DataMember(Name = "subs")]
public Dictionary<int, Sub> Subs { get; set; }
}
[DataContract]
public class Sub
{
[DataMember(Name = "name")]
public string Name { get; set; }
}
public static void Test()
{
var array = System.Text.Encoding.UTF8.GetBytes(EXAMPLE);
using (var mem = new System.IO.MemoryStream(array))
{
mem.Seek(0, System.IO.SeekOrigin.Begin);
DataContractJsonSerializerSettings settings =
new DataContractJsonSerializerSettings();
settings.UseSimpleDictionaryFormat = true;
var ser = new DataContractJsonSerializer(typeof(Root), settings);
var data = (Root)ser.ReadObject(mem);
Console.WriteLine(data.Id);
foreach (var childKey in data.Children.Keys)
{
var child = data.Children[childKey];
Console.WriteLine(" Child: " + childKey + " " + child.Name);
foreach (var subKey in child.Subs.Keys)
{
var sub = child.Subs[subKey];
Console.WriteLine(" Sub: " + subKey + " " + sub.Name);
}
}
}
}
}
}
You could use Tiny-JSON
string json = "{\"key1\":\"value1\", \"key2\":\"value2\"}";
IDictionary<string, string> dict = Tiny.Json.Decode<Dictionary<string, string>>(json);
I would suggest using System.Runtime.Serialization.Json that is part of .NET 4.5.
[DataContract]
public class Foo
{
[DataMember(Name = "data")]
public Dictionary<string,string> Data { get; set; }
}
Then use it like this:
var serializer = new DataContractJsonSerializer(typeof(List<Foo>));
var jsonParams = #"{""data"": [{""Key"":""foo"",""Value"":""bar""}] }";
var stream = new MemoryStream(Encoding.UTF8.GetBytes(jsonParams));
var obj = serializer.ReadObject(stream);
Console.WriteLine(obj);
Here is my solution with System.Text.Json. You get a json string for the nested objects which in own turn can be converted to needed type later on.
public static Dictionary<string,string> JsonToDictionary(this string json)
{
var objectValues = JsonSerializer.Deserialize<Dictionary<string, object>>(json);
var stringValues = objectValues.Select(o => new KeyValuePair<string, string>(o.Key, o.Value?.ToString()));
return stringValues.ToDictionary(pair => pair.Key, pair => pair.Value);
}
Here is the usage example to fetch values from a nested object:
var result= json.JsonToDictionary()["outerField"]
.JsonToDictionary()["innerField"];
Note that this solution does not cover the json objects starting as an array like [12, 13]. These objects can be read as an array in the begining and then the extension method can be applied on each item, in case the items are complex objects with their own properties.

Json.net deserializing nested Dictionaries with non-string key types

I am using Json.NET to deserialize an object which includes a nested Dictionary with a custom (non-string) key type. Here is a sample of what I am trying to do
public interface IInterface
{
String Name { get; set; }
}
public class AClass : IInterface
{
public string Name { get; set; }
}
public class Container
{
public Dictionary<IInterface, string> Map { get; set; }
public Container()
{
Map = new Dictionary<IInterface, string>();
}
}
public static void Main(string[] args)
{
var container = new Container();
container.Map.Add(new AClass()
{
Name = "Hello World"
}, "Hello Again");
var settings = new JsonSerializerSettings
{
TypeNameHandling = TypeNameHandling.Objects,
PreserveReferencesHandling = PreserveReferencesHandling.All,
};
string jsonString = JsonConvert.SerializeObject(container, Formatting.Indented, settings);
var newContainer = JsonConvert.DeserializeObject<Container>(jsonString);
}
This yields the exception message:
Could not convert string 'ConsoleApplication1.AClass' to dictionary key type 'ConsoleApplication1.IInterface'. Create a TypeConverter to convert from the string to the key type object. Please accept my apology however I cant find a way to de-serialize interface in Dictionary key.
The issue is that JSON dictionaries (objects) only support string keys, so Json.Net converts your complex key type to a Json string (calling ToString()) which can't then be deserialized into the complex type again. Instead, you can serialize your dictionary as a collection of key-value pairs by applying the JsonArray attribute.
See this question for details.
If your key type can be (de-)serialized into a plain string (as is the case with your IInterface sample), this is still possible without the use of arrays. Sadly not out of the box.
So.. I wrote a custom JsonConverter to work around this and allow for custom key types in any Dictionary without needing to use other contracts for this. It supports both serialization and deserialization: Json.NET converter for custom key dictionaries in object style
The serialization behavior is very similar to the default behavior when serializing a Dictionary in Json.NET. It is only needed to force the serialization on the key type pretty much. Here is a gist of one way this can be done:
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
// Aquire reflection info & get key-value-pairs:
Type type = value.GetType();
bool isStringKey = type.GetGenericArguments()[0] == typeof(string);
IEnumerable keys = (IEnumerable)type.GetProperty("Keys").GetValue(value, null);
IEnumerable values = (IEnumerable)type.GetProperty("Values").GetValue(value, null);
IEnumerator valueEnumerator = values.GetEnumerator();
// Write each key-value-pair:
StringBuilder sb = new StringBuilder();
using (StringWriter tempWriter = new StringWriter(sb))
{
writer.WriteStartObject();
foreach (object key in keys)
{
valueEnumerator.MoveNext();
// convert key, force serialization of non-string keys
string keyStr = null;
if (isStringKey)
{
// Key is not a custom type and can be used directly
keyStr = (string)key;
}
else
{
sb.Clear();
serializer.Serialize(tempWriter, key);
keyStr = sb.ToString();
// Serialization can wrap the string with literals
if (keyStr[0] == '\"' && keyStr[str.Length-1] == '\"')
keyStr = keyStr.Substring(1, keyStr.Length - 1);
// TO-DO: Validate key resolves to single string, no complex structure
}
writer.WritePropertyName(keyStr);
// default serialize value
serializer.Serialize(writer, valueEnumerator.Current);
}
writer.WriteEndObject();
}
}
De-serialization is the bigger deal as it has to create and parse generic types that cannot be specified explicitly. Thankfully reflection is pretty powerful here. This is the gist:
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
// Aquire reflection info & create resulting dictionary:
Type[] dictionaryTypes = objectType.GetGenericArguments();
bool isStringKey = dictionaryTypes[0] == typeof(string);
IDictionary res = Activator.CreateInstance(objectType) as IDictionary;
// Read each key-value-pair:
object key = null;
object value = null;
while (reader.Read())
{
if (reader.TokenType == JsonToken.EndObject)
break;
if (reader.TokenType == JsonToken.PropertyName)
{
key = isStringKey ? reader.Value : serializer.Deserialize(reader, dictionaryTypes[0]);
}
else
{
value = serializer.Deserialize(reader, dictionaryTypes[1]);
res.Add(key, value);
key = null;
value = null;
}
}
return res;
}
With a converter like this, JSON objects can be used as dictionaries directly, as you'd expect it. In other words you can now do this:
{
MyDict: {
"Key1": "Value1",
"Key2": "Value2"
[...]
}
}
instead of this:
{
MyDict: [
["Key1", "Value1"],
["Key2", "Value2"]
[...]
]
}

Deserialize JSON into C# dynamic object?

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.
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)
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
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);
.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.
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);
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);
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]}
Another way using Newtonsoft.Json:
dynamic stuff = Newtonsoft.Json.JsonConvert.DeserializeObject("{ color: 'red', value: 5 }");
string color = stuff.color;
int value = stuff.value;
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.
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) })); }
}
}
}
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
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; }
}
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.
Another option is to "Paste JSON as classes" so it can be deserialised quick and easy.
Simply copy your entire JSON
In Visual Studio: Click Edit → Paste Special → Paste JSON as classes
Here is a better explanation n piccas... ‘Paste JSON As Classes’ in ASP.NET and Web Tools 2012.2 RC
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
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 .
Try this:
var units = new { Name = "Phone", Color= "White" };
var jsonResponse = JsonConvert.DeserializeAnonymousType(json, units);
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);
Look at the article I wrote on CodeProject, one that answers the question precisely:
Dynamic types with JSON.NET
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.
For that I would use JSON.NET to do the low-level parsing of the JSON stream and then build up the object hierarchy out of instances of the ExpandoObject class.
To get an ExpandoObject:
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
Container container = JsonConvert.Deserialize<Container>(jsonAsString, new ExpandoObjectConverter());
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.
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.
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
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;
}
How to parse easy JSON content with dynamic & JavaScriptSerializer
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();
}
How to parse nested & complex json with dynamic & JavaScriptSerializer
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();
}
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");
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.
try this way!
JSON example:
[{
"id": 140,
"group": 1,
"text": "xxx",
"creation_date": 123456,
"created_by": "xxx#gmail.co",
"tags": ["xxxxx"]
}, {
"id": 141,
"group": 1,
"text": "xxxx",
"creation_date": 123456,
"created_by": "xxx#gmail.com",
"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()}");
}
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();
}
}
}

Categories