Partager via



Septembre 2015

Volume 30, numéro 9

Cet article a fait l'objet d'une traduction automatique.

Applications mobiles connectées au cloud - Conception d’une application Xamarin avec l'authentification et un support hors connexion

Par Kraig Brockschmidt

Comme décrit dans la première partie de cette série en deux parties, « Créer un Web Service avec Azure Web Apps et WebJobs » (msdn.microsoft.com/magazine/mt185572), en août émettre, beaucoup d'applications mobiles aujourd'hui est connectés à un ou plusieurs services Web qui fournissent des données utiles et intéressantes. Bien qu'il soit facile de simplement des appels API REST directs à ces services et les réponses de processus dans le client, une telle approche peut être coûteuse en termes de batterie, la bande passante et la limitation des limitations imposées par les différents services. Également, les performances peuvent diminuer sur un matériel bas de gamme. Il est judicieux, puis, pour alléger le travail à un back-end personnalisé, comme nous montrent avec le projet « Altostratus », nous allons aborder dans cet article.

Le Altostratus back-end, partie 1, régulièrement rassemble et normalise « conversations » de StackOverflow et Twitter (juste à utiliser des sources de données) et les stocke dans une base de données Microsoft Azure. Cela signifie que les données exactes requises par les clients peuvent être pris en charge par le serveur principal directement, ce qui nous permet de faire évoluer le serveur principal dans Azure pour s'adapter à n'importe quel nombre de clients sans atteindre les limites de limitation des fournisseurs d'origine. En normalisant les données sur le serveur principal pour correspondre à ce que le client a besoin, nous optimisons également exchange de données via l'API Web, la conservation des ressources rares jamais des périphériques mobiles.

Dans cet article, nous allons aborder les détails de l'application cliente (voir Figure 1). Nous allons commencer avec l'architecture de l'application pour définir le contexte global, dans notre utilisation de Xamarin et Xamarin.Forms, l'authentification avec le serveur principal, créer le cache hors connexion, puis création avec Xamarin sur Team Foundation Server (TFS) et Visual Studio Online.

Le Xamarin Mobile application s'exécutant sur un Tablet PC Android (à gauche), un kit de développement Windows Phone (au milieu) et un iPhone (à droite)
Figure 1 la Xamarin Mobile application exécutée sur un Tablet PC Android (à gauche), un kit de développement Windows Phone (au milieu) et un iPhone (à droite)

Architecture d'application client

L'application cliente a trois pages principales ou des vues : Configuration, accueil et article, ces noms de partage dont les classes (consultez Figure 2). Une page de connexion secondaire sans interface utilisateur et est simplement l'hôte pour le fournisseur OAuth pages Web. À l'aide d'une structure de base Model-View-ViewModel (MVVM), chaque page principale, à l'exception de connexion a une classe de modèle de vue associée à gérer les relations de liaison entre les vues et les classes de modèle de données qui représentent des articles, des catégories et des paramètres de configuration (y compris une liste de fournisseurs d'authentification).

L'Architecture de l'application cliente Altostratus, affiche les noms des Classes principales impliquées (fichiers du projet correspondent à ces noms de classe sauf indication contraire)
Figure 2 l'Architecture de l'application cliente Altostratus, affiche les noms des Classes principales impliquées (fichiers du projet correspondent à ces noms de classe sauf indication contraire)

Remarque : Développeurs préfèrent souvent séparer les vues XAML dans une bibliothèque de classes portable [PCL] séparé les modèles de vue et d'autres classes, ce qui permet aux concepteurs de travailler indépendamment avec les vues dans des outils tels que Blend. Nous n'a pas de rendre la séparation de conserver la structure de projet simple et également parce que Blend ne fonctionne pas avec les contrôles dans Xamarin.Forms pour l'instant.)

Le modèle de données remplit toujours ces objets à partir d'une base de données SQLite local, qui est prédéfinie à la première exécution de l'application. Fin de la synchronisation avec le serveur, ce qui se passe dans le modèle de données est un processus simple de récupération de nouvelles données (aussi peu que possibles réduire le trafic réseau), mise à jour de la base de données avec ces données, toutes les anciennes données de nettoyage et de demander le modèle de données pour actualiser ses objets. Cela déclenche une mise à jour de l'interface utilisateur, grâce à la liaison de données avec les modèles de vue.

Lors d'une discussion plus tard, une série d'événements déclenche une synchronisation : une actualisation de bouton dans l'interface utilisateur, modifiez la configuration, l'authentification avec le serveur principal (qui Récupère une configuration enregistrée précédemment), la reprise de l'application après au moins 30 minutes et ainsi de suite. La synchronisation est la principale communication avec le serveur principal via son API Web, bien sûr, mais le serveur principal fournit également une API pour l'inscription d'un utilisateur, la récupération des paramètres d'un utilisateur authentifié et la mise à jour de ces paramètres lorsqu'un utilisateur authentifié modifie la configuration.

Xamarin.Forms pour un Client inter-plateformes

Comme vous l'avez peut-être lu dans le Magazine MSDN, Xamarin vous permet d'utiliser c# et Microsoft .NET Framework pour créer des applications pour Android, iOS et Windows, avec une grande quantité de code qui est partagé entre les plates-formes. (Pour une vue d'ensemble de notre configuration de développement, consultez la section ultérieure, « Construction avec Xamarin sur TFS et VSO ».) L'infrastructure Xamarin.Forms augmente ce montant supplémentaire en fournissant une solution de l'interface utilisateur commune pour XAML / C#. Avec Xamarin.Forms, le projet Altostratus partage plus de 95 % de son code dans une seule PCL. Le code de plate-forme spécifiques uniquement dans le projet, sont en fait, les bits pour le démarrage provenant des modèles de projet, les convertisseurs pour les pages de connexion qui traitent un contrôle de navigateur Web et quelques lignes de code pour copier la base de données SQLite prérempli dans l'emplacement approprié en lecture-écriture dans le stockage local.

Notez qu'un projet Xamarin peut également être configuré pour utiliser un projet partagé, et non une PCL. Toutefois, Xamarin recommande d'utiliser une PCL et constituent le principal avantage avec Altostratus que nous utilisons la PCL même dans une application console Win32 pour créer la base de données prédéfinie. Cela signifie que nous ne dupliquent pas de code de base de données à cette fin, et le programme initialiseur sera toujours synchronisé avec le reste de l'application.

Penser que code partagé ne réduit pas beaucoup l'effort nécessaire pour tester l'application sur chaque plateforme cible ; Cette partie de votre processus prendra environ tant qu'elle serait si vous avez écrit chaque application en mode natif. En outre, Xamarin.Forms étant relativement nouveau, vous pouvez trouver des bogues spécifiques à la plateforme ou autres comportements que vous devrez gérer dans votre code. Pour plus d'informations sur quelques que nous avons trouvé lors de l'écriture de Altostratus, consultez notre publication à partir de bit.ly/1g5EF4j.

Si vous rencontrez des problèmes étranges, la première étape doit être la base de données de bogue Xamarin (bugzilla.xamarin.com). Si vous ne voyez pas votre problème discuté, publiez une question ou problème sur les Forums Xamarin (forums.xamarin.com), où vous trouverez le personnel Xamarin tout à fait répondre.

Ceci dit, résolution des problèmes individuels comme il est beaucoup moins de travail que d'apprendre les détails de la couche d'interface utilisateur individuel de chaque plateforme. Et Xamarin.Forms étant relativement nouveau, recherche de ces problèmes permet à l'infrastructure deviennent de plus en plus robuste.

Ajustements spécifiques à la plateforme

Dans Xamarin.Forms, il est parfois nécessaire d'ajuster pour une plateforme ou une autre, comme le réglage de la mise en page. (Reportez-vous à excellent ouvrage de Petzold, « Programmation Mobile applications avec Xamarin.Forms » [bit.ly/1H8b2q6], pour un nombre d'exemples.) Vous devrez peut-être également gérer certaines incohérences comportementales, par exemple lorsqu'un élément webview déclenche son premier événement Navigating (là encore, pour quelques que nous avons rencontré, consultez notre publication à partir de bit.ly/1g5EF4j).

Pour cela, Xamarin.Forms a un API Device.OnPlatform < T > (iOS_value, Android_value, Windows_value) et un élément XAML correspondant. Comme vous pouvez le deviner, OnPlatform renvoie une valeur différente selon l'exécution en cours. Par exemple, le code XAML suivant masque les contrôles de connexion de la page de Configuration sur Windows Phone que le composant Xamarin.Auth ne prend en charge cette plate-forme, donc nous exécutons toujours non authentifiés (configuration.xaml) :

<StackLayout Orientation="Vertical">
  <StackLayout.IsVisible>
    <OnPlatform x:TypeArguments="x:Boolean" Android="true" iOS="true"
      WinPhone="false" />
  </StackLayout.IsVisible>
  <Label Text="{ Binding AuthenticationMessage }" FontSize="Medium" />
  <Picker x:Name="providerPicker" Title="{ Binding ProviderListLabel }"
    IsVisible="{ Binding ProviderListVisible }" />
  <Button Text="{ Binding LoginButtonLabel}" Clicked="LoginTapped" />
</StackLayout>

À propos des composants, Xamarin elle-même repose principalement des composants qui résument les fonctionnalités courantes des plateformes natives, qui sont antérieurs à Xamarin.Forms pour l'interface utilisateur. Certains de ces composants sont intégrés Xamarin, tandis que d'autres, y compris les contributions de la Communauté, vous obtenez à partir components.xamarin.com. En plus de Xamarin.Auth, Altostratus utilise le plug-in de connectivité (tinyurl.com/xconplugin) pour afficher un indicateur et désactiver le bouton Actualiser lorsque le périphérique est hors connexion.

Nous avons trouvé il y a toujours un décalage entre lors de la modification de la connectivité sur le périphérique (reflété dans la propriété de plug-in IsConnected) et lorsque le plug-in déclenche son événement. Cela signifie qu'il peut y avoir quelques secondes entre le périphérique hors connexion et le bouton Actualiser l'état désactivé. Pour gérer cette situation, nous utilisons l'événement de commande Refresh pour vérifier IsConnected état le plug-in. Si elle est hors connexion, nous immédiatement désactiver le bouton, mais définir un indicateur indiquant au gestionnaire ConnectivityChanged pour démarrer automatiquement une synchronisation lorsque la connectivité est rétablie.

Altostratus utilise également Xamarin.Auth (tinyurl.com/xamauth) pour gérer les informations d'authentification via OAuth, dont nous parlerons dans un moment. L'inconvénient ici est que le composant actuellement prend uniquement en charge iOS et Android pas Windows Phone, et il n'était pas dans la portée de notre projet résoudre ce problème particulier. Heureusement, l'application cliente s'exécute bien non authentifié, ce qui signifie simplement que les paramètres de l'utilisateur ne sont pas conservés dans le cloud et échange de données avec le serveur principal n'est pas entièrement optimisé. Lorsque le composant est mis à jour pour prendre en charge de Windows, nous devons uniquement supprimer la balise OnPlatform dans le code XAML ci-dessus pour afficher les contrôles de connexion.

Authentification avec le serveur principal

Dans l'application Altostratus dans son ensemble, nous voulions démontrer la mécanique impliquée dans le stockage des préférences spécifiques à l'utilisateur sur le back-end tels que le serveur principal peut appliquer automatiquement ces préférences lors du traitement des requêtes HTTP. Pour cette application spécifique, bien sûr, nous avons atteint le même résultat avec simplement les paramètres URI avec les demandes, mais un exemple de ce type ne seraient pas servir de base pour des scénarios plus complexes. Enregistrer les préférences sur le serveur permet de se déplacer entre tous les périphériques l'utilisateur.

Pour fonctionner avec n'importe quel type de données spécifiques à l'utilisateur signifie que l'authentification utilisateur unique. Cela diffère, sachez que, d'autorisation. L'authentification est un moyen d'identifier un utilisateur et de valider qu'ils sont bien ceux qu'ils prétendent être. Autorisation, se rapporte quant à lui, aux autorisations accordées à un utilisateur spécifique (par exemple, administrateur et utilisateur standard par rapport aux invités).

Pour l'authentification, nous utiliser sociaux grâce à des tiers tels que Google et Facebook, au lieu d'implémenter notre propre système d'informations d'identification (et le serveur principal a une API par le biais duquel l'application cliente récupère une liste de fournisseurs pour la page de Configuration de l'interface utilisateur). Le principal avantage à sociaux est que nous n'avons pas à traiter des informations d'identification du tout, ou leurs préoccupations de sécurité et de confidentialité du service Surveillance du ; le serveur principal stocke uniquement une adresse de messagerie comme nom d'utilisateur et le client gère un jeton d'accès au moment de l'exécution. Dans le cas contraire, le fournisseur ne le gros, y compris la vérification de courrier électronique, la récupération de mot de passe et ainsi de suite.

Bien sûr, pas pour tout le monde dispose d'un compte avec un fournisseur sociaux et certains utilisateurs ne souhaitent pas utiliser de comptes sociaux pour des raisons de confidentialité. En outre, sociaux peut ne pas convenir pour les applications line of business ; Dans ce cas, nous vous recommandons d'Azure Active Directory. Pour nos objectifs, toutefois, il est un choix logique, car nous devons simplement un moyen pour authentifier un utilisateur individuel.

Une fois authentifié, un utilisateur est autorisé à enregistrer les préférences sur le serveur principal. Si nous voulons implémenter d'autres niveaux d'autorisation (par exemple la modification des préférences d'autres utilisateurs), le serveur principal peut vérifier le nom d'utilisateur par rapport à une base de données d'autorisations.

à l'aide d'OAuth2 pour sociaux dans ASP.NET Web API OAuth2 (bit.ly/1SxC1AM) est une infrastructure d'autorisation qui permet aux utilisateurs d'accorder l'accès aux ressources, sans partager leurs informations d'identification. Il définit plusieurs « informations d'identification flux » qui spécifient comment les informations d'identification sont transmises avec parmi diverses entités. L'API Web ASP.NET utilise les soi-disant « grant implicite flux » dans lequel l'application mobile collecte les informations d'identification ni stocke des informations sensibles. Que le travail est effectué par le fournisseur de OAuth2 et de la bibliothèque ASP.NET Identity (asp.net/identity), respectivement.

Pour activer la connexion sociale, vous devez inscrire votre application avec chacun des fournisseurs de connexion via leurs portails de développeur. (Une « application » dans ce contexte signifie que toutes les expériences clients, y compris mobile et Web et n'est pas spécifiquement liée à une application mobile). Une fois inscrit, le fournisseur vous donne un ID unique du client et le secret. Voir bit.ly/1BniZ89 pour obtenir des exemples.

Nous utilisons ces valeurs pour initialiser le middleware identité ASP.NET, comme indiqué dans Figure 3.

Figure 3 l'initialisation de l'intergiciel d'identité ASP.NET

var fbOpts = new FacebookAuthenticationOptions
{
  AppId = ConfigurationManager.AppSettings["FB_AppId"],
  AppSecret = ConfigurationManager.AppSettings["FB_AppSecret"]
};
fbOpts.Scope.Add("email");
app.UseFacebookAuthentication(fbOpts);
var googleOptions = new GoogleOAuth2AuthenticationOptions()
{
  ClientId = ConfigurationManager.AppSettings["GoogleClientID"],
  ClientSecret = ConfigurationManager.AppSettings["GoogleClientSecret"]
};
app.UseGoogleAuthentication(googleOptions);

Les chaînes telles que « FB_AppID » sont des clés qui font référence aux paramètres d'environnement et de configuration de l'application Web, où sont stockés les ID et les secrets réelle. Cela vous donne la possibilité de les mettre à jour sans régénérer et redéployer l'application.

à l'aide de Xamarin.Auth pour gérer les informations d'identification fluxen général, le processus d'authentification sociaux implique une variété de négociations entre l'application, le serveur principal et le fournisseur. Heureusement, le composant Xamarin.Auth (disponible dans le magasin de composants Xamarin), gère la plupart de cela pour l'application. Cela inclut utilisation du contrôle de navigateur et en fournissant le rappel raccorde afin de l'application peut répondre lorsque l'autorisation est terminée.

Dès le départ, Xamarin.Auth a l'application cliente d'effectuer certaines parties de la danse d'autorisation, ce qui signifie que l'application stocke l'ID client et le secret. Qui est légèrement différent à partir du flux d'ASP.NET, mais Xamarin.Auth a une hiérarchie de classes correctement factorisées. La classe Xamarin.Auth.OAuth2Authenticator dérivée de WebRedirectAuthenticator, ce qui nous donne la fonctionnalité de base nous avons besoin et nous oblige à écrire uniquement une petite quantité de code supplémentaire, qui se trouve dans les fichiers LoginPageRenderer.cs dans les projets Android et iOS (car Xamarin.Auth ne prend encore en charge Windows). Pour plus d'informations sur ce que nous faisons ici, consultez notre blog à tinyurl.com/kboathalto.

Ensuite, l'application cliente, a tout simplement une classe LoginPage qui dérive de la ContentPage base de Xamarin.Forms, ce qui nous permet de le parcourir. Cette classe expose deux méthodes, CompleteLoginAsync et CancelAsync, sont appelées à partir du code LoginPageRenderer selon ce que fait l'utilisateur dans l'interface Web du fournisseur.

Envoi de demandes authentifiées après une connexion réussie, l'application cliente a un jeton d'accès. Pour effectuer une demande authentifiée, il inclut simplement ce jeton dans un en-tête d'autorisation comme suit :

GET http://hostname/api/UserPreferences HTTP/1.1
Authorization: Bearer I6zW8Dk...
Accept: */*
X-Requested-With: XMLHttpRequest
User-Agent: Mozilla/5.0 (Windows NT 6.3; WOW64; Trident/7.0; rv:11.0) like Gecko

Ici, « Support » indique l'autorisation à l'aide des jetons de support, après avoir qui vient la longue chaîne de jeton opaque.

Nous utilisons la bibliothèque System.Net.Http.HttpClient pour toutes les demandes REST avec un gestionnaire de message personnalisé pour ajouter l'en-tête d'authentification à chaque demande. Gestionnaires de messages sont des composants plug-in qui vous permettent d'examiner et modifier les messages de demande et de réponse HTTP. Pour plus d'informations, consultez bit.ly/1MyMMB8.

Le Gestionnaire de messages est implémenté dans la classe AuthenticationMessageHandler (webapi.cs) et est installé lors de la création de l'instance de HttpClient :

_httpClient = HttpClientFactory.Create(
  handler, new AuthenticationMessageHandler(provider));

L'interface ITokenProvider est un moyen simple pour le gestionnaire obtenir l'accès au jeton de l'application (implémenté dans la classe UserPreferences s'il y a). La méthode SendAsync est appelée pour chaque requête HTTP ; en tant que Figure 4 présente, il ajoute l'en-tête Authorization si le fournisseur de jetons peut utiliser.

Figure 4 Ajout de l'en-tête d'autorisation

public interface ITokenProvider
{
  string AccessToken { get; }
}
class AuthenticationMessageHandler : DelegatingHandler
{
  ITokenProvider _provider;
  public AuthenticationMessageHandler(ITokenProvider provider)
  {
     _provider = provider;
  }
  protected override Task<HttpResponseMessage>
    SendAsync(HttpRequestMessage request,
    System.Threading.CancellationToken cancellationToken)
  {
    var token = _provider.AccessToken;
    if (!String.IsNullOrEmpty(token))
    {
      request.Headers.Authorization =
        new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", token);
    }
    return base.SendAsync(request, cancellationToken);
  }
}

Sur le serveur principal, comme décrit dans la partie 1 de cet article, si un jeton est reçu avec une demande, le jeton est utilisé pour extraire les préférences de l'utilisateur et de les appliquer automatiquement pour le reste de la demande. Par exemple, si l'utilisateur a défini la limite de conversation à 25 au lieu de la valeur par défaut de 100, un maximum de 25 éléments retourné avec une demande, l'enregistrement de la bande passante réseau.

Création d'un Cache en mode hors connexion de données Back-End

Un avantage majeur d'une application mobile sur le Web mobile est la possibilité de prendre en charge l'utilisation hors connexion. Une application mobile, par définition, est toujours présente sur le périphérique de l'utilisateur et peut utiliser une variété d'options de stockage de données, notamment SQLite, pour maintenir un cache de données hors connexion, plutôt que de compter sur les mécanismes basés sur le navigateur.

L'interface utilisateur du client mobile Altostratus, en fait, tout simplement fonctionne avec les données qui sont conservées dans une base de données locale SQLite, rendre l'application entièrement fonctionnels sans connectivité. Lorsque la connectivité est présente, les processus d'arrière-plan récupérer les données actuelles de la mise à jour de la base de données back-end. Cela met à jour les objets de modèle de données qui se trouvent au-dessus de la base de données, qui à son tour déclenche les mises à jour de l'interface utilisateur via la liaison de données (vous pouvez voir ce dans Figure 2). De cette façon, il est une architecture très similaire à la partie 1, où les webjobs continues collecter, normaliser et stocker des données dans une base de données SQL Server afin que l'API Web peut traiter les demandes directement à partir de cette base de données back-end.

Prise en charge en mode hors connexion pour Altostratus implique trois tâches distinctes :

  • Placement d'un fichier de base de données prédéfinie directement dans le package d'application pour fournir des données de travail immédiatement à la première exécution sans nécessiter de connectivité.
  • Implémentation de processus de synchronisation à sens unique pour chaque partie du modèle de données obtient signalée dans l'interface utilisateur : conversations (éléments), les catégories, les fournisseurs d'authentification et les préférences de l'utilisateur.
  • Raccordement de synchronisation aux déclencheurs appropriés au-delà du bouton d'actualisation dans l'interface utilisateur.

Examinons chacun d'entre eux à son tour.

Création d'une base de données préremplies qu'il est possible pour un utilisateur d'installer une application à partir d'un magasin en ligne, mais pas l'exécuter jusqu'à une date ultérieure, lorsque le périphérique est hors connexion. La question est, voulez-vous que votre application à dire, « Désolé, nous ne pouvons pas faire quelque chose d'utile, sauf si vous êtes en ligne? » Ou voulez-vous que votre application pour gérer ces cas de manière intelligente ?

Pour illustrer cette dernière approche, le client de Altostratus inclut une base de données SQLite préremplie directement dans son package d'application sur chaque plateforme (situé dans le dossier ressources/brut de chaque projet de plate-forme). À la première exécution, le client copie ce fichier de base de données vers un emplacement en lecture / écriture sur le périphérique et travaille ensuite avec lui à partir de là exclusivement. Étant donné que le processus de copie de fichier est unique pour chaque plateforme, la fonctionnalité Xamarin.Forms.DependencyService nous permet de résoudre, lors de l'exécution, une implémentation spécifique d'une interface que nous définissons appelée ISQLite. Cela se produit à partir du constructeur de DataAccessLayer (DataAccess.cs), qui appelle ensuite ISQLite.GetDatabasePath pour extraire l'emplacement spécifique à la plateforme du fichier de base de données copiée en lecture-écriture, comme dans Figure 5.

Figure 5 la localisation spécifique à la plate-forme de la base de données

public DataAccessLayer(SQLiteAsyncConnection db = null)
{
  if (db == null)
  {
    String path = DependencyService.Get<ISQLite>().GetDatabasePath();
    db = new SQLiteAsyncConnection(path);               
    // Alternate use to use the synchronous SQLite API:
    // database = SQLiteConnection(path);               
  }
  database = db;
  _current = this;
}

Pour créer la base de données initiale, la solution de Altostratus contient une petite application de console Win32 appelée DBInitialize. Il utilise la même PCL partagée en tant que l'application fonctionne avec la base de données, donc il n'est jamais un problème d'avoir une base de code deuxième, ne correspondent pas. DBInitialize, cependant, n'a pas besoin d'utiliser le DependencyService : Il peut uniquement créer un fichier directement et ouvrir une connexion :

string path = "Altostratus.db3";
SQLiteAsyncConnection conn = new SQLiteAsyncConnection(path);
var dbInit = new DataAccessLayer(conn);

À partir de là, DBInitialize appelle DataAccessLayer.InitAsync pour créer les tables (quelque chose que l'application n'a jamais faire avec la base de données préremplie) et utilise les autres méthodes DataAccessLayer pour obtenir des données depuis le serveur principal. Notez qu'avec les appels asynchrones, DBInitialize utilise seulement. Attente ; car il est une application console et n'a pas besoin de vous inquiéter à propos de l'interface utilisateur réactive :

DataModel model = new DataModel(dbInit);
model.InitAsync().Wait();
model.SyncCategories().Wait();
model.SyncAuthProviders().Wait();
model.SyncItems().Wait();

Pour donner aux utilisateurs quelque chose à regarder, il utilise un minuteur pour placer un point sur l'écran à chaque seconde moitié.

Notez que vous voudrez toujours vérifier la base de données préremplie avec un outil comme navigateur DB SQLite (bit.ly/1OCkm8Y) avant extrayant dans le projet. Il est possible pour un ou plusieurs des demandes Web à échouer, auquel cas la base de données ne seraient pas être valide. Vous pourriez créer cette logique dans DBInitialize afin qu'il supprime la base de données et affiche une erreur. Dans notre cas, nous avons simplement observer les messages d'erreur et exécutez le programme à nouveau, si nécessaire.

Vous pouvez poser la question « le contenu d'une base de données préremplie entrerai obsolète relativement rapidement ? Il est préférable des utilisateurs de mon application pour voir les données périmées vraiment à la première exécution! » Ceci, bien sûr, sera le cas si vous ne mettez régulièrement à jour votre application. Par conséquent, vous voudrez valider les mises à jour périodiques d'application qui inclure une base de données raisonnablement actuelles (selon la nature de vos données).

Si l'utilisateur dispose déjà de l'application est installée, la mise à jour n'a aucun effet car le code qui copie le fichier de package de la base de données vérifie si une copie en lecture-écriture existe déjà et qui utilise uniquement. Cependant, si l'existence du fichier était l'uniquement cette vérification, un utilisateur qui n'a pas exécuté l'application pendant un certain temps pourrait finir lancement de l'application avec des données plus anciennes que ce qui est réellement dans un package plus récemment mis à jour. Vous pouvez vérifier si l'horodatage de la base de données du cache est antérieure à celle de package et remplacer le cache avec la copie la plus récente. Ce n'est pas quelque chose que nous avons implémenté dans Altostratus, toutefois, étant donné que nous devrons également de conserver les informations de préférences de l'utilisateur de la base de données existante.

Synchronisation du Cache hors connexion avec le Back-End comme mentionné précédemment, le client Altostratus s'exécute toujours par rapport à sa base de données du cache. Toutes les requêtes Web vers le serveur principal (à l'exception de chargement des préférences de l'utilisateur) se produisent dans le contexte de synchronisation du cache. Le mécanisme est implémenté en tant que partie de la classe DataModel, en particulier via les quatre méthodes de sync.cs : SyncSettings (qui délègue à endConfiguration Configuration.ApplyBack dans model.cs), SyncCategories, SyncAuthProviders et SyncItems. Le produit phare de la série est clairement SyncItems, mais nous reviendrons sur ce qui déclenche tous ces éléments dans la section suivante.

Notez que Altostratus synchronise les données dans un seul sens, de la fin dans le cache local. En outre, étant donné que nous savons que les données que nous nous intéressons ne changent tout cela rapidement (compte tenu de la planification pour le webjobs back-end), nous intéresse uniquement la cohérence éventuelle avec le magasin de données back-end, plutôt que de mettre à jour l'ordre de minutes ou secondes.

Chaque processus de synchronisation est essentiellement le même : Récupérer les données actuelles de la fin, mettre à jour la base de données locale avec les nouvelles valeurs, supprimer les anciennes valeurs de la base de données et puis remplir à nouveau les objets de modèle de données en vue de déclencher des mises à jour de l'interface utilisateur.

Pour les éléments, est un peu plus de travail car SyncItems peut être appelée à partir de l'interface utilisateur, et nous voulons vous prémunir contre les utilisateurs trop enthousiaste, appuyez plusieurs fois sur le bouton. La propriété DataModel.syncTask privée indique s'il existe une synchronisation de l'élément actif ; SyncItems ignore une demande de répétition si syncTask n'est pas null. En outre, comme une demande d'articles peut prendre du temps et implique des jeux de données volumineux, nous souhaitons pouvoir annuler une synchronisation de l'élément si le périphérique est mis hors connexion. Pour ce faire, nous allons enregistrer un System.Threading.CancellationToken pour la tâche.

La méthode SyncItemsCore privée, illustrée Figure 6, est le cœur du processus. Il récupère l'horodatage de la dernière synchronisation de la base de données et qui inclut à la requête Web.

Figure 6 la méthode SyncItemsCore privée

private async Task<SyncResult> SyncItemsCore()
{
  SyncResult result = SyncResult.Success;
  HttpResponseMessage response;
  Timestamp t = await DataAccessLayer.Current.GetTimestampAsync();
  String newRequestTimestamp =
    DateTime.UtcNow.ToString(WebAPIConstants.ItemsFeedTimestampFormat);
  response = await WebAPI.GetItems(t, syncToken);
  if (!response.IsSuccessStatusCode)
  {
    return SyncResult.Failed;
  }
  t = new Timestamp() { Stamp = newRequestTimestamp };
  await DataAccessLayer.Current.SetTimestampAsync(t);
  if (response.StatusCode == System.Net.HttpStatusCode.NoContent)
  {
    return SyncResult.NoContent;
  }
  var items = await response.Content.ReadAsAsync<IEnumerable<FeedItem>>();
  await ProcessItems(items);
  // Sync is done, refresh the ListView data source.
  await PopulateGroupedItemsFromDB();
  return result;
}

Ce faisant, le back-end retourne uniquement les éléments qui sont nouveaux ou mis à jour depuis un moment donné. Par conséquent, le client obtient uniquement les données qu'il a réellement besoin, potentiellement la conservation de l'utilisateur limité plan des données. Cela signifie également que le client fait moins de travail pour traiter des données à partir de chaque demande, également la préservation de la batterie et réduit le trafic réseau. S'il ne semble pas beaucoup, la gestion des cinq conversations par catégorie au lieu de dire, 50, avec chaque requête est une réduction de 90 %. À 20 à 30 synchronisations par jour, cela pourrait ajouter facilement des centaines de mégaoctets dans un mois pour simplement l'application. En bref, vos clients apprécieront certainement les efforts que vous apportez à optimiser le trafic !

Une fois que la demande est renvoyée, la méthode ProcessItems ajoute tous ces éléments à la base de données, faire un peu de nettoyage des titres (par exemple, en supprimant les guillemets) et l'extraction des 100 premiers caractères du corps d'une description à afficher dans la liste principale. Le nettoyage de titre est quelque chose que nous aurions le back-end faire à la place, qui peut enregistrer un peu de temps de traitement sur le client. Nous avons choisi de laisser sur le client, car les autres scénarios spécifiques à la plateforme ajustements peut s'avérer nécessaire. Nous pourrions également avoir le back-end créer les descriptions de 100 caractères, ce qui signifie que l'enregistrement d'un client peu de traitement, mais l'augmentation du trafic réseau. Avec les données que nous travaillons ici, il s'agit probablement une même compromis, et parce que l'interface utilisateur est finalement la responsabilité du client, il semble préférable de laisser le client de contrôle de cette étape. (Pour plus d'informations sur cela et quelques autres considérations d'interface utilisateur, consultez notre blog tinyurl.com/kboathaltoxtra.)

Une fois que nous avons ajouté des éléments à la base de données, les groupes de modèles de données sont actualisées via PopulateGroupedItemsFromDB. Ici, il est important de comprendre que la base de données a probablement plus d'éléments que nécessaire pour le paramètre de limite de conversation de l'utilisateur actuel. PopulateGroupedItemsFromDB compte de cela en appliquant cette limite directement à la requête de base de données.

Au fil du temps, cependant, nous ne voulons pas continuer d'étendre en conservant une série d'éléments qui ne sera jamais affichée à nouveau la base de données. Pour ce faire, SyncItems appelle une méthode DataAccessLayer.ApplyConversationLimit à éliminez les anciens éléments à partir de la base de données jusqu'à ce que le nombre d'éléments correspond à la limite spécifiée. Étant donné que la taille d'un élément individuel dans le jeu de données Altostratus est relativement faible, nous utilisons la limite maximale de conversation de 100 quel que soit le paramètre actuel de l'utilisateur. De cette façon, si l'utilisateur déclenche cette limite, nous n'avons redemander les données du système principal. Si nous avions des éléments de données beaucoup plus grandes, toutefois, il peut être plus judicieux de manière agressive sélectionnons la base de données et redemander éléments s'ils sont nécessaires.

Déclencheurs de synchronisation le bouton Actualiser dans l'interface utilisateur est clairement se produit de façon une synchronisation de l'élément principal, mais lorsque les autres processus de synchronisation prennent place ? Et autres déclencheurs pour un élément de la synchronisation ?

Il est un peu difficile à répondre à ces questions en ce qui concerne le code, car tous les appels aux méthodes de synchronisation * se produisent dans un seul endroit, la méthode HomeViewModel.Sync. Toutefois, cette méthode et un point d'entrée secondaire, HomeViewModel.CheckTimeAndSync, sont appelés à partir d'une variété d'autres emplacements. Voici un résumé des quand, où et comment les appels de synchronisation sont paramétrables avec une valeur de l'énumération SyncExtent :

  • Au démarrage, le constructeur de HomeViewModel appelle Sync(SyncExtent.All), donc la synchronisation se produit entièrement en arrière-plan en utilisant un modèle d'incendie et oubliés. Le modèle ici signifie simplement que l'enregistrement de la valeur de retour à partir d'une méthode async dans une variable locale pour supprimer un avertissement du compilateur de ne pas utiliser await.
  • Dans le gestionnaire pour ConnectivityChanged événement la connectivité du plug-in, nous appelons synchronisation si le périphérique était hors connexion lors d'un appel précédent a été effectué (à l'aide de la même étendue que demandé puis).
  • Si l'utilisateur consulte la page de Configuration et apporte des modifications aux catégories actives ou la limite de la conversation, ou ouvre une session sur le serveur principal et, par conséquent, elle applique les paramètres principaux, ce fait est mémorisé par l'indicateur DataModel.Configuration.HasChanged. Lorsque l'utilisateur revient à la page d'accueil, le Gestionnaire de HomePage.OnAppearing appelle HomeViewModel.CheckRefresh, qui vérifie HasChanged et appelle Sync(SyncExtent.Items), si nécessaire.
  • Les appels d'événements (app.cs) App.OnResume CheckTimeAndSync, qui applique une logique pour déterminer ce qui doit être synchronisée basé sur la durée pendant laquelle l'application a été interrompue. Clairement, ces conditions sont fortement dépendantes de la nature de vos données et les opérations de back-end.
  • Enfin, le bouton d'actualisation appelle CheckTimeAndSync avec un indicateur de toujours effectuer au moins un élément de synchronisation. Le bouton Actualiser utilise CheckTimeAndSync car il est possible, bien que très rare, qu'un utilisateur a peut-être laissé l'application en cours d'exécution au premier plan pour plus d'une demi-heure ou même un jour, en, auquel cas le bouton d'actualisation doit également effectuer les autres synchronisations n'est pas lors de la reprise.

Des avantages de la consolidation tout en HomeViewModel.Sync sont qu'il peut définir la propriété de HomeViewModel.IsSyncing publique aux moments appropriés. Cette propriété est liée aux données pour les IsVisible IsRunning propriétés et d'un Xamarin.Forms.ActivityIndicator dans Home.xaml. Le simple fait de la définition de cet indicateur détermine la visibilité de cet indicateur.

Création avec Xamarin sur TFS et Visual Studio Online

Pour le projet Altostratus, nous avons utilisé un environnement de développement est quelque peu courant pour le travail inter-plateformes : un PC Windows des émulateurs et les périphériques attachés pour Android et Windows Phone, ainsi que d'un ordinateur Mac OS X local avec le simulateur iOS et les périphériques iOS attachés (voir Figure 7). Avec ce type de configuration, vous pouvez faire tout développement et débogage travail directement dans Visual Studio sur l'ordinateur, à l'aide de l'ordinateur Mac OS X pour les builds iOS distant et le débogage. Magasin prêt iOS, les applications peuvent également être ensuite envoyées à partir de Mac.

Un environnement de développement multiplateforme commun pour les projets Xamarin, ainsi que celles qui utilisent d'autres Technologies telles que les outils Visual Studio pour Apache Cordova
Environnement de développement multiplateforme commun figure 7 pour les projets Xamarin, ainsi que celles qui utilisent d'autres Technologies telles que les outils Visual Studio pour Apache Cordova

Nous employé Visual Studio Online pour le contrôle de code source et de collaboration d'équipe et qu'il est configuré pour faire des builds d'intégration continue pour le serveur principal et le client Xamarin. Avions nous avons lancé ce projet dès aujourd'hui, nous serait en mesure d'utiliser le dernier système de génération Visual Studio Online pour créer des applications Xamarin directement dans le contrôleur de build hébergé. Vous trouverez plus d'informations à partir de notre publication de blog à tinyurl.com/kboauthxamvso. Précédemment dans 2015, toutefois, le contrôleur de build hébergé n'ont encore cette prise en charge. Heureusement, il est très simple, honnêtement! — à utiliser un ordinateur local exécutant TFS en tant que le contrôleur de build pour Visual Studio Online. Sur le serveur, nous avons installé l'édition gratuite de TFS Express Xamarin et Android nécessaire et Windows platform SDK, veillant à placer le Kit de développement logiciel Android dans un emplacement tel que c:\android-sdk, dont le compte de génération peut accéder. (Son programme d'installation par défaut place le Kit de développement dans le stockage de l'utilisateur actuel, à laquelle le compte de build n'a pas les autorisations). Cela est décrit dans la documentation Xamarin, « Configuration de Team Foundation Server pour Xamarin, » à bit.ly/1OhQPSW.

Une fois le serveur de builds entièrement configuré, les étapes suivantes établissement la connexion à Visual Studio Online (Voir « Déployer et configurer une Build Server » à l'adresse bit.ly/1RJS4QL) :

  1. Ouvrez la Console Administration TFS.
  2. Dans le volet de navigation de gauche, développez le nom du serveur et sélectionnez la Configuration de Build.
  3. Le service de build, cliquez sur Propriétés pour ouvrir la boîte de dialogue Propriétés du Service de Build.
  4. En haut de la boîte de dialogue, cliquez sur « Arrêter le service ».
  5. Sous Communications, dans la zone de fournir des Services de Build pour la Collection de projets, entrez l'URL de votre collection Visual Studio Online, comme compte https://<your >.visualstudio.com/defaultcollection.
  6. Cliquez sur le bouton Démarrer au bas de la boîte de dialogue de redémarrage du service.

C'est tout ! Lorsque vous créez une définition de build dans Visual Studio Team Explorer, l'ordinateur TFS connecté à Visual Studio Online s'affiche dans la liste des contrôleurs de build disponibles. En sélectionnant qu'option, les builds en file d'attente à partir de Visual Studio ou qui sont en attente à la consignation doivent être routé vers votre ordinateur TFS.

Synthèse

Nous espérons que vous avez apprécié notre discussion sur le projet Altostratus, que vous trouverez le code utile pour vos propres applications mobiles, connectée au cloud. L'objectif de ce projet, a été à nouveau, pour fournir un exemple clair d'une application mobile multiplateforme avec un serveur principal personnalisé qui pourrait être un travail considérable pour le client afin d'optimiser le travail qui devait être effectués directement sur le client. En ayant l'à exécution précédent terminer la collecte de données pour le compte de tous les clients, nous avons réduit considérablement la quantité de trafic de réseau généré par les clients (et son impact sur les plans de données suivante). En normalisant les données provenant de sources différentes, nous avons réduit la quantité de traitement des données nécessaire sur le client, ce qui économise de l'énergie de batterie important. Et en s'authentifiant auprès d'un utilisateur avec le serveur principal, nous l'avons démontré comment il est possible de stocker les préférences utilisateur il et les appliquer automatiquement aux interactions du client avec le serveur principal, optimiser le trafic réseau et les exigences de traitement à nouveau. Nous avons réalisé pour nos besoins spécifiques contenait peut-être plus simples pour obtenir le même effet que nous voulons créer un exemple serait évolutif pour des scénarios plus complexes.

Nous aimerions avoir votre avis sur ce projet. Faites-le nous savoir !

Synchronisation hors connexion Azure

Pour implémenter votre propre cache hors connexion est Azure Sync hors connexion pour les tables, qui fait partie des Services mobiles Azure. Cela évite d'avoir à écrire de code de synchronisation à tout et fonctionne pour envoyer des modifications à partir du client au serveur. Car il utilise le stockage de table, cependant, il ne fournit pas un modèle de données relationnelles comme SQLite.


Kraig Brockschmidt fonctionne en tant que développeur de contenu senior pour Microsoft et se concentre sur les applications mobiles multiplateforme. Il est l'auteur de « Applications de programmation Windows Store avec HTML, CSS et JavaScript » (deux éditions) à partir de Microsoft Press et des blogs sur kraigbrockschmidt.com.

Mike Wasson est un développeur de contenu chez Microsoft. Il a travaillé sur la documentation des API multimédia Win32 durant de nombreuses années. Il écrit actuellement sur Microsoft Azure et ASP.NET.

Rick Anderson fonctionne en programmation senior pour Microsoft, se concentrant sur ASP.NET MVC, Microsoft Azure et Entity Framework. Vous pouvez le suivre sur Twitter à l'adresse twitter.com/RickAndMSFT.

Erik Reitan est un développeur de contenu senior chez Microsoft. Il se concentre sur Microsoft Azure et ASP.NET. Vous pouvez le suivre sur Twitter à l'adresse twitter.com/ReitanErik.

Tom Dykstra est un développeur de contenu senior chez Microsoft, se concentrant sur Microsoft Azure et ASP.NET.

Remercie les experts techniques suivants d'avoir relu cet article : Michael Collier, Brady Gaster, John de Havilland, Ryan Jones, Vijay Ramakrishnan et Pranav Rastogi