Removing deserializing a dictionary key from json to enum in .net
I am reading a json API response that contains information about images.
It is in dictionary format like this:
images: {
low_resolution: {
url: "...",
width: 150,
height: 150
},
high_resolution: {
url: "...",
width: 450,
height: 450
}
}
I deserialize the response into an object, and the images into a dictionary property like so:
[DataContract()]
public class Post
{
...
[DataMember(Name = "images")]
public IDictionary<string, Media> Images { get; set; }
...
}
HttpResponseMessage response = await client.GetAsync(query);
if (response.IsSuccessStatusCode)
{
post = await response.Content.ReadAsAsync<Post>();
}
This all works fine so far, but I would rather deserialize the image resolution information into an enum value. So I created an enum ImageResolution
and changed the dictionary from string
to ImageResolution
.
This also deserializes successfully, as long as the actual enum value is json string , but I want to change the enum values.
As with other other posts I've tried the following:
[DataContract()]
public enum ImageResolution
{
[EnumMember(Value = "low_resolution")]
Low,
[EnumMember(Value = "high_resolution")]
High,
}
Also from a search I also tried to add:
[JsonConverter(typeof(StringEnumConverter))]
But so far nothing has worked out. There is another property in the answer that I successfully deserialize into an enum and change the value of the enum using the attribute JsonConverter
, but this is a direct access property, not a dictionary, so I guess this dictionary key is causing some problems.
Is it possible to deserialize json value for enum dictionary key with different text value?
source to share
You need to write a CustomConverter for the whole Dictionary as mentioned here .
I adapted the code to use EnumMember instead of the prefix used in another post:
public class DictionaryWithSpecialEnumKeyConverter : JsonConverter
{
public override bool CanWrite
{
get { return false; }
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
throw new NotSupportedException();
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
if (reader.TokenType == JsonToken.Null)
return null;
var valueType = objectType.GetGenericArguments()[1];
var intermediateDictionaryType = typeof(Dictionary<,>).MakeGenericType(typeof(string), valueType);
var intermediateDictionary = (IDictionary)Activator.CreateInstance(intermediateDictionaryType);
serializer.Populate(reader, intermediateDictionary);
var finalDictionary = (IDictionary)Activator.CreateInstance(objectType);
foreach (DictionaryEntry pair in intermediateDictionary)
finalDictionary.Add(ToEnum<ImageResolution>(pair.Key.ToString()), pair.Value);
return finalDictionary;
}
private T ToEnum<T>(string str)
{
var enumType = typeof(T);
foreach (var name in Enum.GetNames(enumType))
{
var enumMemberAttribute = ((EnumMemberAttribute[])enumType.GetField(name).GetCustomAttributes(typeof(EnumMemberAttribute), true)).Single();
if (enumMemberAttribute.Value == str) return (T)Enum.Parse(enumType, name);
}
return default(T);
}
public override bool CanConvert(Type objectType)
{
return true;
}
}
And use it in a dictionary:
[DataContract]
public class Post
{
[JsonConverter(typeof(DictionaryWithSpecialEnumKeyConverter))]
[DataMember(Name = "images")]
public Dictionary<ImageResolution, Media> Images { get; set; }
}
source to share