2010-10-13 11 views
0

Comment puis-je désérialiser chaîne JSON dans l'entité de type comme ceci (propriétés auto-suivi enlevés pour être simple):entité auto-suivi désérialisation avec TrackableCollection imbriqué

public class User: 
{ 
    int Id { get; set; } 
    string Name { get; set; } 
    public TrackableCollection<Role> Roles { get; set; } // <! 
} 

rôle est aussi simple classe avec deux propriétés. TrackableCollection est un descendant de Collection (System.Collections.ObjectModel).

Je veux: avoir chaîne JSON comme celui-ci

{"Id":0, "Name":"Test User", "Roles": [{"Id":1, "Name": "Role 1"}, {"Id":2, "Name": "Role 2"}, {"Id":3, "Name": "Role 3"}]}

entité get avec la collecte des rôles correctement désérialisée.

Répondre

1

Ok, semble que personne ne s'est intéressé à cette question, de toute façon voici la solution. Cette classe sérialise et désérialise les entités POCO auto-suivies, y compris toutes les TrackableCollections imbriquées et les objets.

Veuillez noter à propos de SupportedTypes méthode. J'ai ajouté le IEntity Interface (blanc à l'intérieur) et modifié mon modèle T4 sur cette ligne:

<#=Accessibility.ForType(entity)#> <#=code.SpaceAfter(code.AbstractOption(entity))#>partial class <#=code.Escape(entity)#><#=code.StringBefore(" : ", code.Escape(entity.BaseType))#><#=(entity.BaseType == null ? ": " : ", ") + "IEntity" #>, IObjectWithChangeTracker, INotifyPropertyChanged 

Vous ne pouvez rien faire au sujet IEntity. Il suffit d'écrire la méthode SupportedTypes selon vos besoins.

I a également commenté le [DataMember] attribut dans le modèle ci-dessus la propriété ChangeTracker:

//[DataMember] 
public ObjectChangeTracker ChangeTracker 

Quoi qu'il en soit ce n'est pas important. Prenez l'EntityConverter et profitez-en.

/// <summary> 
/// Serializes self-tracking POCO entities with DataMemberAttribute marked properties. 
/// </summary> 
public class EntityConverter : JavaScriptConverter 
{ 
    public override IDictionary<string, object> Serialize(object obj, JavaScriptSerializer serializer) 
    { 
     Dictionary<string, object> result = new Dictionary<string, object>(); 
     if (obj != null) 
     { 
      var properties = obj.GetType().GetProperties().Where(prop => prop.HasAttibute(typeof(DataMemberAttribute))); 
      foreach (var property in properties) 
      { 
       object value = property.GetValue(obj, null); 
       // Serialize nested TrackableCollection object 
       if (property.PropertyType.Name.Equals(typeof(TrackableCollection<object>).Name)) 
        value = SerializeCollection((value as IEnumerable).Cast<object>(), serializer); 

       result.Add(property.Name, value); 
      } 
     } 
     return result; 
    } 

    public override object Deserialize(IDictionary<string, object> dictionary, Type type, JavaScriptSerializer serializer) 
    { 
     if (dictionary == null) 
      throw new ArgumentNullException("dictionary"); 

     var entity = Activator.CreateInstance(type); 
     foreach (KeyValuePair<string, object> kvp in dictionary) 
     { 
      PropertyInfo property = type.GetProperty(kvp.Key); 
      if ((property != null) && (property.HasAttibute(typeof(DataMemberAttribute)))) 
      { 
       object value = default(object); 
       if (!property.PropertyType.Name.Equals(typeof(TrackableCollection<object>).Name)) 
       { 
        // If property is not a TrackableCollection object 
        // http://stackoverflow.com/questions/793714/how-can-i-fix-this-up-to-do-generic-conversion-to-nullablet 
        Type u = Nullable.GetUnderlyingType(property.PropertyType); 
        string jsonValue = kvp.Value != null ? kvp.Value.ToString() : null; 
        dynamic dynamicVal; 
        if (u != null) 
         dynamicVal = jsonValue == "null" ? null : Convert.ChangeType(jsonValue, u); 
        else if (kvp.Value is IDictionary<string, object>) 
         dynamicVal = Deserialize(kvp.Value as IDictionary<string, object>, property.PropertyType, serializer); 
        else 
         dynamicVal = Convert.ChangeType(jsonValue, property.PropertyType); 
        value = dynamicVal; 
       } 
       else 
       { 
        // If property is a TrackableCollection object 
        var dictionaries = (kvp.Value as IEnumerable).Cast<IDictionary<string, object>>(); 
        value = DeserializeCollection(dictionaries, property.PropertyType, serializer); 
       } 

       property.SetValue(entity, value, null); 
      } 
     } 
     return entity; 
    } 

    /// <summary> 
    /// Serializes TrackableCollection 
    /// </summary> 
    protected IList<IDictionary<string, object>> SerializeCollection(IEnumerable<object> collection, JavaScriptSerializer serializer) 
    { 
     var result = new List<IDictionary<string, object>>(); 
     foreach (object obj in collection) 
     { 
      result.Add(Serialize(obj, serializer)); 
     } 
     return result; 
    } 

    /// <summary> 
    /// Deserializes TrackableCollection 
    /// </summary> 
    protected object DeserializeCollection(IEnumerable<IDictionary<string, object>> dictionaries, Type propertyType, JavaScriptSerializer serializer) 
    { 
     object collection = Activator.CreateInstance(propertyType); // TrackableCollection<T> 
     Type genericType = propertyType.GetGenericArguments()[0]; // T 
     MethodInfo addMethod = collection.GetType().GetMethod("Add"); // Add(T object) 
     foreach (var dic in dictionaries) 
     { 
      addMethod.Invoke(collection, new [] { Deserialize(dic, genericType, serializer) }); 
     } 
     return collection; 
    } 

    /// <remarks> 
    /// http://stackoverflow.com/questions/159704/how-to-implement-custom-json-serialization-from-asp-net-web-service 
    /// </remarks> 
    public override IEnumerable<Type> SupportedTypes 
    { 
     get 
     { 
      IList<Type> result = new List<Type>(); 
      foreach (Assembly assembly in AppDomain.CurrentDomain.GetAssemblies()) 
      { 
       AssemblyBuilder dynamicAssemblyCheck = assembly as AssemblyBuilder; 
       if (dynamicAssemblyCheck == null) 
       { 
        try 
        { 
         foreach (Type type in assembly.GetExportedTypes()) 
         { 
          if ((type != typeof(IEntity)) && typeof(IEntity).IsAssignableFrom(type)) 
          { 
           result.Add(type); 
          } 
         } 
        } 
        catch(Exception){} // bad practice, i know, i know 
       } 
      } 
      return result; 
     } 
    } 
}