Bienvenue à Blogs CodeS-SourceS Identification | Inscription | Aide

[WP7] Besoin d’avoir des données en cache

Les développeurs ASP.NET ont l’habitude de mettre des données en cache pour éviter de requêter a chaque fois la base de données. Et il est toujours utilie de penser que vos utilisateurs mobiles n’ont pas troujours une super connexion 3G/WIFI et un forfait ilimité. Il est donc utile de mettre des données en cache, lors d’un développement WP7, le reflexe à avoir pour ajouter de la persitence à des données est l’isolatedstorage.

Si comme en ASP.NET, vous souhaitez ajouter une expiration, c’est a dire que l’objet n’est disponible que pendant une certaine durée, vous devez passer par du code spécifique, il est n’est pas possible de le faire en standard.

Pour réaliser cette fonctionnalité, il faut développer un wrapper, donc voici les étapes de code:

La première etape est de créer une classe Cache qui contient un singleton, il contient également les valeurs pour NoAbsoluteExpiration et NoSlidingExpiration.

    public class Cache
    {
        public static readonly DateTime NoAbsoluteExpiration = DateTime.MaxValue;
        public static readonly TimeSpan NoSlidingExpiration = TimeSpan.Zero;

// Accès à l'isolatedstorage
        readonly IsolatedStorageFile _myStore = IsolatedStorageFile.GetUserStoreForApplication();

// singleton
        private static Cache _current;
        public static Cache Current
        {
            get { return _current ?? (_current = new Cache()); }
        }

Comme l’api ASP.NET le propose, nous ajoutons une méthode pour ajouter un objet au cache et définir les expirations.

Un objet en cache est défini par une clef (pour le retrouver),  l’objet en lui même qui sera sérialisé et les éléments d’expiration.

/// <summary>
/// Adds the specified key.
/// </summary>
/// <param name="key">The key.</param>
/// <param name="value">The value.</param>
/// <param name="absoluteExpiration">The absolute expiration.</param>
/// <param name="slidingExpiration">The sliding expiration.</param>
public void Add(string key, object value, DateTime absoluteExpiration, TimeSpan slidingExpiration)
{
    lock (_sync)
    {
        if (Contains(key))
            Remove(key);

        if (absoluteExpiration == NoAbsoluteExpiration)
            Add(key, DateTime.UtcNow + slidingExpiration, value);
        if (slidingExpiration == NoSlidingExpiration)
            Add(key, absoluteExpiration, value);
    }
}

Puis nous ajoutons concrètement l’objet dans l’isolated storage.

Pour chaque key, un répertoire avec son nom est créé, puis dans ce répertoire est créé un fichier nommer avec la date d’expiration au format Windows file time UTC (Une heure de fichier Windows est une valeur 64 bits qui représente le nombre d'intervalles de 100 nanosecondes qui se sont écoulés depuis 12:00 minuit, le 1er janvier 1601 après Jésus-Christ(notre ère) en temps universel coordonné (UTC)).

 

/// <summary>
/// Adds the specified key.
/// </summary>
/// <param name="key">The key.</param>
/// <param name="expirationDate">The expiration date.</param>
/// <param name="value">The value.</param>
private void Add(string key, DateTime expirationDate, object value)
{
    lock (_sync)
    {
        if (!_myStore.DirectoryExists(key))
            _myStore.CreateDirectory(key);
        else
        {
	// Si la key existe déja, on supprime le répertoire et le fichier
            string currentFile = _myStore.GetFileNames(string.Format("{0}\\*.cache", key).FirstOrDefault();
            if (currentFile != null)
                _myStore.DeleteFile(string.Format("{0}\\{1}", key, currentFile));
            _myStore.DeleteDirectory(key);
            _myStore.CreateDirectory(key);
        }

        string fileName = string.Format("{0}\\{1}.cache", key, expirationDate.ToFileTimeUtc());


        if (_myStore.FileExists(fileName))
            _myStore.DeleteFile(fileName);

      using (var isolatedStorageFileStream = new IsolatedStorageFileStream(fileName, FileMode.OpenOrCreate, _myStore))
         {
           DataContractSerializer s = new DataContractSerializer(value.GetType());
           s.WriteObject(isolatedStorageFileStream, value);
         }
    }
}

Puis la dernière étape est de recuperer la valeur dans le cache, si le cache a expiré, la méthode retourne null.

/// <summary>
/// Gets the specified key.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="key">The key.</param>
/// <returns></returns>
public T Get<T>(string key)
{
    lock (_sync)
    {
// Récuperation du fichier
        string currentFile =  _myStore.GetFileNames(string.Format("{0}\\*.cache", key).FirstOrDefault();
        if (currentFile != null)
        {
// verification si le cache n'a pas expiré
            var expirationDate =
                DateTime.FromFileTimeUtc(long.Parse(Path.GetFileNameWithoutExtension(currentFile)));
            if (expirationDate >= DateTime.UtcNow)
            {
// Deserialisation de l'objet
                using (var isolatedStorageFileStream = new IsolatedStorageFileStream(
string.Format(@"{0}\{1}", key, currentFile), FileMode.Open, _myStore))
                {
                    DataContractSerializer s = new DataContractSerializer(typeof(T));
                    var value = s.ReadObject(isolatedStorageFileStream);
                    isolatedStorageFileStream.Close();
                    return (T)value;
                }
            }
// Si la date d'expiration est dépassé, on supprime le fichier de l'isolatedstorage
            Remove(key);
        }
        return default(T);
    }
}

Maintenant que nous avons les bases d’un sytème de cache, voici comment nous pouvons l’utiliser facilement et en y mettans un peut de Rx dans tout ca. Dans cette exemple, nous avons une methode GetAll qui renvoie des données depuis un service WCF. Le MyServiceClient a été généré par Visual Studio.

public void GetAll(Action<ObservableCollection<MyEntity>> callback)
{
    // Verification si l'objet est en cache et n'a pas expiré
    if (Cache.Current.Contains("KEY1"))
    {
        // Lecture du cache dans un nouveau thread, et appel du callback dans le dispatcher thread
        Observable.Start(() =>
                            Cache.Current.Get<ObservableCollection<MyEntity>>("KEY1"), Scheduler.ThreadPool).
            ObserveOn(Scheduler.Dispatcher).Subscribe(callback);
        return;
    }
    // Création du client pour le service WCF
    MyServiceClient client = new MyServiceClient();
    Observable.FromEvent<GetAllCompletedEventArgs>(client, "GetAllCompleted")
            .ObserveOn(Scheduler.ThreadPool)
            .Select(s =>
            {
                // Dans un nouveau thread, on ajoute l'objet recu par WCF dans le cache,
                	//sa durée de vie est de 1 jour
                if (s.EventArgs.Error == null)
                {
                    Cache.Current.Add("KEY1", s.EventArgs.Result, Cache.NoAbsoluteExpiration, TimeSpan.FromDays(1));
                }
                return s;
            })
        .ObserveOn(Scheduler.Dispatcher).Subscribe(s =>
        {
            // Puis dans le dispatcher thread, on appel le callback
            callback(s.EventArgs.Result);
        });
    // Appel de la méthode WCF
    client.GetAllAsync();
}

Si vous n’avez que des “settings” à sauvegarder, je vous conseil d’utiliser les API standard:

IsolatedStorageSettings.ApplicationSettings.Add("key", value);
IsolatedStorageSettings.ApplicationSettings.Save();

Ce code est utilisé pour le projet Warnygo, et est bien sur disponible au complet: Phone7.Fx.Preview.zip

Si vous avez des retours, n’hésitez pas !

Publié mercredi 1 septembre 2010 15:12 par Nicolas
Classé sous : ,
Ce post vous a plu ? Ajoutez le dans vos favoris pour ne pas perdre de temps à le retrouver le jour où vous en aurez besoin :

Commentaires

# re: [WP7] Besoin d’avoir des données en cache

Intéressant ! Merci beaucoup (^__^)

mercredi 1 septembre 2010 19:06 by Danuz
Les commentaires anonymes sont désactivés

Les 10 derniers blogs postés

- Merci par Blog de Jérémy Jeanson le 10-01-2019, 20:47

- Office 365: Script PowerShell pour auditer l’usage des Office Groups de votre tenant par Blog Technique de Romelard Fabrice le 04-26-2019, 11:02

- Office 365: Script PowerShell pour auditer l’usage de Microsoft Teams de votre tenant par Blog Technique de Romelard Fabrice le 04-26-2019, 10:39

- Office 365: Script PowerShell pour auditer l’usage de OneDrive for Business de votre tenant par Blog Technique de Romelard Fabrice le 04-25-2019, 15:13

- Office 365: Script PowerShell pour auditer l’usage de SharePoint Online de votre tenant par Blog Technique de Romelard Fabrice le 02-27-2019, 13:39

- Office 365: Script PowerShell pour auditer l’usage d’Exchange Online de votre tenant par Blog Technique de Romelard Fabrice le 02-25-2019, 15:07

- Office 365: Script PowerShell pour auditer le contenu de son Office 365 Stream Portal par Blog Technique de Romelard Fabrice le 02-21-2019, 17:56

- Office 365: Script PowerShell pour auditer le contenu de son Office 365 Video Portal par Blog Technique de Romelard Fabrice le 02-18-2019, 18:56

- Office 365: Script PowerShell pour extraire les Audit Log basés sur des filtres fournis par Blog Technique de Romelard Fabrice le 01-28-2019, 16:13

- SharePoint Online: Script PowerShell pour désactiver l’Option IRM des sites SPO non autorisés par Blog Technique de Romelard Fabrice le 12-14-2018, 13:01