- 2013-08-25 - Licence Fondamentale d'Informatique
mardi 27 août 2013

JSON désérialisation avec JSON.net: résultats mise en cache


Le 22 Janvier, j'ai promis que cela soit une série en trois parties. J'ai été un peu occupé avec les applications de mise à niveau, Windows 8 expériences et trivial ;-) trucs comme camps de code, un MVP Summit, la préparation de mon premier et second discours sur Windows Phone et autres joyeusetés et fait attendre pour la partie finale pour trois mois exactement - mais ceux qui me connaissent, savent que je tiens mes promesses, alors voici la troisième et dernière partie de mon JSON pour Windows Phone série.
Dans la partie 1 de cette série que j'ai décrit les bases de la création de classes à partir d'une chaîne JSON et puis tout simplement désérialisant la chaîne dans un (Liste des) cours. Dans la partie 2 , j'ai montré comment utiliser les sous-classes de JSONConverter pour gérer trucs complexes désérialiseur ne peut pas traiter de la boîte, comme des hiérarchies de classes. Partie 3, comme promis, montre une manière de cache des résultats - ce qui rend l'application plus rapide, plus réactif et plus de batterie / plan de données conviviale.
Utilisation de la solution de démonstration de la partie 2 comme point de départ, j'ai fait en premier dans mabibliothèque wp7nl sur CodePlex utilisant NuGet. Je suis paresseux comme tout programmeur (devrait être) et je tiens à reporter autant soulever de lourdes charges au code déjà existant que je peux ;-).
Lorsque vous traitez avec des données téléchargées à partir du Web tout devient asynchrone par nature (au moins sur Windows Phone), et puisque nous n'avons pas le attendre et claviers asynchrones à bord de notre plate-forme encore, j'ai tendance à utiliser observables de Microsoft.Phone.Reactive. Pour laisser ce travail à des événements, j'ai besoin d'une classe enfant EventArgs pour mon "chargement terminé" délégué, que j'ai défini de la manière triviale suivante:
using System;
utilisant System.Collections.Generic;

Wp7nl.Utilities d'espace de noms
{
  public class DataLoadCompletedArgs <T>: EventArgs
  {
    publique IList <T> Résultat {get; fixer;}

    Exception publique erreur {get; fixer;}
  }
}
Il s'agit d'une classe générique parce que je suis fondamentalement trop paresseux pour écrire des déclarations de coulée partout. La configuration de base de la classe d'assistance qui fait à la fois le chargement lui-même est comme ceci:
utilisant System.Linq;
utilisant Microsoft.Phone.Reactive;
using System;
utilisant System.Collections.Generic;
using System.ComponentModel;
using System.Net;
utilisant Newtonsoft.Json;

Wp7nl.Utilities d'espace de noms
{
  public class CachedServiceDataLoader <T> où T: classe
  {
    privé en lecture seule IsolatedStorageHelper <Liste <T>> storageHelper;

    CachedServiceDataLoader publique ()
    {
      storageHelper = new IsolatedStorageHelper <Liste <T>> ();
    }

    private void FireDataLoadCompleted (IList <T> résultat, une erreur d'exception)
    {
      if (DataLoadCompleted! = null)
      {
        DataLoadCompleted (ce qui,
                          nouveau DataLoadCompletedArgs <T> 
                          {Result = result, Error = erreur});
      }
    }

    publique DataLoadCompletedHandler void délégué (object sender, 
      DataLoadCompletedArgs <T> args);

    DataLoadCompletedHandler de manifestation publique DataLoadCompleted;
  }
}
Alors qu'avons-nous ici? Un constructeur qui crée un IsolatedStorageHelper - c'est une classe à partir de la dernière version de Wp7nl, où il se trouve dans l'espace de Wp7nl.Utilities. Il s'agit essentiellement de la logique interne des méthodes d'extension que j'ai décrit dans mon article sur tombstoning MVVMLight ViewModels utilisantSilverlightSerializer couper lâche de ces méthodes d'extension - de sorte qu'ils peuvent être utilisés pour mettre en cache toutes sortes de classes, et pas seulement ViewModels sur la désactivation ou la fermeture de l'application .La partie inférieure de la classe n'est que la manifestation indiquant une action de chargement des données est terminée, et une méthode pratique pour facilement tirer de cet événement (je l'ai mentionné que j'étais paresseux, n'ai-je pas? ;-)).
Ensuite, il ya un autre petit méthodes pratiques pour le chargement des trucs à partir du cache ou de retourner une liste par défaut (vide) si les résultats ne sont pas disponibles:
Liste privée <T> LoadFromStorage ()
{
  retourner storageHelper.ExistsInStorage (?) 
     storageHelper.RetrieveFromStorage (): nouvelle liste <T> ();
}
Il a utilisé qu'une seule fois, donc je ne pouvais tout simplement une simple omis, mais il fait le reste du code un peu plus lisible et c'est important aussi. Lorsque vous déclarez vos intentions dans le code, qui permet d'économiser sur le commentaire.
La méthode pour lire des trucs de cache est un peu plus complexe que le strict nécessaire, mais puisque les données provenant du web est à venir en asynchrone, pourquoi voudrais-je mon application à attendre sur mon cache crachats de ses résultats? J'ai donc fait la récupération de la mémoire cache asynchrone ainsi, en utilisant certains old skool BackgroundWorker battage:
public bool StartLoadFromCache ()
{
  si (storageHelper.ExistsInStorage ())
  {
    var w = new BackgroundWorker ();
    w.DoWork + = (s, e) =>
      {
        e.Result = LoadFromStorage ();
      };

    w.RunWorkerCompleted + = (s, e) =>
      FireDataLoadCompleted (e.Result comme List <T>, e.Error);

    w.RunWorkerAsync ();
    return true;
  }
  return false;
}
J'aurais pu utiliser une observable ici aussi je suppose, mais je n'ai toujours pas adapté mon extrait de code. De toute façon, je triche un peu en vérifiant d'abord si il ya toutes les données du cache du tout - s'il n'y a pas, la méthode renvoie immédiatement false, informant la méthode d'appel il n'ya pas de données mises en cache et d'aller chercher les trucs sur le web. Laquelle il peut, d'ailleurs, en appelant la méthode suivante:
vide StartDownloadCacheData (IList <T> currentObjects publics, Uri ServiceUri,
                                   params JsonConverter [] convertisseurs)
{
  var w = new SharpGIS.GZipWebClient ();
  Observable.FromEvent <DownloadStringCompletedEventArgs> (
    w ", DownloadStringCompleted")
    . S'abonner (r =>
    {
      if (DataLoadCompleted! = null)
      {
        if (r.EventArgs.Error == null)
        {
          var = désérialisée 
               JsonConvert.DeserializeObject <Liste <T>> (r.EventArgs.Result,
                                                      convertisseurs);
          var result = new List <T> (currentObjects);
          result.AddRange (deserialized.Where (p => Les currentObjects.Contains (p))!);
          FireDataLoadCompleted (résultat, r.EventArgs.Error);
          storageHelper.SaveToStorage (result);
        }
        autre
        {
          FireDataLoadCompleted (null, r.EventArgs.Error);
        }
      }
    });

  w.DownloadStringAsync (serviceUri);
}
Alors que cette méthode fait est assez simple:
  • Il fait un GZipWebClient (qui permet aux données d'être chargées zippé, sauvant ainsi la quantité d'octets transmis)
  • Il fait une observable de l'événement "DownloadStringCompleted" et souscrit une méthode anonyme
  • Il tire la méthode DownloadStringAsync sur l'URI
Maintenant, la méthode anonyme qui est déclenché lorsque les données arrivent
  • Vérifie les erreurs
  • Essaie de désérialiser les données entrantes utilisant des convertisseurs prévoit (le cas échéant)
  • Ajoute la liste d'objets existant à la liste des résultats
  • Ajouter les nouveaux objets à la liste après le désherbage des doublons qui étaient déjà dans la liste
  • Déclenche l'événement complet
  • Stocke l'ensemble des données dans le stockage isolé maintenant fusionnées.
Donc, l'idée est que vous pouvez faire de téléchargements consécutifs, mais que les données obtenues ne contient jamais les doublons. C'est pourquoi vous devez fournir la liste des actuels objets. Cela peut sembler un peu bizarre, mais c'est exactement la chose que vous voulez faire avec l'utilisation de données géographiques - ce que je fais presque tout le temps pour gagner sa vie. Comme un inspecteur vous voulez télécharger trucs des zones que vous souhaitez contrôler, et non l'ensemble de la municipalité. Vous déplacez votre carte sur un endroit, cliquez sur "télécharger" et hop, vous avez les trucs que vous souhaitez utiliser dispositif mis en cache sur vous avant de vous rendre sur la route. Répétez jusqu'à ce que toutes les zones que vous souhaitez visiter aujourd'hui ont été traitées.Un peu comme Nokia Drive fait - il n'y a jamais assez de place à bord de votre téléphone pour stocker toutes les cartes possibles du monde, mais quand tu Seattle, de télécharger les cartes pour l'État de Washington, et non pas l'ensemble de l'Amérique du Nord, et vous êtes bon aller.
Mais que faire si vous voulez recommencer - vider le cache au lieu de l'ajouter? C'est la dernière méthode de cette classe:
StartClearStorage public void ()
{
  var w = new BackgroundWorker ();
  w.DoWork + = (s, e) => storageHelper.DeletedFromStorage ();

  w.RunWorkerCompleted + = (s, e) =>
  {
    if (DataLoadCompleted! = null)
    {
      FireDataLoadCompleted (nouvelle liste <T> (), e.Error);
    }
  };

  w.RunWorkerAsync ();
}
Également de manière asynchrone, également pas strictement nécessaire, mais Microsoft ont tendance à se déplacer vers tout faire de manière asynchrone - si vous avez fait tout le développement de Windows 8, vous savez exigences de performance sont assez élevées et strictes, afin de mieux s'habituer à elle déjà.
JSONdemo3J'ai mis à jour la solution démo pour montrer les rouages ​​de cette classe, qui présente lui-même comme montré à droite. Si vous cliquez sur "dispositifs de charge", il affichera quatre dispositifs, comme affichés sur l'image et le message "Chargement du web". Si vous appuyez de nouveau sur le bouton "dispositifs de charge", il affichera les quatre mêmes appareils, mais affiche le message "Chargement du cache" et il va leur montrer un tout petit peu plus vite.
Si vous cliquez sur "Charger plus d'appareils", vous verrez six appareils, - avec le Lumia 800 mentionné deux fois. Mais attendez, qu'est-ce au sujet de désherbage les doublons dans StartDownloadCacheData - n'est pas que le travail? Il fait sûr, mais je l'ai déjà mentionné, je suis paresseux, je n'ai donc pas mis en œuvre une logique "égale" sur la classe de l'appareil - ce qui reste comme exercice pour le lecteur ;-). Je peux vous assurer qu'il fonctionne correctement alors.
"Effacer la liste" efface seulement la liste, et si vous cliquez sur "dispositifs de charge», il va charger les dispositifs de cache à nouveau - très rapide.
"Effacer le cache et la liste" seront effectivement effacer le cache, donc si vous cliquez sur "dispositifs de charge" à nouveau il va voir "Chargement du web".
Je ne vais pas vous ennuyer avec le XAML - le code dans MainPage.xaml.cs est assez simple et met en valeur toutes les caractéristiques de la CachedServiceDataLoader:
using System;
utilisant System.Collections.Generic;
utilisant System.Windows;
utilisant Microsoft.Phone.Controls;
utilisant Microsoft.Phone.Reactive;
utilisant Wp7nl.Utilities;

namespace JsonDemo
{
  publique MainPage de classe partielle: PhoneApplicationPage
  {
    CachedServiceDataLoader privé <Device> cachedLoader;
    IList privé <Device> CurrentData;
    MainPage publique ()
    {
      InitializeComponent ();
      Loaded + = MainPage_Loaded;
    }

    annuler MainPage_Loaded (object sender, RoutedEventArgs e)
    {
      cachedLoader = new CachedServiceDataLoader <Device> ();
      CurrentData = new List <Device> ();
      Observable.FromEvent <DataLoadCompletedArgs <Device>> (
        cachedLoader, "DataLoadCompleted")
       . S'abonner (r =>
                    {
                      CurrentData = r.EventArgs.Result;
                      PhoneList.ItemsSource = r.EventArgs.Result;
                    });
    }

    private void Load_Click (object sender, RoutedEventArgs e)
    {
      if (! cachedLoader.StartLoadFromCache ())
      {
        Message.Text = "Chargement du web";
        cachedLoader.StartDownloadCacheData (CurrentData,
          new Uri ("http://www.schaikweb.net/dotnetbyexample/JSONPhones2.txt"),
          nouveau JsonDeviceConverter (), nouveau JsonSpecsConverter ());
      }
      autre
      {
        Message.Text = "Chargement du cache";        
      }
    }

    private void Load2_Click (object sender, RoutedEventArgs e)
    {
      Message.Text = "Chargement du web";
      cachedLoader.StartDownloadCacheData (CurrentData,
        new Uri ("http://www.schaikweb.net/dotnetbyexample/JSONPhones3.txt"),
        nouveau JsonDeviceConverter (), nouveau JsonSpecsConverter ());
    }      

    private void Clear_Click (object sender, RoutedEventArgs e)
    {
      PhoneList.ItemsSource = null;
      Message.Text = "Liste dégagé (pas de cache)";
    }

    private void ClearCache_Click (object sender, RoutedEventArgs e)
    {
      cachedLoader.StartClearStorage ();
      Message.Text = "liste et cache effacée";
    }
  }
}
Il n'y a même pas de ma marque code MVVM ici. Dans le MainPage_Loaded - sans surprise - tout le truc est initialisée. Le CachedServiceDataLoader est créé en utilisant un type T, et crache un IList de T. J'utilise une observable de garder une trace des choses ici aussi, mais bien sûr, vous êtes libre de vous abonner à des événements de la manière «old fashioned».
Load_Click montre l'utilisation de StartLoadFromCache et StartDownloadCacheData, cette dernière utilisant les classes d'enfants de JSONconverter je l'ai montré dans la partie 2. Le reste, je suppose être assez simple.
Comme vous pouvez le voir, en collaboration avec JSON sur Windows Phone est mort facile et ma petite classe d'assistance qui rend encore plus facile. Je réfléchissais encore si je dois inclure dans la bibliothèque wp7nl, car cela crée encore deux autres dépendances (SharpGIS.GZipWebClient et Newtonsoft.Json) pour rester en phase. Si vous avez des commentaires à ce sujet, je serais heureux de l'entendre. Mais de toute façon, je termine mon JSON pour la série Windows Phone, j'espère que cela se révélera être un mini-tutoriel utile pour la communauté des développeurs Windows Phone. Et comme d'habitude, vous pouvez télécharger la solution complète de mon site.

JSON désérialisation avec JSON.net: hiérarchies de classes

Dans la partie 1 de cette série que j'ai décrit les bases de la création de classes à partir d'une chaîne JSON et puis tout simplement désérialisant la chaîne dans un (Liste des) cours. De cette façon, vous n'avez pas toutes les hooplah de SOAP, mais qui ont encore des classes fortement typées dans votre application client. Mais méfiez-vous, il n'ya pas de contrat formel soit, si un beau matin vous pourriez commencer à penser que, soit vous avez eu trop de boisson hier soir, ou que l'entreprise qui fournit le flux de données de votre application en effet a commencé à vendre des Windows Phone 7 appareils fabriqués par Sony, avec un "écran 65.
En regardant la chaîne JSON vous voyez maintenant quelque chose comme ceci:

[
  {
    "Marque": "Nokia", "Type": "Lumia 800", "périphériques": "Téléphone",
    "Specs": {"stockage": "16 Go", "Memory": "512", "l'Ecran": "3,7"}
  },
  {
    "Marque": "Sony", "Type": "KDL-65HX920", "périphériques": "TV",
    "Specs": {"Screensize": "65", "FullHD": "Oui", "ThreeD": "Oui"}
  },  
  {"Marque": "Nokia", "Type": "Lumia 900", "périphériques": "Téléphone",
    "Specs": {"stockage": "8 Go", "Memory": "512", "l'Ecran": "4,3"}
  },
  {
    "Marque": "Samsung", "Type": "UE55C9000", "périphériques": "TV",
    "Specs": {"Screensize": "55", "FullHD": "Oui", "ThreeD": "Oui"}
  },  
]

Aucune des deux options mentionnées avant de comparaître pour être vrai: apparemment, la société s'est diversifiée.Ils vendent maintenant des téléviseurs ainsi. Bien sûr, vous pouvez exécuter ce creux json2csharp , qui vous donnera ceci:

Spécifications public class
{
    Stockage public string {get; fixer;}
    Mémoire public string {get; fixer;}
    Screensize public string {get; fixer;}
    public string FullHD {get; fixer;}
    ThreeD public string {get; fixer;}
}

public class RootObject
{
    Marque chaîne publique {get; fixer;}
    Type de public string {get; fixer;}
    Appareil public string {get; mettre;}
    Caractéristiques Caractéristiques publics {get; fixer;}
}

Ce sera travailler, mais pas dans le but de ce que je voudrais montrer. Nous remanier le stuff ensemble dans une structure d'objet comme ceci:


CodeScheme

Or, dans le code (mettre dans un seul fichier pour des raisons de concision)

namespace JsonDemo
{
  Dispositif publique de la classe abstraite
  {
    Marque chaîne publique {get; fixer;}
    Type de public string {get; fixer;}
  }
  
  public class Téléphone: Périphérique
  {
    PhoneSpecs Specs publics {get; fixer;}
  }
  
  Tv public class: Appareil
  {
    TvSpecs Specs publics {get; fixer;}
  }
  
  Spécifications publics de classe abstraite
  {
    Screensize public string {get; fixer;}
  }
  
  PhoneSpecs public class: Spécifications
  {
    Stockage public string {get; fixer;}
    Mémoire public string {get; fixer;}
  }
  
    TvSpecs public class: Spécifications
  {
    public string FullHD {get; fixer;}
    ThreeD public string {get; fixer;}
  }
}

Si vous pensez que c'est une manière compliquée ridicule pour stocker une telle structure de données simple je pense que vous avez tout à fait raison, mais a) ils ne me Un appel ne Architecte Senior Software pour rien, ce qui rend les choses compliquées, c'est ce qu'on me dit architectes font pour une vie, alors j'essaie d'être un bon garçon ;-) et b) c'est juste pour le but de l'échantillon, alors restez avec moi, non?
Si vous vous souvenez l'essentiel de la partie 1: tout cela est arrivé à une seule ligne de code, à savoir:
JsonConvert.DeserializeObject <Liste <Phone>> (r.EventArgs.Result);
Cette méthode a fait un second paramètre: params Newtonsoft.Json.JsonConverter [] convertisseurs , ce qui vous permet de fournir vos propres convertisseurs personnalisés. Est faire ceux assez facile, et il devient encore plus facile lorsque vous utilisez la classe <T> JsonCreationConverter qui est flottant autour de l'Internet dans diverses permutations. J'ai entaillé à partir StackOverflow ici .

using System;
utilisant Newtonsoft.Json;
utilisant Newtonsoft.Json.Linq;

namespace JsonDemo
{
  public abstract class JsonCreationConverter <T>: JsonConverter
  {
    protégé abstrait T Create (Type objectType, JObject JsonObject);

    public override bool CanConvert (Type objectType)
    {
      retourner typeof (T) IsAssignableFrom (objectType).;
    }

    public override objet ReadJson (lecteur JsonReader, Type objectType, 
      objet existingValue, sérialiseur JsonSerializer)
    {
      var = JsonObject JObject.Load (lecteur);
      var target = Create (objectType, JsonObject);
      serializer.Populate (jsonObject.CreateReader (), cible);
      retourner cible;
    }

    du public override void WriteJson (écrivain JsonWriter, la valeur de l'objet, 
   sérialiseur JsonSerializer)
    {
      throw new NotImplementedException ();
    }
  }
}

Pour faire un convertisseur, vous sous-classe de cet objet dans un convertisseur basé sur un modèle pour la classe de base, substituez la méthode "Create" et vous partez. Rédaction d'un convertisseur pour la hiérarchie appareil / téléphone / TV est assez simple: il vous suffit de vérifier la valeur de la propriété "Device", ce que vous faites comme ceci:

using System;
utilisant Newtonsoft.Json.Linq;

namespace JsonDemo
{
  JsonDeviceConverter public class: JsonCreationConverter <Device>
  {
    système de forçage protégé Créer (objectType type, JObject JsonObject)
    {
      var = typeName JsonObject ["Device"] ToString ().;
      switch (typeName)
      {
        cas "TV":
          return new Tv ();
        cas "téléphone":
          return new Téléphone ();
        default: return null;
      }
    }
  }
}

Pour les Specs / PhoneSpecs / TvSpecs vous faire plus ou moins la même, c'est seulement maintenant que vous avez à vérifier pour l' existence de certaines propriétés, et non pas la valeur. J'ai décidé que si un objet a une propriété "Stockage" C'est un PhoneSpecs, et si elle a "FullHD" C'est un TVSpecs.

using System;
utilisant Newtonsoft.Json.Linq;

namespace JsonDemo
{
  JsonSpecsConverter public class: <Specs> de JsonCreationConverter
  {
    Spécifications dérogatoires protégées Créer (Type objectType, JObject JsonObject)
    {
      if (JsonObject ["stockage"]! = null)
      {
        retourner nouveaux PhoneSpecs ();
      }

      if (JsonObject ["FullHD"]! = null)
      {
        retourner nouveaux TvSpecs ();
      }

      return null;
    }
  }
}
Enfin, pour obtenir ces convertisseurs utilisés par le désérialiseur vous devez modifier légèrement la ligne de désérialisation:
var = désérialisée JsonConvert.DeserializeObject <Liste <Device>> (r.EventArgs.Result, 
  nouveau JsonDeviceConverter (), nouveau JsonSpecsConverter ());

Et bien sûr, si vous mettez un point d'arrêt derrière cette ligne, vous pouvez placer une veille sur "désérialisées" et de voir que la structure de données a été désérialisé dans notre structure de classe habilement conçu.


Désérialisées

Et c'est tout ce qu'il ya à faire. solution de démo avec le code complet peut être consulté ici .

JSON désérialisation avec JSON.net: les bases

J'ai été en contemplant un article sur la gestion JSON depuis un certain temps maintenant, mais il s'est avéré être un assez long article. Alors j'avais pensé à essayer quelque chose de nouveau, et écrire une courte série en trois parties.
  • Partie 1 gère les bases
  • Partie 2 poignées désérialisation avancé avec des hiérarchies de classes
  • Partie 3 gère un cache-et-mise à jour des scénarios.
Et c'est la partie 1 ;-)
Cet article en entier en fait se résume à une ligne de code , mais j'ai besoin de faire une dépression certaine hooplah vous montrer comment l'utiliser. Tout commence avec les données. Considérez ce morceau de JSON tout à fait lisible, décrivant quelques dernières Windows Phone modèles.
[
  {
    "Marque": "Nokia", "Type": "Lumia 800",
    "Specs": {"stockage": "16 Go", "Memory": "512", "l'Ecran": "3,7"}
  },
  {
    "Marque": "Nokia", "Type": "Lumia 710",
    "Specs": {"stockage": "8 Go", "Memory": "512", "l'Ecran": "3,7"}
  },  
  {"Marque": "Nokia", "Type": "Lumia 900",
    "Specs": {"stockage": "8 Go", "Memory": "512", "l'Ecran": "4,3"}
  },
  {"Marque": "HTC", "Type": "Titan II",
    "Specs": {"stockage": "16 Go", "Memory": "512", "l'Ecran": "4,7"}
  },
  {"Marque": "HTC", "Type": "Radar",
    "Specs": {"stockage": "8 Go", "Memory": "512", "l'Ecran": "3,8"}
  }
]
JSON est plutôt compact, ce qui est une grande fonctionnalité lorsque vous développez pour les appareils mobiles. Il a aussi quelques inconvénients autant que la programmation de clients est concerné:
  • générer le code client pour lui qui fait tout le parsing et appelant, comme pour SOAP, n'est pas une caractéristique standard de Visual Studio,
  • il est presque impossible à lire pour un être humain ordinaire,
  • déchiffrer dans les classes est beaucoup de travail,
  • codage d'un analyseur syntaxique pour le main n'est pas amusant.
C'est pourquoi vous ne le faites pas. Il ya plusieurs façons de générer des classes à partir de JSON, le plus simple est ce site: json2csharp par Jonathan Keith . Vous copiez un résultat JSON dans la zone de texte supérieure, cliquez sur le bouton "Générer" et à venir à votre cours:Json2Csharp
Il ya plus de sites qui font la même chose, soit dit en passant, mais c'est ce que j'utilise. Prochaines étapes:
  • Lancez Visual Studio
  • Créez un nouveau projet Windows Phone (par exemple JsonDemo)
  • Pinard les classes générées ci-dessus dans le projet. les cookies de bonus si vous les divisez dans des fichiers séparés et d'ajouter des espaces de noms pour eux. Bonus beignet si vous, comme moi, pensent "RootObject» est en fait un nom assez laid pour un objet - donc le changer pour " Téléphone " .
  • Cliquez sur Outils / Library Package Manager / Gérer les paquets NuGet pour Solution (vous ne devez le NuGet Package Manager installé, n'est-ce pas? Sinon, arrêtez ce que vous faites maintenant et obtenez le droit ce cas , vous m'entendez ;)? )
  • Rechercher JSON.Net
  • Cliquez sur Installer. Cela va ajouter une référence à NewtonSoft.Json.dll à votre produit.
  • Ajoutez des références à Microsoft.Phone.Reactive et System.Observable parce qu'ils vont être nécessaires dans l'étape suivante.
Pour rendre le résultat visible, ajouter un peu de XAML dans le panneau de contenu par défaut dans MainPage.xaml - juste un bouton et une zone de liste basé sur un modèle, pas sorcier ici:
<StackPanel>
  <Nom du bouton = "Load"
      VerticalAlignment = "Top"
      Content = "téléphones de charge" Click = "Load_Click" />
  <listbox X:Name="PhoneList" Height="532">
    <ListBox.ItemTemplate>
      <DataTemplate>
        <StackPanel Orientation="Horizontal">
          <TextBlock Text = "{Binding} Marque" 
                 Marge = "0,0,12,0" />
          <TextBlock Text="{Binding Type}"/>
        </ StackPanel>
      </ DataTemplate>
    </ ListBox.ItemTemplate>
  </ ListBox>
</ StackPanel>
Enfin, MainPage.xaml.cs ouvrir et ajouter la méthode Load_Click comme affichés ci-dessous.
using System;
utilisant System.Collections.Generic;
using System.Net;
utilisant System.Windows;
utilisant Microsoft.Phone.Controls;
utilisant Microsoft.Phone.Reactive;
utilisant Newtonsoft.Json;

namespace JsonDemo
{
  publique MainPage de classe partielle: PhoneApplicationPage
  {
    / / Constructeur
    MainPage publique ()
    {
      InitializeComponent ();
    }

    private void Load_Click (object sender, RoutedEventArgs e)
    {
      var w = new WebClient ();
      Observable
        . FromEvent <DownloadStringCompletedEventArgs> (w, "DownloadStringCompleted")
        . S'abonner (r =>
        {
          var = désérialisée 
            JsonConvert.DeserializeObject <Liste <Phone>> (r.EventArgs.Result);
          PhoneList.ItemsSource = désérialisée;
        });
      w.DownloadStringAsync (
        new Uri ("http://www.schaikweb.net/dotnetbyexample/JSONPhones1.txt"));
    }
  }
}

JsonSerializerEt ça y est, la seule ligne de code que tout cela est à propos. Appelez la méthode DeserializeObject, modèle avec le type de retour que vous voulez, et farcir la chaîne JSON en elle. Résultat: une liste d'objets avec leurs propriétés remplis, même si il ya des choses comme des objets imbriqués (spécifications dans ces cas) et des tableaux à l'intérieur.
Si vous exécutez la solution de démonstration vous obtenez le résultat affiché dans l'image sur la droite. Gardez à l'esprit ce code n'est en aucun cas spécifique de Windows Phone. Il existe des implémentations de JSON.Net pour pratiquement tous les cadres disponibles.Donc, si vous ressentez le besoin d'utiliser ce à partir de Silverlight ou complète. NET: c'est là.
Vous devez, par ailleurs, faire attention à la structure du JSON . Le code que je montre travaille pour une liste . Une liste en JSON commence avec un crochet: [ . Si votre JSON commence par une accolade: { puis vous êtes retourné un seul objet - un objet que l'on appelle la racine. Dans ce cas, votre désérialisation doit code de retourner un objet unique au lieu d'une liste aussi bien, c'est quelque chose comme
var = désérialisée 
     JsonConvert.DeserializeObject <Phone> (r.EventArgs.Result);
Enfin, une pointe de ninja:
  • Cliquez sur Outils / Library Package Manager / Gérer Forfaits NuGet pour Solution nouveau
  • Rechercher SharpGIS.GZipWebClient
  • Cliquez sur Installer
  • Changez "WebClient" dans la méthode Load_Click à SharpGIS.GZipWebClient
Ce plug-in pour remplacer WebClient par Morten Nielsen ajoute le support pour gzip requêtes web comprimé - cela réduit le trafic réseau encore plus loin, augmentant apparemment les performances de chargement de manière significative. Vous ne serez pas vraiment remarqué la différence sur un si petit fichiers de données telle qu'elle est utilisée dans cet échantillon, mais que vos valeurs de retour JSON deviennent plus grandes, ainsi sera l'impact de l'utilisation de cette bibliothèque.
Pour la petite histoire: je ne suis pas malade et je n'ai pas abandonné MVVM, mais j'ai essayé de faire l'exemple le plus simple possible donc oui, j'ai utilisé un peu de code derrière, comme pour ne pas troubler la solution en fioritures architecturales. ;-)
Merci à Matthijs Hoekstra pour me mettre sur la bonne voie pour cela, et à son compatriote # wp7nl développeurLeon Zandman pour corriger quelques fautes de frappe ennuyeux.
 
-