Double Parse with Culture Format

Newtonsoft Json Deserialize Dictionary as Key/Value list from DataContractJsonSerializer

You could use a custom converter for this, depending on what token the dictionary starts with, deserialize it JSON.NET's default way, or deserialize it into an array and then turn that array into a Dictionary:

public class DictionaryConverter : JsonConverter
{
public override object ReadJson(
JsonReader reader,
Type objectType,
object existingValue,
JsonSerializer serializer)
{
IDictionary<string, string> result;

if (reader.TokenType == JsonToken.StartArray)
{
JArray legacyArray = (JArray)JArray.ReadFrom(reader);

result = legacyArray.ToDictionary(
el => el["Key"].ToString(),
el => el["Value"].ToString());
}
else
{
result =
(IDictionary<string, string>)
serializer.Deserialize(reader, typeof(IDictionary<string, string>));
}

return result;
}

public override void WriteJson(
JsonWriter writer, object value, JsonSerializer serializer)
{
throw new NotImplementedException();
}

public override bool CanConvert(Type objectType)
{
return typeof(IDictionary<string, string>).IsAssignableFrom(objectType);
}

public override bool CanWrite
{
get { return false; }
}
}

Then, you can decorate the Dict property in the Data class with a JsonConverter attribute:

public sealed class Data
{
[JsonConverter(typeof(DictionaryConverter))]
public IDictionary<string, string> Dict { get; set; }
}

Then deserializing both strings should work as expected.

How can I deserialize JSON to a simple Dictionarystring,string in ASP.NET?

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

Deserialize Dictionary with JSON.NET

It should work if you declare Attributes as List<KeyValuePair<string, string>>

Can I set my own default ListT converter in JSON.net (without attributes)

You can take advantage of the fact that List<T> implements the non-generic interface IList to create a non-generic JsonConverter for all List<T> types:

public class ArrayObjectConverter : JsonConverter
{
public override bool CanConvert(Type t) => t.GetListItemType() != null;
public override bool CanWrite => false;

public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer) => throw new NotImplementedException();

public override object? ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer)
{
System.Diagnostics.Debug.Assert(objectType.GetListItemType() != null);

if (reader.MoveToContentAndAssert().TokenType == JsonToken.Null)
return null;

IList value = existingValue as IList ?? (IList)serializer.ContractResolver.ResolveContract(objectType).DefaultCreator!();

if (reader.TokenType == JsonToken.StartArray)
{
serializer.Populate(reader, value);
}
else if (reader.TokenType == JsonToken.StartObject)
{
var itemType = objectType.GetListItemType().ThrowOnNull();
while (reader.ReadToContentAndAssert().TokenType != JsonToken.EndObject)
{
// Eat the property name
reader.AssertTokenType(JsonToken.PropertyName).ReadToContentAndAssert();
// Deserialize the property value and add it to the list.
value.Add(serializer.Deserialize(reader, itemType));
}
}
else
{
throw new JsonSerializationException(string.Format("Unknown token type {0}", reader.TokenType));
}

return value;
}
}

public static partial class JsonExtensions
{
public static JsonReader AssertTokenType(this JsonReader reader, JsonToken tokenType) =>
reader.TokenType == tokenType ? reader : throw new JsonSerializationException(string.Format("Unexpected token {0}, expected {1}", reader.TokenType, tokenType));

public static JsonReader ReadToContentAndAssert(this JsonReader reader) =>
reader.ReadAndAssert().MoveToContentAndAssert();

public static JsonReader MoveToContentAndAssert(this JsonReader reader)
{
if (reader == null)
throw new ArgumentNullException();
if (reader.TokenType == JsonToken.None) // Skip past beginning of stream.
reader.ReadAndAssert();
while (reader.TokenType == JsonToken.Comment) // Skip past comments.
reader.ReadAndAssert();
return reader;
}

public static JsonReader ReadAndAssert(this JsonReader reader)
{
if (reader == null)
throw new ArgumentNullException();
if (!reader.Read())
throw new JsonReaderException("Unexpected end of JSON stream.");
return reader;
}

public static Type? GetListItemType(this Type type)
{
// Quick reject for performance
if (type.IsPrimitive || type.IsArray || type == typeof(string))
return null;
while (type != null)
{
if (type.IsGenericType)
{
var genType = type.GetGenericTypeDefinition();
if (genType == typeof(List<>))
return type.GetGenericArguments()[0];
}
type = type.BaseType!;
}
return null;
}
}

public static partial class ObjectExtensions
{
public static T ThrowOnNull<T>(this T? value) where T : class => value ?? throw new ArgumentNullException(nameof(value));
}

Notes:

  • Your question mentions The solution should be as optimized as possible so the converter deserializes directly from the JsonReader without needing to pre-load anything into intermediate JArray or JObject instances.

  • The converter should work for subclasses of List<T> as well.

  • If you need to support types that implement ICollection<T> types but do not also implement the non-generic IList interface (such as HashSet<T>), you will need to use reflection to invoke a generic method from the non-generic ReadJson() e.g. as shown in this answer to Newtonsoft Json Deserialize Dictionary as Key/Value list from DataContractJsonSerializer.

Demo fiddle here.

How to deserialize a dictionary using DataContractJsonSerializer?

Since there isn't a dictionary type in javascript it's rather difficult to have JSON deparse into one. What you're going to have to do is write a converter yourself.

However, that's also true on most custom serialization objects, so hopefully that comes as no big surprise.

Now it should, however, read in as a KeyValuePair so you can try that, to see if it's at least deserializing for you. Rather, you would need a List<KeyValuePair<>>

What a Dictionary<string,string> translates into for JSON:

var dict = new Dictionary<string,string>; 
dict["Red"] = "Rosso";
dict["Blue"] = "Blu";
dict["Green"] = "Verde";

[{"Key":"Red","Value":"Rosso"},
{"Key":"Blue","Value":"Blu"},
{"Key":"Green","Value":"Verde"}]

The same associative from javascript into JSON:

var a = {}; 
a["Red"] = "Rosso";
a["Blue"] = "Blu";
a["Green"] = "Verde";

{"Red":"Rosso","Blue":"Blu","Green":"Verde"}

So there's the problem in a nutshell.


A few followup links for usefulness

http://my6solutions.com/post/2009/06/17/The-serialization-and-deserialization-of-the-generic-Dictionary-via-the-DataContractJsonSerializer.aspx

http://msdn.microsoft.com/en-us/library/system.runtime.serialization.collectiondatacontractattribute.aspx



Related Topics



Leave a reply



Submit