| 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; } | |
| } |