1

J'utilise IsolatedStorage dans Silverlight 3 pour stocker certains paramètres lorsqu'un utilisateur quitte une page hébergeant l'application.Silverlight IsolatedStorage techniques pour les fichiers volumineux?

Actuellement, j'utilise un DataContractSerializer pour écrire les paramètres dans un fichier. Dans certaines circonstances, le fichier résultant est assez volumineux, plus de 10 Mo (beaucoup de cette taille est due au sérialiseur lui-même et au XML qu'il génère). Cela produit des problèmes parce que

  • je dois demander l'espace supplémentaire de l'utilisateur
  • il est vraiment écrit lent les données dans un fichier

quelqu'un peut-il partager des stratégies qu'ils ont utilisées pour traiter plus fichiers dans IsolatedStorage? Comment déterminez-vous la quantité probable d'espace disque dont vous aurez besoin?

  • utilisez-vous un DataContract ou Xml Serializer et puis compresser le résultat avant de sauvegarder? Ou utilisez-vous une sorte de sérialisation binaire/personnalisée? Si oui, avez-vous gagné beaucoup d'espace ou de temps?
  • Existe-t-il un moyen de déclarer que votre application nécessite un certain quota, de sorte que l'utilisateur n'ait pas à être invité à un point arbitraire? Personnellement, je n'aime pas écrire de grandes quantités de données dans un fichier comme celui-ci, mais j'ai besoin de connaître toutes les options disponibles avant d'expliquer les problèmes à un chef de produit et de les persuader de changer les exigences.

    Merci!

  • Répondre

    4

    slugster,

    Vous pouvez envisager de passer à la place XMLSerializer. Voici ce que j'ai déterminé avec le temps:

    Les classes XMLSerializer et DataContractSerializer fournissent un moyen simple de sérialiser et de désérialiser les graphes d'objets vers et à partir de XML.

    Les principales différences sont les suivantes: 1.

    XMLSerializer a charge beaucoup plus petite que DCS si vous utilisez [XmlAttribute] au lieu de [XmlElement]
    DCS stocker toujours des valeurs comme éléments
    2.
    DCS est " opt-in "plutôt que" opt-out "
    Avec DCS vous marquez explicitement ce que vous voulez sérialiser avec [DataMember]
    Avec DCS vous pouvez sérialiser n'importe quel champ ou propriété, même s'ils sont marqués protégés ou privés
    Avec DCS vous pouvez utiliser [IgnoreDataMember] pour avoir le sérialiseur ignorer certaines propriétés
    Avec des propriétés publiques XMLSerializer sont sérialisés, et ont besoin d'être setters désérialisée
    Avec XmlSerializer, vous pouvez utiliser [XmlIgnore] pour que le sérialiseur ignorer les propriétés publiques
    3.
    CONNAÎTRE! DCS.ReadObject ne remet pas les constructeurs lors de la désérialisation
    Si vous devez effectuer l'initialisation, DCS prend en charge les crochets de rappel suivants:
    [OnDeserializing], [OnDeserialized], [OnSerializing], [OnSerialized]
    (également utile pour gérer les problèmes de versioning)

    Si vous voulez avoir la possibilité de basculer entre les deux serializers, vous pouvez utiliser les deux ensembles d'attributs simultanément, comme dans:

    [DataContract] 
    [XmlRoot] 
        public class ProfilePerson : NotifyPropertyChanges 
        { 
    [XmlAttribute] 
    [DataMember] 
         public string FirstName { get { return m_FirstName; } set { SetProperty(ref m_FirstName, value); } } 
         private string m_FirstName; 
    [XmlElement] 
    [DataMember] 
         public PersonLocation Location { get { return m_Location; } set { SetProperty(ref m_Location, value); } } 
         private PersonLocation m_Location = new PersonLocation(); // Should change over time 
    [XmlIgnore] 
    [IgnoreDataMember] 
         public Profile ParentProfile { get { return m_ParentProfile; } set { SetProperty(ref m_ParentProfile, value); } } 
         private Profile m_ParentProfile = null; 
    
         public ProfilePerson() 
         { 
         } 
        } 
    

    aussi, consultez ma classe sérialiseur qui peut basculer entre les deux:

    using System; 
    using System.IO; 
    using System.Runtime.Serialization; 
    using System.Text; 
    using System.Xml; 
    using System.Xml.Serialization; 
    
    namespace ClassLibrary 
    { 
        // Instantiate this class to serialize objects using either XmlSerializer or DataContractSerializer 
        internal class Serializer 
        { 
         private readonly bool m_bDCS; 
    
         internal Serializer(bool bDCS) 
         { 
          m_bDCS = bDCS; 
         } 
    
         internal TT Deserialize<TT>(string input) 
         { 
          MemoryStream stream = new MemoryStream(input.ToByteArray()); 
          if (m_bDCS) 
          { 
           DataContractSerializer dc = new DataContractSerializer(typeof(TT)); 
           return (TT)dc.ReadObject(stream); 
          } 
          else 
          { 
           XmlSerializer xs = new XmlSerializer(typeof(TT)); 
           return (TT)xs.Deserialize(stream); 
          } 
         } 
    
         internal string Serialize<TT>(object obj) 
         { 
          MemoryStream stream = new MemoryStream(); 
          if (m_bDCS) 
          { 
           DataContractSerializer dc = new DataContractSerializer(typeof(TT)); 
           dc.WriteObject(stream, obj); 
          } 
          else 
          { 
           XmlSerializer xs = new XmlSerializer(typeof(TT)); 
           xs.Serialize(stream, obj); 
          } 
    
          // be aware that the Unicode Byte-Order Mark will be at the front of the string 
          return stream.ToArray().ToUtfString(); 
         } 
    
         internal string SerializeToString<TT>(object obj) 
         { 
          StringBuilder builder = new StringBuilder(); 
          XmlWriter xmlWriter = XmlWriter.Create(builder); 
          if (m_bDCS) 
          { 
           DataContractSerializer dc = new DataContractSerializer(typeof(TT)); 
           dc.WriteObject(xmlWriter, obj); 
          } 
          else 
          { 
           XmlSerializer xs = new XmlSerializer(typeof(TT)); 
           xs.Serialize(xmlWriter, obj); 
          } 
    
          string xml = builder.ToString(); 
          xml = RegexHelper.ReplacePattern(xml, RegexHelper.WildcardToPattern("<?xml*>", WildcardSearch.Anywhere), string.Empty); 
          xml = RegexHelper.ReplacePattern(xml, RegexHelper.WildcardToPattern(" xmlns:*\"*\"", WildcardSearch.Anywhere), string.Empty); 
          xml = xml.Replace(Environment.NewLine + " ", string.Empty); 
          xml = xml.Replace(Environment.NewLine, string.Empty); 
          return xml; 
         } 
        } 
    } 
    

    Bonne chance, Jim
    McCurdy

    Face To Face Software et YinYangMoney

    +0

    Merci Jim, bonne réponse. Malheureusement, je ne peux pas utiliser XmlSerializer en raison de problèmes d'espace de noms et d'objets identiques, d'où mon utilisation du DCS. Et le point # 3 sur le DCS était aussi bon, je suis sûr qu'il a attrapé quelques personnes dans le passé :) – slugster

    +1

    Jim, je sais que l'optimisation prématurée est la racine du plus mauvais, mais 'nouveau DataContractSerializer (typeof (TT)) 'et' new XmlSerializer (typeof (TT)) 'sont des opérations * très * coûteuses. Vous pouvez les mettre en cache dans un 'Dictionnaire statique ' etc si vous avez trouvé que ce code devenait lent. –

    +0

    Rob, Bonne observation sur la performance. Je vais apporter vos modifications suggérées dans mes applications. Merci ... –

    1

    Une autre alternative est de zipper le contenu de la sérialisation XML. Nous avons également une sérialisation importante avec un taux de compression approximatif de 10 à 1. Bien sûr, la compression peut prendre un peu de CPU pour faire sa magie. Nous générons la compression dans un thread pour nous assurer que l'interface utilisateur ne ralentit pas. Nous utilisons un SharpZipLib modifié qui fonctionne sous Silverlight.

    +0

    J'ai implémenté le zipping sur le flux sérialisé aujourd'hui, et cela a certainement fait une différence notable - un fichier auparavant de 10.1 MB a été réduit à 260KB, et il a fallu environ 3 secondes pour sérialiser, compresser et sauvegarder les données. En traitant de petites quantités de données, il n'y avait aucune augmentation perceptible de temps pour faire l'étape supplémentaire de compresser les données, de sorte que la transition loin de la page prenait bien moins d'une seconde à se produire. Dans l'ensemble, je dois dire que zipper toutes les données était une bonne option. – slugster

    1

    Une autre option consiste à sérialiser en json. Je ne connais pas les performances, mais Je viens de comparer la sortie lors de la sérialisation d'une liste assez complexe d'entités à json vs xml, et json est beaucoup plus compact. En utilisant json, la chaîne résultante était 1301303 octets. Avec xml, 2429630. Donc, c'est presque la moitié de la taille en utilisant JSON. Voici la classe d'assistance que j'utilise lors de la sérialisation/désérialisation de JSON.

    EDIT
    J'ai fait quelques tests de performance, et il se fait que JSON est plus rapide aussi bien. Avec XML, la sérialisation de 10000 objets a pris 636 millisecondes, avec json seulement 257. Est-ce que quelqu'un sait s'il y a des raisons de ne pas choisir json sur xml?

    EDIT
    testé à nouveau, avec des données réelles cette fois:
    (1000 objets)
    non compressé JSON: 605 kb
    non compressé xml: (!) 3,53 MB
    Zippé JSON: 28, 5 kb
    xml zippé: 69,9 kb
    Performance lors de l'utilisation sérialiseur préinitialisée:
    JSON: ~ 350 ms
    xml: ~ 120 ms

    using System; 
    using System.Net; 
    using System.Windows; 
    using System.Windows.Controls; 
    using System.Windows.Documents; 
    using System.Windows.Ink; 
    using System.Windows.Input; 
    using System.Windows.Media; 
    using System.Windows.Media.Animation; 
    using System.Windows.Shapes; 
    using System.IO; 
    using System.Text; 
    using System.Runtime.Serialization.Json; 
    
    namespace GLS.Gui.Helper 
    { 
        public static class SerializationHelper 
        { 
         public static string SerializeToJsonString(object objectToSerialize) 
         { 
          using (MemoryStream ms = new MemoryStream()) 
          { 
           DataContractJsonSerializer serializer = new DataContractJsonSerializer(objectToSerialize.GetType()); 
           serializer.WriteObject(ms, objectToSerialize); 
           ms.Position = 0; 
    
           using (StreamReader reader = new StreamReader(ms)) 
           { 
            return reader.ReadToEnd(); 
           } 
          } 
         } 
         public static T Deserialize<T>(string jsonString) 
         { 
          using (MemoryStream ms = new MemoryStream(Encoding.Unicode.GetBytes(jsonString))) 
          { 
           DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(T)); 
    
           return (T)serializer.ReadObject(ms); 
          } 
         } 
    
        } 
    } 
    
    +0

    Par curiosité, avez-vous comparé les tailles de fichier de * zipped * xml et de json? –

    +0

    Je l'ai fait, et les résultats étaient à peu près les mêmes. Mais c'était avec des données de test seulement. Mes entités de données ont été nommées "entité 1", "entité 2", etc. jusqu'à 10000. Avec autant de données répétées, j'ai obtenu un taux de compression d'environ 99%. Je pense que le fichier zippé json était d'environ 13ko et le xml était d'environ 28ko. Mais pour obtenir des résultats utiles, je devrais commencer à jouer avec des données réelles, ou au moins randomiser des noms, des collections d'enfants, etc. Et je suis juste un peu trop paresseux pour le faire. :) –

    +0

    Il s'avère que je n'étais pas trop paresseux après tout. Voir les résultats du test dans la réponse éditée. –

    1

    J'ai une classe sérialiseur binaire compacte pour Silverlight et .NET qui crée des représentations raisonnablement compactes d'un graphe d'objet - je l'ai dû construire pour la même raison (et les frais d'envoi des choses sur le fil à mon WCF un service). Vous pouvez trouver le code et une description plus détaillée sur mon blog.

    0

    Un autre sérialiseur open source est SharpSerializer. Il peut sérialiser même des structures très compliquées au format binaire.Il n'est pas nécessaire de les marquer avant avec les attributs. De plus, il peut sérialiser les données en Xml, c'est-à-dire pour le débogage.

    Questions connexes