Here is the generizied version of Tom Maher's answer. This will automatically register all nested property types in your DataObject
to the converter so they can make use of the JsonPropertyAttribute
.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web.Script.Serialization;
using System.Reflection;
using System.Collections;
public class JavascriptConverterFactory<T> : JavaScriptConverter where T : class
{
public override object Deserialize(IDictionary<string, object> dictionary, Type type, JavaScriptSerializer serializer)
{
List<MemberInfo> members = new List<MemberInfo>();
members.AddRange(type.GetFields());
members.AddRange(type.GetProperties().Where(p => p.CanRead && p.CanWrite && p.GetIndexParameters().Length == 0));
object obj = Activator.CreateInstance(type);
foreach (MemberInfo member in members)
{
JsonPropertyAttribute jsonProperty = (JsonPropertyAttribute)Attribute.GetCustomAttribute(member, typeof(JsonPropertyAttribute));
if (jsonProperty != null && dictionary.ContainsKey(jsonProperty.Name))
{
SetMemberValue(serializer, member, obj, dictionary[jsonProperty.Name]);
}
else if (dictionary.ContainsKey(member.Name))
{
SetMemberValue(serializer, member, obj, dictionary[member.Name]);
}
else
{
KeyValuePair<string, object> kvp = dictionary.FirstOrDefault(x => string.Equals(x.Key, member.Name, StringComparison.InvariantCultureIgnoreCase));
if (!kvp.Equals(default(KeyValuePair<string, object>)))
{
SetMemberValue(serializer, member, obj, kvp.Value);
}
}
}
return obj;
}
private void SetMemberValue(JavaScriptSerializer serializer, MemberInfo member, object obj, object value)
{
if (member is PropertyInfo)
{
PropertyInfo property = (PropertyInfo)member;
property.SetValue(obj, serializer.ConvertToType(value, property.PropertyType), null);
}
else if (member is FieldInfo)
{
FieldInfo field = (FieldInfo)member;
field.SetValue(obj, serializer.ConvertToType(value, field.FieldType));
}
}
public override IDictionary<string, object> Serialize(object obj, JavaScriptSerializer serializer)
{
Type type = obj.GetType();
List<MemberInfo> members = new List<MemberInfo>();
members.AddRange(type.GetFields());
members.AddRange(type.GetProperties().Where(p => p.CanRead && p.CanWrite && p.GetIndexParameters().Length == 0));
Dictionary<string, object> values = new Dictionary<string, object>();
foreach (MemberInfo member in members)
{
JsonPropertyAttribute jsonProperty = (JsonPropertyAttribute)Attribute.GetCustomAttribute(member, typeof(JsonPropertyAttribute));
if (jsonProperty != null)
{
values[jsonProperty.Name] = GetMemberValue(member, obj);
}
else
{
values[member.Name] = GetMemberValue(member, obj);
}
}
return values;
}
private object GetMemberValue(MemberInfo member, object obj)
{
if (member is PropertyInfo)
{
PropertyInfo property = (PropertyInfo)member;
return property.GetValue(obj, null);
}
else if (member is FieldInfo)
{
FieldInfo field = (FieldInfo)member;
return field.GetValue(obj);
}
return null;
}
public override IEnumerable<Type> SupportedTypes
{
get
{
return new[] { typeof(T) }.Concat(GetAllNestedTypes(typeof(T)));
}
}
public static JavaScriptSerializer Create()
{
JavaScriptSerializer serializer = new JavaScriptSerializer();
serializer.RegisterConverters(new[] { new JavascriptConverterFactory<T>() });
return serializer;
}
private static Type[] GetAllNestedTypes(Type type)
{
ArrayList types = new ArrayList();
AddNestedMemberPropertyTypesRecursively(types, type);
return (Type[])types.ToArray(typeof(Type));
}
private static ArrayList AddNestedMemberPropertyTypesRecursively(ArrayList types, Type type)
{
List<MemberInfo> members = new List<MemberInfo>();
members.AddRange(type.GetFields());
members.AddRange(type.GetProperties().Where(p => p.CanRead && p.CanWrite && p.GetIndexParameters().Length == 0));
Dictionary<string, object> values = new Dictionary<string, object>();
foreach (MemberInfo member in members)
{
if (member is PropertyInfo)
{
PropertyInfo property = (PropertyInfo)member;
bool isAlreadyInArray = types.Contains(property.PropertyType);
if (!isAlreadyInArray)
{
types.Add(property.PropertyType);
if (property.PropertyType.IsArray)
{
Type arrayElementType = property.PropertyType.GetElementType();
isAlreadyInArray = types.Contains(arrayElementType);
if (!isAlreadyInArray)
{
types.Add(arrayElementType);
AddNestedMemberPropertyTypesRecursively(types, arrayElementType);
}
}
AddNestedMemberPropertyTypesRecursively(types, property.PropertyType);
}
}
}
return types;
}
}
using System;
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)]
public class JsonPropertyAttribute : Attribute
{
public JsonPropertyAttribute(string name)
{
Name = name;
}
public string Name
{
get;
set;
}
}
public class DataObject
{
[JsonProperty("nested:dataobject")]
NestedDataObject nestedObject { get; set; }
}
public class NestedDataObject
{
[JsonProperty("some-other-string")]
string someOtherString { get; set; }
}
How to use:
public DataObject GetData(responseContent)
{
JavaScriptSerializer serializer = JavascriptConverterFactory<DataObject>.Create();
DataObject deserializedData = serializer.Deserialize<DataObject>(responseContent);
return deserializedData;
}
JavaScriptSerializer
.JwtSecurityTokenHandler
uses it through the staticJsonExtensions.Serializer
property, which means changing it during runtime could affect other code that expects it to be unchanged. Many of these classes are that way, unfortunately. :( – Outvote