Accueil Nos publications Blog Windows Store Apps et leurs données

Windows Store Apps et leurs données

windows 8 logoWindows Store Apps, temporairement « Modern UI » Apps, anciennement Metro, une multitude de noms pour les nouvelles applications Windows. Mais il y a aussi une multitude de façons de sauvegarder nos données quand nous utilisons les APIs de ces applications – il y a plus de possibilités et plus de facilités intégrées que vous ne pouvez l’imaginer !

Il est temps de les présenter et de vous aider à choisir entre toutes ces APIs. Commençons avec…

Le Tableau qui vous fait économiser des heures !

Nom Recommandé pour Limitations API (Windows.Storage.?)
Roaming Storage Petits fichiers exclusifs   à l’application 100Ko au total (à présent) ApplicationData
Roaming Settings Configuration indépendante de   l’appareil 100Ko au total + 8Ko/setting (64   pour les composites) ApplicationData
Roaming Settings   [priorité haute] Endroit de lecture 8Ko ApplicationData
Local Storage Gros fichiers exclusifs à   l’application + bases de données locales ApplicationData
Local Settings Configuration spécifique   à l’appareil 8Ko/setting (64 pour   composites) ApplicationData
Temp Storage Fichiers temporaires Il sera supprimé suite à un nettoyage de disque ApplicationData
Téléchargements Fichiers téléchargés   suite à une action de l’utilisateur DownloadsFolder
AccessCache Fichiers choisis par FilePicker AccessCache
Credentials Locker Informations de connexion Windows.Security.
Credentials
Librairies Fichiers à partager avec d’autres   applications (principalement locales) Risques de sécurité KnownFolders
Web/Cloud Données à partager avec   d’autres applications distantes Connectivité requise Ca dépend mais souvent   Microsoft.Live ou System.ServiceModel
HTML5 Réutiliser du code existant de votre   application web Applications en JavaScript/ HTML seulement IndexedDB/local Storage/AppCache

Limitations Additionnelles

Limitation pour tout : bien sûr tout ce que vous sauvegardez doit être sérialisable d’une façon ou d’une autre (voir DataContractSerializer pour la façon habituelle de sérialiser les objets).

En plus, les 8 premières façons de sauvegarder l’état (de Local Storage jusqu’à Credentials Locker) sont exclusifs à l’application, mais il y a certaines solutions de contournement qui seront présentées plus tard !

En détail

Le tableau est peut-être un peu trop dense ? Pas de panique, tout sera expliqué !

Roaming Storage

C’est le stockage des fichiers exclusifs à l’application. Il est presque identique à l’Isolated Storage de Silverlight (et Windows Phone),  avec la fonctionnalité additionnelle d’être synchronisé avec tous les appareils où l’utilisateur a installé l’application ! Ça a l’air d’être magique mais c’est en fait assez limité : nous ne pouvons aujourd’hui synchroniser que 100Ko de données et la synchronisation ne sera pas faite très rapidement (les synchronisations sont regroupées toutes les quelques minutes pour préserver la batterie).

Ces limitations rendent Roaming Storage presque inutile, mais je vous montre un exemple quand même, avec bien sûr, l’utilisation fréquente du mot clé await pour les opérations asynchrones :

[csharp]
var roamingFolder = ApplicationData.Current.RoamingFolder;
// write
var file = await roamingFolder.CreateFileAsync("something.doc",
CreationCollisionOption.ReplaceExisting);
await FileIO.WriteTextAsync(file, "sample text");
// read
var anotherFile = await roamingFolder.GetFileAsync("somethingElse.doc");
string text = await FileIO.ReadTextAsync(anotherFile);
[/csharp]

Bien sûr, si nous voulons sauvegarder un objet complexe, nous devons faire attention à sa sérialisation (comme déjà mentionné).

Roaming Settings

Etre limité à 100Ko pour les fichiers ce n’est pas très pratique, mais c’est une contrainte acceptable pour la configuration de l’utilisateur. Roaming Settings est plutôt un raccourci pour sauvegarder des objets relativement petits. Je vous conseille de l’utiliser pour presque toute la configuration et les options de l’utilisateur. L’expérience de voir plusieurs appareils se comporter de la même façon sans avoir besoin de les reconfigurer est vraiment très agréable.

[csharp]
ApplicationData.Current.RoamingSettings.Values["message"] = "So@t!";
[/csharp]

Nous avons la possibilité de grouper nos propriétés en “Containers”. On en verra un exemple dans la section suivante. Nous pouvons  même avoir un système de versions de nos données (expliqué en partie dans cet article).

Roaming Settings [Priorité Haute]

Et si on avait une application de lecture de vidéo et qu’on voulait synchroniser la position de lecture très rapidement ? Comme ça, l’utilisateur peut commencer à lire la vidéo sur sa tablette et continuer la lecture sur son ordinateur. Les API nous offrent une solution : il suffit de nommer notre propriété à synchroniser « HighPriority » et elle se synchronisera dans 1 minute au maximum. Si nous avons plusieurs informations à synchroniser, nous pouvons créer une clé composite qui sera synchronisée de façon atomique (comme une seule opération, qui ne peut pas se faire partiellement) :

[csharp]
var composite = new ApplicationDataCompositeValue();
composite["book"] = "Hitchiker’s Guide to the Galaxy";
composite["page"] = 42;
ApplicationData.Current.RoamingSettings.Values["HighPriority"] = composite;
[/csharp]

Local Storage

Local Storage, en combinaison avec d’autres techniques, peut servir pour sauvegarder la plupart des données de l’utilisateur. Nous pouvons héberger de petites bases de données dedans et il est aussi utile pour héberger les documents de l’application (exemple : pour sauvegarder les diagrammes qu’un utilisateur crée avec une application de diagrammes). Par contre, il n’offre pas de synchronisation automatique, ce qui signifie qu’on doit l’implémenter nous-mêmes.

Son utilisation est identique à Roaming Storage, il faut juste remplacer le mot « Roaming » par le mot « Local ».

Local Settings

Sur le même principe que Local Storage, les Local Settings servent à sauvegarder des objets relativement petits. Mais, vu que les Roaming Settings offrent plus de fonctionnalités, il vaut mieux garder les Local Settings pour de la configuration qui n’aurait pas de sens sur un autre appareil.

Temporary Storage

Le stockage temporaire marche de la même façon que le stockage local, mais il sera supprimé si l’utilisateur décide de supprimer ses données temporaires. C’est donc utile pour les fichiers qui ont une durée de vie courte, comme par exemple les fichiers générés par un encodage de vidéo.

Il vaut aussi mieux le vider avec un Background Task qui se déclenchera de façon périodique. Les Background Tasks ne sont pas le sujet de cet article, mais vous pouvez avoir une introduction à leur utilisation pour la gestion de données à la 37 ème minute de la présentation qui a inspiré cet article.

Téléchargements

Rien ne nous empêche de sauvegarder dans le Stockage Local un fichier téléchargé depuis internet. Mais, si ce fichier est d’un type utilisable par d’autres applications, l’utilisateur s’attend à ce qu’il soit téléchargé dans son répertoire de Téléchargements. Les fichiers dans ce répertoire sont accessibles par l’application qui les a créés, mais aussi par les applications desktop (après confirmation de l’utilisateur).

Access Cache

Pour des raisons de sécurité, la plupart des applications Windows Store ne doivent pas avoir accès aux documents de l’utilisateur. Une application de messagerie, par exemple, n’a pas besoin d’avoir accès total aux Documents pour envoyer une pièce jointe. L’utilisateur peut utiliser le File Picker pour choisir un fichier – c’est seulement suite à cette action de l’utilisateur que l’application obtient l’accès à cette ressource. Mais la prochaine fois qu’elle sera ouverte, elle n’aura plus accès au fichier. Alors, comment pouvons-nous implémenter une fonctionnalité de type « Fichiers Récents » sans demander chaque fois à l’utilisateur de choisir son fichier ?

C’est simple : nous pouvons sauvegarder les droits d’accès à ce fichier dans l’Access Cache :

[csharp]
var file = await Pickers.FileOpenPicker.PickSingleFileAsync();
string fileToken;
if (file != null)
fileToken = StorageApplicationPermissions.FutureAccessList.Add(file);

// later
await StorageApplicationPermissions.FutureAccessList.GetFileAsync(fileToken);
[/csharp]

Credentials Locker

Ça aurait été si simple si notre application pouvait contrôler toutes les données nécessaires à son fonctionnement. Mais ce n’est pas le cas. Souvent les ressources nécessitent une authentification explicite parce qu’elles sont visibles par d’autres clients que les applications Windows (un site web, une application iPhone etc). Dans ce cas, il est pratique de sauvegarder les informations de connexion pour ne pas avoir besoin de les re-saisir à chaque fois.

Nous pouvons, bien évidemment, implémenter cette fonctionnalité avec les Roaming Settings, mais dans ce cas nous devons nous occuper du chiffrement. La classe Password Vault fait le nécessaire de façon transparente :

[csharp]
var vault = new PasswordVault();
vault.Add(new PasswordCredential("primaryAccount", "tec-goblin", "superPassword");

// read
var credentials = vault.Retrieve("primaryAccount", "tec-goblin");
[/csharp]

Rien de plus simple ! Mais parfois les mêmes informations de connexion sont utilisées pour plusieurs applications très différentes – l’exemple le plus fréquent c’est Active Directory. Pour gérer ce scénario il est préférable de demander à l’utilisateur de choisir parmi les informations déjà associées à son profil, en utilisant Credential Picker.

Librairies

Ok, le FilePicker c’est bien, mais il y a des applications qui font leur propre présentation des fichiers de l’utilisateur : prenez par exemple un lecteur de musique. Ces applications ont vraiment besoin d’avoir accès à toute la librairie correspondante. Cet accès doit alors être déclaré au niveau de l’application. Attention : ne la déclarez pas si vous n’en avez pas besoin, particulièrement si vous utilisez JavaScript, parce que vous exposez une surface beaucoup plus grande à un éventuel hacker. C’est une chose de se faire supprimer ou voler les fichiers d’une application mais c’en est une autre d’exposer tous les documents de l’utilisateur.

Une fois l’accès donné, nous pouvons lire et modifier les contenus de cette librairie, et même utiliser le moteur de recherche et l’indexation du système pour présenter les résultats. Un exemple assez simple est le suivant :

[csharp]
var documents = KnownFolders.DocumentsLibrary;
var orderByDateQuery = Windows.Storage.Search.CommonFileQuery.OrderByDate;
var files;
if(documents.IsCommonFileQuerySupported(orderByDateQuery)) {
files = documents.GetFilesAsync(orderByDateQuery);
} else {
files = documents.GetFilesAsync();
}
[/csharp]

Web/Cloud

Si nous voulons synchroniser des données qui dépassent la taille permise par Roaming Storage, nous n’avons qu’une solution : utiliser explicitement des services web ou un stockage sur le cloud. Le stockage le plus simple, vu que l’utilisateur y est déjà connecté, est Live/Skydrive. Dans le cas le plus simple, c’est présenté de la même façon que les dossiers du système local : l’utilisateur peut choisir avec FilePicker un endroit sur Skydrive et nous sauvegardons dans AccessCache nos droits d’accès à cet endroit.

Cette solution n’est pas pratique en cas de connectivité interrompue. Nous sommes obligés de sauvegarder en local quand il n’y a pas de réseau. L’idéal est d’avoir aussi un Background Task qui synchronisera les données une fois que la connectivité sera rétablie. Les Background Task ont déjà été mentionnées lors de la description du Temporary Storage.

Pour rester dans le périmètre de cet article, je vous laisse faire vos propres recherches sur l’accès réseau dans les applications Windows Store.

Quand Sauvegarder ?

qr_e7a1bC’est excellent tout ça, mais quand devons-nous sauvegarder ou rafraîchir nos données ? Les bonnes pratiques de Windows Store ne sont pas compliquées :

  • La configuration est sauvegardée immédiatement, sans confirmation – mais les actions doivent être facilement annulables.
  • On trouve encore des applications avec un bouton « Enregistrer » pour les données. Ce n’est pas forcement recommandé, mais c’est la seule solution si nous avons ouvert un fichier sur Skydrive, que nous n’avons pas accès à internet et pas implémenté une synchronisation automatique une fois reconnecté.

L’idéal est d’avoir la possibilité d’annuler toutes les actions, mais enregistrer périodiquement. Les modifications non encore enregistrées doivent être sauvegardées quand l’application est Suspendue (pas visible), et synchronisées avec le Cloud une fois la connectivité rétablie.

Le code de SuspensionManager, inclus avec les projets-modèles de Visual Studio, est un bon point pour commencer à gérer la suspension d’une application.

  • Il est intéressant de sauvegarder la date de la dernière suspension. Quand l’application sera réactivée, nous pourrons vérifier si beaucoup de temps est passé pour déterminer si nous devrons resynchroniser les données. Peut-être entre temps l’utilisateur a laissé sa tablette de côté et a ouvert l’application sur son ordinateur, continuant ainsi son travail.

Cette technique n’est intéressante que pour les données dans Local Storage – les Roaming Settings et Credentials seront probablement déjà synchronisés.

Epilogue

Pour des raisons de sécurité et de performance, les APIs de sauvegarde de Windows Store sont nombreuses. Par contre, une fois que la bonne API est choisie, le code à écrire est extrêmement court et élégant, offrant des fonctionnalités dont on n’osait à peine rêver jusqu’à maintenant. Ceci pourrait être généralisé pour presque tous les aspects de développement pour Windows Store : il y a beaucoup de scénarios à penser pour rendre une application très agréable pour l’utilisateur – des scénarios qui vont au-delà de ce que l’on attend d’une application de bureau. Heureusement les APIs nécessaires sont là et plutôt bien implémentées.

Il ne faut pas oublier l’existence des subtilités (ex : que se passe t-il si notre Roaming Storage dépasse la limite actuelle de 100Ko ?), mais vous trouverez la réponse sur MSDN et les blogs de Microsoft. Vous pouvez aussi laisser un mot au-dessous de l’article, il y a des fortes chances qu’un So@tien connaisse déjà la réponse à votre question.

Il ne reste qu’à implémenter votre idée !