I need to deserialize a complex JSON blob into standard .NET containers for use in code that is not aware of JSON. It expects things to be in standard .NET
One way to deserialize a json string recursively into dictionaries and lists with JSON.NET is to create a custom json converter class that derives from the JsonConverter
abstract class provided by JSON.NET.
It is in your derived JsonConverter
where you put the implementation of how an object should be written to and from json.
You can use your custom JsonConverter
like this:
var o = JsonConvert.DeserializeObject>(json, new DictionaryConverter());
Here is a custom JsonConverter I have used with success in the past to achieve the same goals as you outline in your question:
public class DictionaryConverter : JsonConverter {
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) { this.WriteValue(writer, value); }
private void WriteValue(JsonWriter writer, object value) {
var t = JToken.FromObject(value);
switch (t.Type) {
case JTokenType.Object:
this.WriteObject(writer, value);
break;
case JTokenType.Array:
this.WriteArray(writer, value);
break;
default:
writer.WriteValue(value);
break;
}
}
private void WriteObject(JsonWriter writer, object value) {
writer.WriteStartObject();
var obj = value as IDictionary;
foreach (var kvp in obj) {
writer.WritePropertyName(kvp.Key);
this.WriteValue(writer, kvp.Value);
}
writer.WriteEndObject();
}
private void WriteArray(JsonWriter writer, object value) {
writer.WriteStartArray();
var array = value as IEnumerable
Here is the equivalent in f#
:
type IDictionaryConverter() =
inherit JsonConverter()
let rec writeValue (writer: JsonWriter) (value: obj) =
let t = JToken.FromObject(value)
match t.Type with
| JTokenType.Object -> writeObject writer value
| JTokenType.Array -> writeArray writer value
| _ -> writer.WriteValue value
and writeObject (writer: JsonWriter) (value: obj) =
writer.WriteStartObject ()
let obj = value :?> IDictionary
for kvp in obj do
writer.WritePropertyName kvp.Key
writeValue writer kvp.Value
writer.WriteEndObject ()
and writeArray (writer: JsonWriter) (value: obj) =
writer.WriteStartArray ()
let array = value :?> IEnumerable
for o in array do
writeValue writer o
writer.WriteEndArray ()
let rec readValue (reader: JsonReader) =
while reader.TokenType = JsonToken.Comment do
if reader.Read () |> not then raise (JsonSerializationException("Unexpected token when reading object"))
match reader.TokenType with
| JsonToken.Integer
| JsonToken.Float
| JsonToken.String
| JsonToken.Boolean
| JsonToken.Undefined
| JsonToken.Null
| JsonToken.Date
| JsonToken.Bytes -> reader.Value
| JsonToken.StartObject -> readObject reader Map.empty
| JsonToken.StartArray -> readArray reader []
| _ -> raise (JsonSerializationException(sprintf "Unexpected token when reading object: %O" reader.TokenType))
and readObject (reader: JsonReader) (obj: Map) =
match reader.Read() with
| false -> raise (JsonSerializationException("Unexpected end when reading object"))
| _ -> reader.TokenType |> function
| JsonToken.Comment -> readObject reader obj
| JsonToken.PropertyName ->
let propertyName = reader.Value.ToString ()
if reader.Read() |> not then raise (JsonSerializationException("Unexpected end when reading object"))
let value = readValue reader
readObject reader (obj.Add(propertyName, value))
| JsonToken.EndObject -> box obj
| _ -> raise (JsonSerializationException(sprintf "Unexpected token when reading object: %O" reader.TokenType))
and readArray (reader: JsonReader) (collection: obj list) =
match reader.Read() with
| false -> raise (JsonSerializationException("Unexpected end when reading array"))
| _ -> reader.TokenType |> function
| JsonToken.Comment -> readArray reader collection
| JsonToken.EndArray -> box collection
| _ -> collection @ [readValue reader] |> readArray reader
override __.CanConvert t = (typeof>).IsAssignableFrom t
override __.WriteJson (writer:JsonWriter, value: obj, _:JsonSerializer) = writeValue writer value
override __.ReadJson (reader:JsonReader, _: Type, _:obj, _:JsonSerializer) = readValue reader