Create a gist now

Instantly share code, notes, and snippets.

What would you like to do?
JSON Entity Converter
void Main()
{
var co = new Company { Id = 1, Name = "Moof Inc." };
var clarus = new Contact { Id = 1, Name = "Clarus" };
var mark = new Contact { Id = 2, Name = "Mark" };
co.AddContact(clarus);
co.AddContact(mark);
co.MainContact = clarus;
// Attempt #1: Straight up, no converter
// var serializer1 = new JavaScriptSerializer();
// serializer1.Serialize(co).Dump();
// => InvalidOperationException: A circular reference was detected while serializing an object of type 'UserQuery+Company'.
// Attempt #2: Converter handles all Entities
var converter2 = new EntityConverter();
var serializer2 = new JavaScriptSerializer();
serializer2.RegisterConverters(new[] { converter2 });
serializer2.Serialize(co).Dump();
// => {"Name":"Moof Inc.","Contacts":[{"Name":"Clarus","WorksFor":1,"Id":1},{"Name":"Mark","WorksFor":1,"Id":2}],"MainContact":1,"Id":1}
// Attempt #3: Converter handles only contacts
var converter3 = new EntityConverter(new[] { typeof(Contact) });
var serializer3 = new JavaScriptSerializer();
serializer3.RegisterConverters(new[] { converter3 });
serializer3.Serialize(co).Dump();
// => {"Name":"Moof Inc.","Contacts":[{"Name":"Clarus","WorksFor":1,"Id":1},{"Name":"Mark","WorksFor":1,"Id":2}],"MainContact":{"Name":"Clarus","WorksFor":1,"Id":1},"Id":1}
// Attempt #4: Converter with custom output for entities.
var converter4 = new EntityConverter(new[] { typeof(Contact) }, en => new ReducedEntity(en));
var serializer4 = new JavaScriptSerializer();
serializer4.RegisterConverters(new[] { converter4 });
serializer4.Serialize(co).Dump();
// => {"Name":"Moof Inc.","Contacts":[{"Name":"Clarus","WorksFor":{"TypeName":"Company","Id":1},"Id":1},{"Name":"Mark","WorksFor":{"TypeName":"Company","Id":1},"Id":2}],"MainContact":{"Name":"Clarus","WorksFor":{"TypeName":"Company","Id":1},"Id":1},"Id":1}
}
// Define other methods and classes here
public class Entity {
public int Id { get; set; }
}
public class Company : Entity {
public string Name { get; set; }
public IEnumerable<Contact> Contacts { get { return _contacts; } }
public Contact MainContact { get; set; }
public void AddContact(Contact aContact) {
if (_contacts.Contains(aContact)) throw new ArgumentException("Contact already exists in the list.");
aContact.WorksFor = this;
_contacts.Add(aContact);
}
private List<Contact> _contacts = new List<Contact>();
}
public class Contact : Entity {
public string Name { get; set; }
// public string Address { get; set; }
public Company WorksFor { get; set; }
}
public class EntityConverter : JavaScriptConverter {
private IEnumerable<Type> _supportedTypes;
private Func<Entity, object> _reducer;
public EntityConverter() : this(new[] { typeof(Entity) }) {}
public EntityConverter(IEnumerable<Type> supportedTypes, Func<Entity, object> reducer = null) {
_supportedTypes = supportedTypes.DefaultIfEmpty(typeof(Entity));
_reducer = reducer ?? (en => en.Id);
}
public override IEnumerable<Type> SupportedTypes { get { return _supportedTypes; } }
public override IDictionary<string, object> Serialize(object obj, JavaScriptSerializer serializer) {
var ret = new Dictionary<string, object>();
if (obj == null) return ret;
string name; object value;
var props = obj.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.GetProperty);
foreach (PropertyInfo prop in props) {
name = prop.Name;
value = prop.GetValue(obj, null);
if (value != null && typeof(Entity).IsAssignableFrom(prop.PropertyType))
ret.Add(name, _reducer((Entity) value));
else
ret.Add(name, value);
}
return ret;
}
public override object Deserialize(IDictionary<string, object> obj, Type type, JavaScriptSerializer serializer) {
throw new NotImplementedException();
}
}
public class ReducedEntity {
public ReducedEntity(Entity anEntity) {
TypeName = anEntity.GetType().Name;
Id = anEntity.Id;
}
public string TypeName { get; private set; }
public int Id { get; private set; }
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment