Developpement Windows Phone - partie 12

Les Notifications Push pour le développement Windows Phone

Cet article fait partie d’une série d’articles sur le développement Windows Phone. Il s’agit d’une traduction des articles se trouvant sur la MSDN.

Sommaire

Bien débuter et fondamentaux

Visuels et média

Travailler avec les données

Sondes et autres fonctionnalités spécifiques au téléphone


Les Notifications Push pour le développement Windows Phone

Les applications Windows Phone 7 peuvent recevoir des messages d’Internet qui sont envoyés par un serveur, grâce à l’utilisation des Notifications Push. Ces notifications peuvent être reçues par l’utilisateur même si l’application n’est pas en marche. Les Notifications Push sont relayées aux périphériques Windows Phone 7 par le service de notification de Microsoft (MPNS: Microsoft Push Notification Service)

Ce tutoriel contient les sections suivantes:

Télécharger les sources complètes de ce tutoriel

La solution en vidéo

Pour voir un exemple de cette application en marche, et pour consulter ce tutoriel en suivant une vidéo plutôt que de continuer sur la lecture de cet article, vous pouvez regarder la vidéo ci-dessous. Sur cette page de Channel9, la vidéo possède plusieurs options de téléchargement si vous souhaitez télécharger une version qui peut être lue sur des appareils (téléphones, tablettes, etc..) plutôt que sur un ordinateur, ou si le flux de la vidéo n’est pas optimisé pour vous.

Get Microsoft Silverlight

Vue d’ensemble des Notifications Push

Le service de Notification de Push de Microsoft pour Windows Phone (MPNS) offre aux tiers développeurs un canal dédié et persistant pour envoyer des informations et des mises à jour à une application mobile à partir d’un web service. Dans le passé, une application mobile aurait eu besoin d’effectuer plusieurs requêtes au web service correspondant pour savoir s’il y a des notifications en attente. Bien que cela soit efficace, un usage fréquent de requêtes fait que l’on utilise le périphérique radio et que par conséquent nous réduisons la durée de vie de la batterie. En utilisant les Notifications Push au lieu que d’utiliser le polling (requêtage intensif vers un web service), un web service peut notifier une application de mises à jour importantes sur une base as-needed.

Quand un web service a une information à envoyer à une application, il envoie une notification au service de Notification de Push, qui à son tour route celle-ci à l’application. Selon le format de la Notification Push et de la charge liée, l’information est livrée sous forme de données brutes à l’application, les Tiles de celle-ci sont visuellement mises à jour, ou une notification toast est affichée. L’application peut alors communiquer avec un web service en utilisant son propre protocole si nécessaire.

image

Voici les types de Notifications Push supports par Windows Phone 7 avec quelques grandes lignes à garder en tête pour chacune.

Les notifications Tile:

  • Mettent à jour le Live Tile pour l’application présente sur l’écran de démarrage, changement du graphique, du titre du Tile, et affichage de l’intégration d’un compteur
  • Sont toujours reçues quand l’application est en marche, soyez donc prudent aux anciens Live Tiles.
  • Doivent avoir un poids de 80k ou moins et être téléchargées en 15 secondes ou moins.

Les notifications Raw:

  • Peuvent être utilisées pour n’importe quoi, mais avoir une limite de poids de 1K, sinon vous devrez fournir des URIs pour n’importe quels binaires et gérer le téléchargement séparément.
  • Peuvent être reçues que lorsque l’application est en marche.
  • Déclenchent une réaction non perceptible de l’utilisateur sur le téléphone, sauf si le code de l’application permet de le faire.

Les notifications Toast:

  • Contiennent un message court avec un sujet et un corps.
  • Si l’application n’est pas démarrée, les notifications Toast se mettront en haut de l’affichage, superposant ce qu’il y a sur l’écran.
  • Si l’application est en marche, les notifications Toast ne déclencheront pas de réaction perceptible de l’utilisateur sur le téléphone, sauf si le code permet de le faire.

Il y a une limite quotidienne de 500 push par URI sauf si vous téléchargez un certificat TLS pour votre compte de développeur sur AppHub.com et que vous l’utilisez pour authentifier votre WebService avec MPNS. Pour plus d’informations, consultez la procédure : Configurer un WebService sécurisé pour Windows Phone.

Créer un web service qui envoie des Notifications Push

Si vous envisagez de publier votre web service sur Windows Azure, suivez ces étapes:

  1. Installez la dernière version du SDK de Windows Azure et inscrivez-vous pour un essai gratuit ou classique à un compte Azure.
  2. Après installation de SDK Azure, démarrez un nouveau projet dans Visual Studio en utilisant le modèle de projet "Cloud", et sélectionnez "Windows Azure Project," en lui donnant un nom de projet.
  3. Ajoutez un “WCF Service Web Role” à la solution Windows Azure, éditez alors le nom. Entrez un nom différent pour le Role que ce qui était entré pour le projet Windows Azure.Dans cet exemple, le rôle est nommé "PushService," qui créera un web service avec ce même nom qui sera utilisé par défaut pour son namespace.

image

Saisissez le nom "PushService" ici générera un namespace avec ce même nom, comme on le voit dans le code suivant.

Si vous ne planifiez pas d’utiliser Azure, suivez ces étapes:

  1. Lancez Visual Studio et sélectionnez un projet de type "WCF" pour le langage souhaité. (C# est utilisé dans l’exemple).
  2. Sélectionnez "WCF Service Application" comme type de projet, et entrez un nom. Dans cet exemple, le projet est nommé "PushService," lequel créé un a web service avec le nom de projet utilisé pour le namespace par défaut.

Une fois le projet chargé dans Visual Studio, ouvrez le fichier IService1.cs et effacez le contenu de la classe Service1.

Dans le fichier IService1.cs, entrez les signatures des quatre méthodes, précédées par l’attribut OperationContract:

  1. SubscribeMyPhone, recevra un GUID représentant l’ID du téléphone qui s’inscrit pour recevoir les Notifications Push de ce service, et un objet URI représentant l’URL du service de Notification de Push de Microsoft à laquelle les Notifications Push seront relayées pour être reçues par ce téléphone.
  2. PushRawData, recevra un message qui sera envoyé comme notification Raw à tous les téléphones qui se seront inscrits au service par un précédent appel à la méthode SubscribeMyPhone
  3. PushToast, recevra un message qui sera envoyé comme une notification Toast à tous les téléphones qui se seront inscrits au service par un précédent appel à la méthode SubscribeMyPhone.
  4. PushTileUpdate, recevra les paramètres définissant une mise à jour du Tile qui sera envoyé à tous les téléphones qui se seront inscrits au service par un précédent appel à la méthode SubscribeMyPhone.

Le contenu final du fichier IService1.cs après la saisie de ces méthodes sera comme suit:

C# (IService1.cs)

Code Snippet

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Runtime.Serialization;
  5. using System.ServiceModel;
  6. using System.ServiceModel.Web;
  7. using System.Text;
  8. namespace PushService
  9. {
  10.     [ServiceContract]
  11.     public interface IService1
  12.     {
  13.         [OperationContract]
  14.         void SubscribeMyPhone(Guid phoneID, string channelURI);
  15.         [OperationContract]
  16.         void PushRawData(string rawMessage);
  17.         [OperationContract]
  18.         void PushToast(string toastTitle, string toastMessage);
  19.         [OperationContract]
  20.         void PushTileUpdate(string tileTitle, int tileCount, string tileImageURI);
  21.     }
  22. }

Dans le fichier Service1.svc.cs, nous saisirons le code qui implémente ces méthodes dans la classe par défaut, nommée Service1, qui est dans namespace par défaut « PushService ». La classe Service1 contient les implémentations des membres suivants :

  1. SubcsriptionURIs est un dictionnaire <Guid, Uri> qui suit les GUID des téléphones qui ont appelé la méthode SubsribeMyPhone et ont fourni une URI par laquelle ils peuvent recevoir des Notifications Push.
  2. BatchingIntervalValues est un Enum qui définit différents temps d’attente qui peuvent être utilisés pour retarder une Notification Push qui sera envoyée au téléphone à partir du service de notification.
  3. SendPushToSubscribedURIs est une méthode qui reçoit la sortie des quatres méthodes que nous avons définies dans le fichier IService1.cs, les packages dans le corps d’un paquet HTTP POST qui possède un en-tête personnalisé qui active les fonctionnalités Notification Push et envoie un paquet final pour toutes les URI définies dans le dictionnaire SubscriptionURIs. Ces URIs sont fournies par le service de Notification Push de Microsoft relayeront les messages aux téléphones destinés.
  4. SubscribeMyPhone sera implémenté pour mettre à jour SubscripitionURIs avec les données entrantes des URIs.
  5. PushRawData sera implémenté pour encoder les messages entrants comme un tableau de byte[] et enverra le résultat à sendPushToSubscribedURIs
  6. PushToast sera implémenté pour encoder le message entrant dans un flux XML avec une structure spécifique que le service de Notification Push de Microsoft attendra, et enverra le résultat à sendPushToSubscribedURIs
  7. PushTileUpdate sera implémenté pour encoder les données entrantes de type Tile Update dans un flux XML avec une structure spécifique que le service de Notification Push de Microsoft attendra, et enverra le résultat à sendPushToSubscribedURIs

Une fois terminé le fichier ressemblera à cela :

C# (Service1.svc.cs)

Code Snippet

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Runtime.Serialization;
  5. using System.ServiceModel;
  6. using System.ServiceModel.Web;
  7. using System.Text;
  8. using System.Xml;
  9. using System.IO;
  10. using System.Net;
  11. namespace PushService
  12. {
  13.     public class Service1 : IService1
  14.     {
  15.         //Custom constructor
  16.         public Service1()
  17.         {
  18.             //TODO: Load from database into SubscriptionURIs here.
  19.         }
  20.         //Data members.
  21.         //This tracks the devices-to-channelURI list, which gets updated by calls to
  22.         //SubscribeMyPhone();
  23.         private static Dictionary<Guid, Uri> SubscriptionURIs = new Dictionary<Guid, Uri>();
  24.         //This overwrites/creates entries for each phone that wants to receive Push Notifications.
  25.         //Note: This list is reset whenever application restarts -- in real life, you will want
  26.         //to store this data from the SubscriptionURIs list into a database so it persists. Hence,
  27.         //there are TODO sections in this code.
  28.         public void SubscribeMyPhone(Guid phoneID, string channelURI)
  29.         {
  30.             Uri thisURI = new Uri(channelURI);
  31.             if (SubscriptionURIs.ContainsKey(phoneID))
  32.             {
  33.                 //update the existing URI entry for this phone, if need be
  34.                 SubscriptionURIs[phoneID] = thisURI;
  35.             }
  36.             else
  37.             {
  38.                 //otherwise, add a subscription for this phone
  39.                 SubscriptionURIs.Add(phoneID, thisURI);
  40.             }
  41.             // TODO: Save this data in a database, otherwise it will be lost on application restart.
  42.         }
  43.         //Sends the received text value as a Raw notification -- which can only be received
  44.         //while the subscribed phone app is running. Raw notifications have a size limit of 1K.
  45.         public void PushRawData(string rawMessage)
  46.         {
  47.             //Encode the message as a byte[] array as the Notification Service Expects.
  48.             System.Text.UTF8Encoding encoding = new UTF8Encoding();
  49.             //Send this message to all subscribed devices.
  50.             sendPushToSubscribedURIs(encoding.GetBytes(rawMessage), "raw");
  51.         }
  52.         //Sends a Toast notification, using the arguments to define the notification's Title and Message.
  53.         public void PushToast(string ToastTitle, string ToastMessage)
  54.         {
  55.             //Use XMLWriter to construct notification structure/contents.
  56.             MemoryStream myStream = new MemoryStream();
  57.             XmlWriter myWriter = XmlWriter.Create(myStream);
  58.             myWriter.WriteStartDocument();
  59.             myWriter.WriteStartElement("wp", "Notification", "WPNotification");
  60.             myWriter.WriteStartElement("wp", "Toast", "WPNotification");
  61.             myWriter.WriteStartElement("wp", "Text1", "WPNotification");
  62.             myWriter.WriteValue(ToastTitle);
  63.             myWriter.WriteEndElement();
  64.             myWriter.WriteStartElement("wp", "Text2", "WPNotification");
  65.             myWriter.WriteValue(ToastMessage);
  66.             myWriter.WriteEndElement();
  67.             myWriter.WriteEndElement();
  68.             myWriter.WriteEndDocument();
  69.             //Transfer Xml Outpute from myWriter's buffer to myStream.
  70.             myWriter.Flush();
  71.             //Send this message to all subscribed devices.
  72.             sendPushToSubscribedURIs(myStream.ToArray(), "toast");
  73.         }
  74.         //Sends the specified Tile Title, Tile Count, and Tile Image URL as a Tile
  75.         //notification, which can only be received while the subscribed phone app is
  76.         //NOT running. The maximum allowed size of the Tile image is 80kb, with a
  77.         //maximum download time of 15 seconds. Only Tile image URLs from the domains listed in
  78.         //Push Client's ListOfAllowedDomains will be accepted. The Tile Title will overwrite
  79.         //the text that labels the tile on the phone's menu, and the Tile Count is
  80.         //shown as a numeric value displayed on top of the Tile image, visually.
  81.         public void PushTileUpdate(string TileTitle, int TileCount, string TileImageURL)
  82.         {
  83.             // Use XmlWriter to construct notification structure/contents.
  84.             MemoryStream myStream = new MemoryStream();
  85.             XmlWriter myWriter = XmlWriter.Create(myStream);
  86.             myWriter.WriteStartDocument();
  87.             myWriter.WriteStartElement("wp", "Notification", "WPNotification");
  88.             myWriter.WriteStartElement("wp", "Tile", "WPNotification");
  89.             myWriter.WriteStartElement("wp", "BackgroundImage", "WPNotification");
  90.             myWriter.WriteValue(TileImageURL);
  91.             myWriter.WriteEndElement();
  92.             myWriter.WriteStartElement("wp", "Count", "WPNotification");
  93.             myWriter.WriteValue(TileCount);
  94.             myWriter.WriteEndElement();
  95.             myWriter.WriteStartElement("wp", "Title", "WPNotification");
  96.             myWriter.WriteValue(TileTitle);
  97.             myWriter.WriteEndElement();
  98.             myWriter.WriteEndElement();
  99.             myWriter.WriteEndDocument();
  100.             //Transfer Xml output from myWriter's buffer to myStream.
  101.             myWriter.Flush();
  102.             //Send this message to all subscribed devices.
  103.             sendPushToSubscribedURIs(myStream.ToArray(), "tile");
  104.         }
  105.         //This enum gives symbolic names to the numeric values used to "batch together"
  106.         //push notifications according to the specified time intervals. You can send them
  107.         //immediately, within 450 seconds, or within 900 seconds. Allowing the Notification
  108.         //Service to batch notifications will let the service group messages together with
  109.         //notifications from other apps to save phone battery life.
  110.         public enum BatchingIntervalValues
  111.         {
  112.             ImmediateTile = 1,
  113.             ImmediateToast = 2,
  114.             ImmediateRaw = 3,
  115.             Wait450SecondsTile = 11,
  116.             Wait450SecondsToast = 12,
  117.             Wait450SecondsRaw = 13,
  118.             Wait900SecondsTile = 21,
  119.             Wait900SecondsToast = 22,
  120.             Wait900SecondsRaw = 23
  121.         }
  122.  
  123.         //Iterates through SubscriptionURIs, sending the constructed Push Notification to
  124.         //of the notification, which is every subscribed device via the Microsoft
  125.         //Push Notification Service. The payload passed in, is packaged into an HTTP POST
  126.         //message that defines headers containing the notification type and batching interval.
  127.         private static void sendPushToSubscribedURIs(byte[] pushPayload, string notificationType)
  128.         {
  129.             //Iterate through SubscriptionURIs
  130.             foreach (var thisURI in SubscriptionURIs.Values)
  131.             {
  132.                 //Add headers to HTTP Post message.
  133.                 var myRequest = (HttpWebRequest)WebRequest.Create(thisURI); // Push Client's channelURI
  134.                 myRequest.Method = WebRequestMethods.Http.Post;
  135.                 myRequest.ContentType = "text/xml";
  136.                 myRequest.ContentLength = pushPayload.Length;
  137.     
  138.                 // gives this message a unique ID
  139.                 myRequest.Headers.Add("X-MessageID", Guid.NewGuid().ToString());
  140.                 //Customize or exclude the X-WindowsPhone-Target header based on the notification type.
  141.                 switch (notificationType)
  142.                 {
  143.                     case "toast":
  144.                     myRequest.Headers["X-WindowsPhone-Target"] = "toast";
  145.                     myRequest.Headers.Add("X-NotificationClass",
  146.                     ((int)BatchingIntervalValues.ImmediateToast).ToString());
  147.                     break;
  148.                     case "tile":
  149.                     myRequest.Headers["X-WindowsPhone-Target"] = "token";
  150.                     myRequest.Headers.Add("X-NotificationClass",
  151.                     ((int)BatchingIntervalValues.ImmediateTile).ToString());
  152.                     break;
  153.                     case "raw":
  154.                     myRequest.Headers.Add("X-NotificationClass",
  155.                     ((int)BatchingIntervalValues.ImmediateRaw).ToString());
  156.                     //Raw notifications do not specify a value for the X-WindowsPhone-Target header.
  157.                     break;
  158.                 }
  159.                 //Merge headers with payload.
  160.                 using (var requestStream = myRequest.GetRequestStream())
  161.                 {
  162.                     requestStream.Write(pushPayload, 0, pushPayload.Length);
  163.                 }
  164.                 //Send notification to this phone!
  165.                 var response = (HttpWebResponse)myRequest.GetResponse();
  166.             }
  167.         }
  168.     }
  169. }

Visual Basic (Service1.svc.vb)

Code Snippet

  1. Imports System.Collections.Generic
  2. Imports System.Linq
  3. Imports System.Runtime.Serialization
  4. Imports System.ServiceModel
  5. Imports System.ServiceModel.Web
  6. Imports System.Text
  7. Imports System.Xml
  8. Imports System.IO
  9. Imports System.Net
  10. Namespace PushService
  11.     Public Class Service1
  12.         Implements IService1
  13.         'Custom constructor
  14.         'TODO: Load from database into SubscriptionURIs here.
  15.         Public Sub New()
  16.         End Sub
  17.         'Data members.
  18.         'This tracks the devices-to-channelURI list, which gets updated by calls to
  19.         'SubscribeMyPhone();
  20.         Private Shared SubscriptionURIs As New Dictionary(Of Guid, Uri)()
  21.         'This overwrites/creates entries for each phone that wants to receive Push Notifications.
  22.         'Note: This list is reset whenever application restarts -- in real life, you will want
  23.         'to store this data from the SubscriptionURIs list into a database so it persists. Hence,
  24.         'there are TODO sections in this code.
  25.         Public Sub SubscribeMyPhone(phoneID As Guid, channelURI As String)
  26.             Dim thisURI As New Uri(channelURI)
  27.             If SubscriptionURIs.ContainsKey(phoneID) Then
  28.                 'update the existing URI entry for this phone, if need be
  29.                 SubscriptionURIs(phoneID) = thisURI
  30.             Else
  31.                 'otherwise, add a subscription for this phone
  32.                 SubscriptionURIs.Add(phoneID, thisURI)
  33.             End If
  34.             ' TODO: Save this data in a database, otherwise it will be lost on application restart.
  35.         End Sub
  36.         'Sends the received text value as a Raw notification -- which can only be received
  37.         'while the subscribed phone app is running. Raw notifications have a size limit of 1K.
  38.         Public Sub PushRawData(rawMessage As String)
  39.             'Encode the message as a byte[] array as the Notification Service Expects.
  40.             Dim encoding As System.Text.UTF8Encoding = New UTF8Encoding()
  41.             'Send this message to all subscribed devices.
  42.             sendPushToSubscribedURIs(encoding.GetBytes(rawMessage), "raw")
  43.         End Sub
  44.         'Sends a Toast notification, using the arguments to define the notification's Title and Message.
  45.         Public Sub PushToast(ToastTitle As String, ToastMessage As String)
  46.             'Use XMLWriter to construct notification structure/contents.
  47.             Dim myStream As New MemoryStream()
  48.             Dim myWriter As XmlWriter = XmlWriter.Create(myStream)
  49.             myWriter.WriteStartDocument()
  50.             myWriter.WriteStartElement("wp", "Notification", "WPNotification")
  51.             myWriter.WriteStartElement("wp", "Toast", "WPNotification")
  52.             myWriter.WriteStartElement("wp", "Text1", "WPNotification")
  53.             myWriter.WriteValue(ToastTitle)
  54.             myWriter.WriteEndElement()
  55.             myWriter.WriteStartElement("wp", "Text2", "WPNotification")
  56.             myWriter.WriteValue(ToastMessage)
  57.             myWriter.WriteEndElement()
  58.             myWriter.WriteEndElement()
  59.             myWriter.WriteEndDocument()
  60.             'Transfer Xml Outpute from myWriter's buffer to myStream.
  61.             myWriter.Flush()
  62.             'Send this message to all subscribed devices.
  63.             sendPushToSubscribedURIs(myStream.ToArray(), "toast")
  64.         End Sub
  65.         'Sends the specified Tile Title, Tile Count, and Tile Image URL as a Tile
  66.         'notification, which can only be received while the subscribed phone app is
  67.         'NOT running. The maximum allowed size of the Tile image is 80kb, with a
  68.         'maximum download time of 15 seconds. Only Tile image URLs from the domains listed in
  69.         'Push Client's ListOfAllowedDomains will be accepted. The Tile Title will overwrite
  70.         'the text that labels the tile on the phone's menu, and the Tile Count is
  71.         'shown as a numeric value displayed on top of the Tile image, visually.
  72.         Public Sub PushTileUpdate(TileTitle As String, TileCount As Integer, TileImageURL As String)
  73.             ' Use XmlWriter to construct notification structure/contents.
  74.             Dim myStream As New MemoryStream()
  75.             Dim myWriter As XmlWriter = XmlWriter.Create(myStream)
  76.             myWriter.WriteStartDocument()
  77.             myWriter.WriteStartElement("wp", "Notification", "WPNotification")
  78.             myWriter.WriteStartElement("wp", "Tile", "WPNotification")
  79.             myWriter.WriteStartElement("wp", "BackgroundImage", "WPNotification")
  80.             myWriter.WriteValue(TileImageURL)
  81.             myWriter.WriteEndElement()
  82.             myWriter.WriteStartElement("wp", "Count", "WPNotification")
  83.             myWriter.WriteValue(TileCount)
  84.             myWriter.WriteEndElement()
  85.             myWriter.WriteStartElement("wp", "Title", "WPNotification")
  86.             myWriter.WriteValue(TileTitle)
  87.             myWriter.WriteEndElement()
  88.             myWriter.WriteEndElement()
  89.             myWriter.WriteEndDocument()
  90.             'Transfer Xml output from myWriter's buffer to myStream.
  91.             myWriter.Flush()
  92.             'Send this message to all subscribed devices.
  93.             sendPushToSubscribedURIs(myStream.ToArray(), "tile")
  94.         End Sub
  95.         'This enum gives symbolic names to the numeric values used to "batch together"
  96.         'push notifications according to the specified time intervals. You can send them
  97.         'immediately, within 450 seconds, or within 900 seconds. Allowing the Notification
  98.         'Service to batch notifications will let the service group messages together with
  99.         'notifications from other apps to save phone battery life.
  100.         Public Enum BatchingIntervalValues
  101.             ImmediateTile = 1
  102.             ImmediateToast = 2
  103.             ImmediateRaw = 3
  104.             Wait450SecondsTile = 11
  105.             Wait450SecondsToast = 12
  106.             Wait450SecondsRaw = 13
  107.             Wait900SecondsTile = 21
  108.             Wait900SecondsToast = 22
  109.             Wait900SecondsRaw = 23
  110.         End Enum
  111.         'Iterates through SubscriptionURIs, sending the constructed Push Notification to
  112.         'of the notification, which is every subscribed device via the Microsoft
  113.         'Push Notification Service. The payload passed in, is packaged into an HTTP POST
  114.         'message that defines headers containing the notification type and batching interval.
  115.         Private Shared Sub sendPushToSubscribedURIs(pushPayload As Byte(), notificationType As String)
  116.             'Iterate through SubscriptionURIs
  117.             For Each thisURI As var In SubscriptionURIs.Values
  118.                 'Add headers to HTTP Post message.
  119.                 Dim myRequest = DirectCast(WebRequest.Create(thisURI), HttpWebRequest)
  120.                 ' Push Client's channelURI
  121.                 myRequest.Method = WebRequestMethods.Http.Post
  122.                 myRequest.ContentType = "text/xml"
  123.                 myRequest.ContentLength = pushPayload.Length
  124.                 ' gives this message a unique ID
  125.                 myRequest.Headers.Add("X-MessageID", Guid.NewGuid().ToString())
  126.                 'Customize or exclude the X-WindowsPhone-Target header based on the notification type.
  127.                 Select Case notificationType
  128.                     Case "toast"
  129.                         myRequest.Headers("X-WindowsPhone-Target") = "toast"
  130. myRequest.Headers.Add("X-NotificationClass",
  131. CInBatchingIntervalValues.ImmediateToast).ToString())
  132.                         Exit Select
  133.                     Case "tile"
  134.                         myRequest.Headers("X-WindowsPhone-Target") = "token"
  135. myRequest.Headers.Add("X-NotificationClass",
  136. CIntBatchingIntervalValues.ImmediateTile).ToString())
  137.                         Exit Select
  138.                     Case "raw"
  139.                         myRequest.Headers.Add("X-NotificationClass",
  140.                         (CIntBatchingIntervalValues.ImmediateRaw).ToString())
  141.                         'Raw notifications do not specify a value for the X-WindowsPhone-Target header.
  142.                         Exit Select
  143.                 End Select
  144.                 'Merge headers with payload.
  145.                 Using requestStream = myRequest.GetRequestStream()
  146.                     requestStream.Write(pushPayload, 0, pushPayload.Length)
  147.                 End Using
  148.                 'Send notification to this phone!
  149.                 Dim response = DirectCast(myRequest.GetResponse(), HttpWebResponse)
  150.             Next
  151.         End Sub
  152.     End Class
  153. End Namespace

Comme dernière étape, il faut inclure les fichiers .png qui seront utilisés sous forme de graphiques Tile pour l’application mobile. Vous pouvez utiliser les fichiers .png inclus dans l’exemple du code téléchargeable ou créez les vôtres. Les Tiles doivent être de 80KB ou plus petit en poids et avoir une résolution de 173 x 173 pixels. Ajoutez les fichiers .png au projet WebService en faisant un clic droit sur le Web Service Role et en sélectionnant « Add Existing Item ». Une fois visible dans le Solution Explorer, cliquez sur les fichiers .png et dans le panneau des propriétés définissez la valeur de la propriété « Copy to output Directory » à « Always »

Le web service est maintenant complet et prêt à être publié. Si vous n’êtes pas intéressé par la publication sur Azure, vous pouvez exécuter ce service sur n’importe quel serveur IIS qui possède une connexion à Internet (pour contacter MPNS) et peut être atteint par votre émulateur ou téléphone Windows Phone 7.

Publier votre web service sur Windows Azure

  1. Inscrivez-vous pour un essai gratuit ou classique à un compte Azure. Une fois réalisé, connectez-vous à https://windows.azure.com avec le LiveID associé à votre compte Azure et assurez-vous que vous avez accès aux outils de gestion.
  2. En supposant que vous ayez suivi les instructions de la création du projet ci-dessus, vous serez en mesure de faire un clic droit sur le projet Azure dans le Solution Explorer (avec une icône représentant un globe) et sélectionnez « Publish » à partir du menu, comme indiqué ici :
    image
  3. La fenêtre de déploiement s’affichera. Sous la liste déroulante « Credentials » sélectionnez "Add," comme montré ici:
    image
  4. Dans la fenêtre d’authentification du projet Windows Azure faites défiler vers le bas la liste des identifications, et sélectionnez “Create”. Donner un nom significatif à ces informations d’identification, elles peuvent être réutilisées à l’avenir pour toute activité de publication pour n’importe quel service hébergé sur votre compte. Cliquez sur le lien « copy the full path » du fichier d’identification que vous avez créé puis cliquez à nouveau sur le lien pour visiter le portail Windows Azure sur internet avec le chemin du fichier du certificat dans votre presse papier.
    image
  5. Dans le portail Windows Azure, entrez le menu « Management Certificates » et dans la section « Hosted Services, Storage Accounts & CDN ». Cliquez sur le bouton « Add Certificate » en haut du ruban de navigation. Cliquez sur « Browse » et quand l’on vous demande de sélectionner un certificat à ajouter, collez alors le chemin complet du certificat que vous avez créé à l’étape 4 et cliquez sur « OK ». Cela télécharge le nouveau certificat et génère un Subscription ID qui est associé au certificat. Copiez le Subscription ID dans votre presse papier et revenez à Visual Studio.
    image
  6. Dans Visual Studio, collez le Subscription ID dans le troisième champ de la fenêtre de gestion d’authentification du projet Windows Azure, où un exemple d’ID est déjà entré, et cliquez sur « OK » pour sauvegarder les informations authentifiées
  7. Retournez au portail Windows Azure, cliquez sur « Storage Accounts » dans le menu gauche, et cliquez sur « New Storage Account » à partir du haut du ruban. Donnez un nom significatif à votre compte de stockage. Ce compte peut être réutilisé pour d’autres services hébergés sur Windows Azure. Choisissez un centre de données qui est situé dans une zone souhaitée, et cliquez sur « Create » pour créer le nouveau compte de stockage.
    image
  8. Dans le portail Windows Azure, cliquez sur “Hosted Services” dans le menu gauche, puis cliquez sur “New Hosted Service” en haut du ruban. Entrez un nom significatif ainsi que le préfixe d’URL pour ce service.
    Ceux-ci seront uniques à ce web service. Choisissez le même centre de données où le compte de stockage a été créé (permet d’éviter de payer des frais de trafic entrants/sortants pour le trafic croisant les centres de données) et sélectionnez l’option « Do Not Deploy ». Cliquez sur « OK » quand cela est fait pour créer un nouveau service hébergé.
    image
  9. Retournez dans Visual Studio, fermez la fenêtre de projet de déploiement de Windows Azure et rouvrez-la en faisant un clic droit sur le projet Azure et en sélectionnant à nouveau « Publish ». Cette fois, sélectionnez votre nouvelle identification à partir de la liste déroulante de Credentials ». Visual Studio chargera le « Storage Account » et le « Hosted Service Account » qui sont associés avec ce certificat de Subscription ID. Changez l’environnement de déploiement en « Production ». Cliquez sur « OK » pour publier votre web service sur Windows Azure. Cette étape peut prendre plusieurs minutes. Le journal d’activité de Windows Azure montrera l’état en cours pendant que le service est publié et initialisé.
    image
  10. Quand l’opération est terminée, le web service sera accessible à l’url du site listé par le journal d’activité de Windows Azure. Cette URL correspond au préfixe URL que vous avez entré pour le service hébergé. Ajoutez le nom du fichier .svc à la fin de l’url pour voir la déclaration du WDSL pour votre web service (par exemple https://my_url_prefix.cloudapp.net/Service1.svc). Votre service fonctionne sur Windows Azure et est prêt à être consommé.
    image

Créer une application mobile de réception de Push

Assurez-vous que le Push Service, le web service que nous avons créé plus tôt, a été déployé et possède une connexion Internet afin qu’il puisse relayer les messages au service de notification de push de Microsoft. Dans la section précédente, nous avons atteint cet objectif en publiant sur Windows Azure.

Lancez Visual Studio et démarrez un projet de type « Silverlight for Windows Phone ». Puis créez une interface utilisateur (UI) qui possèdera les éléments suivants :

  • Un TextBlock nommé subscriptionStatus dont le texte est défini par « Checking subscription status…. »
  • Un TextBlock nommé rawmessage, avec son attribut TextWrapping défini à la valeur « Wrap ». Donnez à la propriété Text la valeur « Waiting to Receive Raw Notification »
  • Un TextBlock nommé channelURITextBlock, avec son attribut TextWrapping défini à la valeur « Wrap ». Donnez à la propriété Text la valeur « This App’s ChannelUri : »

Une disposition de ces éléments est proposée et fournie ci-dessous. Ici, un quatrième TextBlock est affiché avec des instructions de test et de déploiement qui sont en bleu clair pour utiliser cette application. Cela est pour vous aider à exécuter l’exemple du code qui s’appuie sur la connexion internet, un web service, et les Push Notifications envoyées seulement après une exécution initiale de l’application sur ce téléphone. De plus, à cause de ses dépendances, l’exemple de ce projet a besoin de plusieurs modifications avant qu’il puisse s’exécuter sur votre téléphone. Ce TextBlock n’est pas mentionné ailleurs dans cet article ou dans le code lui-même.
image

Le document final en XAML contenant ces éléments ressemble à ceci:

XAML (MainPage.xaml)

Code Snippet

  1. <!--LayoutRoot is the root grid where all page content is placed-->
  2. <Grid x:Name="LayoutRoot" Background="Transparent">
  3.     <Grid.RowDefinitions>
  4.         <RowDefinition Height="Auto"/>
  5.         <RowDefinition Height="*"/>
  6.     </Grid.RowDefinitions>
  7.     <!--TitlePanel contains the name of the application and page title-->
  8.     <StackPanel x:Name="TitlePanel" Grid.Row="0" Margin="12,17,0,28">
  9.         <TextBlock x:Name="PushDemo" Text="JoMul Push Demo" Style="{StaticResource PhoneTextNormalStyle}"/>
  10.     </StackPanel>
  11.     <!--ContentPanel - place additional content here-->
  12.     <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
  13.         <TextBlock Height="30" HorizontalAlignment="Left" Margin="12,460,0,0" Name="subscriptionStatus" Text="Checking subscription status..." VerticalAlignment="Top" Width="438" />
  14.         <TextBlock Height="380" HorizontalAlignment="Left" Margin="12,77,0,0" Name="instructions" Text="To use:
  15.                 1) Deploy Push Service to an internet-accessible host (such as Azure).
  16.                 2) In this project (Push Client) right-click on ServiceReference1 in Solution
  17.                 Explorer, then click "Configure Service Reference", updating the address with Push Service's new WSDL URL.
  18.                 3) Edit ListOfAllowedDomains in MainPage.xaml.cs to include the domain that now hosts Push Service.
  19.                 4) Launch this app (Push Client) on your phone so it registers to receive notifications.
  20.                 5) On your PC, launch Visual Studio Command Prompt, and type WCFTestClient. In the client, enter Push Service's WSDL URL, then invoke
  21.                 the methods that send notifications to your phone!" VerticalAlignment="Top" Width="426" TextWrapping="Wrap"
  22.                 TextAlignment="Left" Foreground="Cyan" Visibility="Visible" />
  23.         <TextBlock Height="134" HorizontalAlignment="Left" Margin="12,556,0,0" Name="channelURITextBlock" Text="This App's ChannelURI: " VerticalAlignment="Top" Width="426" TextWrapping="Wrap" />
  24.         <TextBlock x:Name="PageTitle" Text="Push Client" Margin="12,-7,-3,613" Style="{StaticResource PhoneTextTitle1Style}"/>
  25.         <TextBlock Height="70" HorizontalAlignment="Left" Margin="12,493,0,0" Name="rawmessage" Text="Waiting to receive Raw notification." VerticalAlignment="Top" Width="414" TextWrapping="Wrap" />
  26.     </Grid>
  27. </Grid>

Dans le Solution Explorer, faites un clic droit sur “References” et sélectionnez « Add Service Reference ». Entrez l’Url pour le Push Service du fichier .svc (par exemple : https://your_url_prefix.doudapp.net/Service1.svc) et cliquez sur « Go ». Une fois que Visual Studio a confirmé avoir découvert le Push Service, remarquez que le namespace qui est assigné pour la référence au web service, qui est « ServiceReference1 » par défaut, enfin cliquez sur « OK ». Le Push Service peut maintenant être accessible via le namespace ServiceReference1 dans le code de l’application.

Ouvrez le fichier MainPage.xaml.cs et ajoutez les références aux namespace suivants: System.IO.IsolatedStorage, System.IO, Microsoft.phone.Notification ainsi que System.Collections.objectModel.

En haut de la classe MainPage, ajoutez les membres de données suivants:

  1. Un Guid nommé deviceID que nous utiliserons pour enregistrer un identifiant unique pour ce téléphone.
  2. Un « ServiceReference1.Service1Client » nommé myClient que nous utiliserons pour accéder au Push Service. Si vous changez le nom par défaut du namespace du Service Reference ou du Push Service, ce type aura un nom différent. Dans cet article, les valeurs par défaut sont supposées.
  3. Un objet HttpNotificationChannel nommé myPushChannel. C’est le canal qui va écouter les Notifications Push qui sont relayées du MPNS.

Maintenant, nous allons implémenter quelques méthodes qui préparent l’application à la réception des Notifications Push.

  1. Dans la méthode MainPage(), nous vérifions le stockage isolé du téléphone ( stockage interne qui est accessible seulement par cette application) pour une valeur de clé « DeviceID » . Si une valeur est trouvée, elle est chargée à partir de l’Isolated Storage et est assignée au membre de données deviceID. Autrement, une nouvelle valeur Guid est générée, assignée et stockée.
  2. Toujours dans la méthode MainPage(), nous vérifions si il existe une valeur de type HttpNotificationChannel sous la clé « myChannel ». Si elle n’existe pas, elle est créée et stockée ici, alors les fonctions de traitement de l’évènement sont attachées. Le canal de communication est ouvert, celui qui demandera une nouvelle attribution de canal URI du MPNS, à laquelle les Notifications Push peuvent être reçues par ce canal. Si ce canal existait précédemment, nous attacherons tout simplement les fonctions de gestion d’événements, et passerons sur le canal existant du Push Service.
  3. Une méthode nommée attachHandlerFunctions() est implémentée qui spécifie que les fonctions déléguées recevront le callback quand certaines fonctions se seront déclenchées. L’évènement ErrorOccured se déclenche que si l’origine d’une exception est levée dans la méthode myPushChannel. L’événement HttpNotificationReceived se déclenche que lorsque qu’une Raw Notification est reçue. L’événement ChannelUriUpdated se déclenche lorsque le MPNS assigne ou met à jour une nouvelle URI pour la méthode myPushChannel. Et pour finir, un évènement sur MyClient nommé SubscribeMyPhoneCompleted est géré. Cet événement se déclenche quand un appel à la méthode SubscribeMyPhone se termine normalement. Remarquez que vous n’avez pas eu à générer cet événement. Il a été généré automatiquement lorsque vous avez ajouté une référence vers Push Service.

Par la suite, nous devons implémenter les fonctions déléguées que nous assignerons pour gérer les événements spécifiés dans la méthode attachHandlerFunctions() :

  1. La fonction myPushChannel_ErrorOccured sera simplement un message d’erreur affiché sur l’écran en utilisant le TextBlock susbcriptionStatus.
  2. La fonction myPushChannel_HttpNotificationReceived décodera la Notification Push de type Raw en utilisant un StreamReader et l’affichera à l’écran en utilisant le TextBlock rawmessage. Cependant, à cause du déclenchement des événements de Push dans le thread de notification, la mise à jour de rawmessage est traitée avec la méthode BeginInvoke() du Dispatcher
  3. La fonction myClient_SubscribeMyPhoneCompleted affiche un message quand le téléphone a chargé normalement les valeurs de deviceID et de ChannelURI de l’application dans le Push Service en affichant la chaine de caractère « Subscribed ! » dans le TextBlock subscriptionStatus.
  4. myPushChannel_ChannelUriUpdated est la fonction la plus complexe. Ici, l’application vérifie et assure que myPushChannel peut recevoir la Notification Push même quand l’application ne fonctionne pas en vérifiant les valeurs IsShellTileBound et IsShellToastBound. Si ces valeurs sont « False », l’application lie le canal de communication au shell de sorte à ce que les notifications peuvent être reçues quand l’application ne fonctionne pas, en passant une liste des domaines autorisés à envoyer des mises à jour. Ici, le domaine sur lequel nous avons publié le Push Service est spécifié (e.g. https://your_url_prefix.cloudapp.net). La récupération d’une URI sur le canal est notée à l’écran en utilisant une fois encore la méthode BeginInvoke() du Dispatcher, et l’appel à la méthode SubscribeMyPhone() assure que cette URI est connue par le Push Service.

Maintenant que nous avons terminé, la page MainPage.xaml.cs doit ressembler à ceci:

C# (MainPage.xaml.cs)

Code Snippet

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Net;
  5. using System.Windows;
  6. using System.Windows.Controls;
  7. using System.Windows.Documents;
  8. using System.Windows.Input;
  9. using System.Windows.Media;
  10. using System.Windows.Media.Animation;
  11. using System.Windows.Shapes;
  12. using Microsoft.Phone.Controls;
  13. //added
  14. using System.IO.IsolatedStorage;
  15. using System.IO;
  16. using Microsoft.Phone.Notification;
  17. using System.Collections.ObjectModel;
  18. namespace Push_Client_Example
  19. {
  20.     public partial class MainPage : PhoneApplicationPage
  21.     {
  22.         //Data members for this class
  23.         //A unique ID for your phone, saved to internal memory
  24.         Guid deviceID;
  25.         //Add a reference to your deployed Push Service URL and name it ServiceReference1
  26.         //and this line will compile. In Solution Explorer, Right-click References,
  27.         //then click "Add Service Reference," then enter the URL for the SVC file
  28.         //for the Push Service and click "Go." Verify that the
  29.         //Push Service's four methods are indeed exposed then click "OK."
  30.         ServiceReference1.Service1Client myClient = new ServiceReference1.Service1Client();
  31.         //URI for this app's notification channel.
  32.         HttpNotificationChannel myPushChannel;
  33.         // Constructor
  34.         public MainPage()
  35.         {
  36.             InitializeComponent();
  37.             //First, generate a GUID on this phone and save it; reuse if it exists to
  38.             //keep consistent with service's data.
  39.             if (IsolatedStorageSettings.ApplicationSettings.Contains("DeviceId"))
  40.             {
  41.                 //load existing
  42.                 deviceID = (Guid)IsolatedStorageSettings.ApplicationSettings["DeviceId"];
  43.             }
  44.             else
  45.             {
  46.                 //generate new ID
  47.                 deviceID = Guid.NewGuid();
  48.                 IsolatedStorageSettings.ApplicationSettings["DeviceId"] = deviceID;
  49.             }
  50.             //Next, create a notification channel which will have its own URI that the
  51.             //web service will need to know. We're naming the channel for this
  52.             //app "myChannel." Channels need only be created once per app;
  53.             //if the URI ever changes, the ChannelUriUpdated event will fire. This
  54.             //event also fires when the channel is created for the first time.
  55.             myPushChannel = HttpNotificationChannel.Find("myChannel");
  56.             //check to see if this channel has already been created; if so, reuse
  57.             if (myPushChannel == null)
  58.             {
  59.                 rawmessage.Text += " Channel was null.";
  60.                 //This channel needs to be created. ChannelUriUpdated will fire upon completion.
  61.                 myPushChannel = new HttpNotificationChannel("myChannel"); //create, then attach delegates, then Open()
  62.                 attachHandlerFunctions();
  63.                 myPushChannel.Open(); // will not fire ChannelUriUpdated if no handler is wired up first!
  64.             }
  65.             else
  66.             {
  67.                 rawmessage.Text += " Channel was found!";
  68.                 //ChannelUriUpdated is not going to fire. Call subscribing method on
  69.                 //web service. Attach delegates.
  70.                 attachHandlerFunctions();
  71.                 myClient.SubscribeMyPhoneAsync(deviceID, myPushChannel.ChannelUri.ToString());
  72.             }
  73.         }
  74.         void attachHandlerFunctions()
  75.         {
  76.             //attaches delegates to push channel events
  77.             //if error, print onscreen
  78.             myPushChannel.ErrorOccurred += new EventHandler<NotificationChannelErrorEventArgs>(myPushChannel_ErrorOccurred);
  79.             //After call to SubscribeMyPhone completes, notify of success
  80.             myClient.SubscribeMyPhoneCompleted += new EventHandler<System.ComponentModel.AsyncCompletedEventArgs>(myClient_SubscribeMyPhoneCompleted);
  81.             //ChannelUriUpdated fires when channel is first created or the channel URI changes
  82.             myPushChannel.ChannelUriUpdated += new EventHandler<NotificationChannelUriEventArgs>(myPushChannel_ChannelUriUpdated);
  83.             //Handle raw push notifications, which are received only while app is running.
  84.             myPushChannel.HttpNotificationReceived += new EventHandler<HttpNotificationEventArgs>(myPushChannel_HttpNotificationReceived);
  85.         }
  86.         void myPushChannel_HttpNotificationReceived(object sender, HttpNotificationEventArgs e)
  87.         {
  88.             //Fires from shell thread, so updates to UI have to use dispatcher's
  89.             //BeginInvoke() method. The body of the notification is a stream,
  90.             //per the MPNS standard, but we know it's just text per our web
  91.             //service design, so here we just decode, and display.
  92.             Deployment.Current.Dispatcher.BeginInvoke(() =>
  93.             {
  94.                 //this will fire in UI thread
  95.                 StreamReader myReader = new StreamReader(e.Notification.Body);
  96.                 rawmessage.Text = "Received Raw Notification: " + myReader.ReadToEnd();
  97.             });
  98.         }
  99.         void myPushChannel_ChannelUriUpdated(object sender, NotificationChannelUriEventArgs e)
  100.         {
  101.             //also fires in notification thread. There are a couple things we want to do
  102.             //here, once we know we have a valid channel from MPNS.
  103.             // 1) Make sure phone's shell knows this channel is authorized to receive Tile
  104.             //updates when app is not running.
  105.             if (myPushChannel.IsShellTileBound == false)
  106.             {
  107.                 var ListOfAllowedDomains = new Collection<Uri> {
  108. //Lists domains that can send tile updates and so forth as push notifications.
  109. //Only these authorized domains will be allowed by the shell to
  110. //push new tiles to the phone
  111. new Uri(@"https://YOUR WEB SERVICE'S DOMAIN GOES HERE")
  112. //e.g. if you published a webservice at https://foo.com/service1.svc -- put "https://foo.com" here.
  113. };
  114.                 //Register this channel with the shell, pass on authorized
  115.                 //domain in way method expects
  116.                 myPushChannel.BindToShellTile(ListOfAllowedDomains);
  117.             }
  118.             //2) Make sure phone's shell knows this channel is authorized to receive
  119.             //Toast messages when app is not running
  120.             if (myPushChannel.IsShellToastBound == false)
  121.             {
  122.                 myPushChannel.BindToShellToast();
  123.             }
  124.             //3) Show that this event fired onscreen.
  125.             Deployment.Current.Dispatcher.BeginInvoke(() =>
  126.             {
  127.                 rawmessage.Text = "uri updated";
  128.             });
  129.             //4) Pass the new ChannelUri on to the subscription service.
  130.             myClient.SubscribeMyPhoneAsync(deviceID, e.ChannelUri.ToString());
  131.         }
  132.         void myClient_SubscribeMyPhoneCompleted(object sender, System.ComponentModel.AsyncCompletedEventArgs e)
  133.         {
  134.             //Handles completion of call to SubscribeMyPhone() on web service
  135.             if (e.Error == null)
  136.             {
  137.                 // no server-side error occurred
  138.                 subscriptionStatus.Text = "Subscribed!";
  139.             }
  140.             else
  141.             {
  142.                 //show error onscreen
  143.                 subscriptionStatus.Text = e.Error.Message;
  144.             }
  145.             //As a last step, since we know at this point that we will have
  146.             //a valid ChannelUri, print its value onscreen. Don't do this in real
  147.             //life, obviously. Here, it's just to show how MPNS works.
  148.             channelURITextBlock.Text = myPushChannel.ChannelUri.ToString();
  149.         }
  150.         void myPushChannel_ErrorOccurred(object sender, NotificationChannelErrorEventArgs e)
  151.         {
  152.             //handles channel error caused from indirect exception
  153.             subscriptionStatus.Text = e.Message;
  154.         }
  155.     }
  156. }

Visual Basic (MainPage.xaml.vb)

Code Snippet

  1. Imports System.Collections.Generic
  2. Imports System.Linq
  3. Imports System.Net
  4. Imports System.Windows
  5. Imports System.Windows.Controls
  6. Imports System.Windows.Documents
  7. Imports System.Windows.Input
  8. Imports System.Windows.Media
  9. Imports System.Windows.Media.Animation
  10. Imports System.Windows.Shapes
  11. Imports Microsoft.Phone.Controls
  12. 'added
  13. Imports System.IO.IsolatedStorage
  14. Imports System.IO
  15. Imports Microsoft.Phone.Notification
  16. Imports System.Collections.ObjectModel
  17. Namespace Push_Client_Example
  18.     Partial Public Class MainPage
  19.         Inherits PhoneApplicationPage
  20.         'Data members for this class
  21.         'A unique ID for your phone, saved to internal memory
  22.         Private deviceID As Guid
  23.         'Add a reference to your deployed Push Service URL and name it ServiceReference1
  24.         'and this line will compile. In Solution Explorer, Right-click References,
  25.         'then click "Add Service Reference," then enter the URL for the SVC file
  26.         'for the Push Service and click "Go." Verify that the
  27.         'Push Service's four methods are indeed exposed then click "OK."
  28.         Private myClient As New ServiceReference1.Service1Client()
  29.         'URI for this app's notification channel.
  30.         Private myPushChannel As HttpNotificationChannel
  31.         ' Constructor
  32.         Public Sub New()
  33.             InitializeComponent()
  34.             'First, generate a GUID on this phone and save it; reuse if it exists to
  35.             'keep consistent with service's data.
  36.             If IsolatedStorageSettings.ApplicationSettings.Contains("DeviceId") Then
  37.                 'load existing
  38.                 deviceID = CType(IsolatedStorageSettings.ApplicationSettings("DeviceId"), Guid)
  39.             Else
  40.                 'generate new ID
  41.                 deviceID = Guid.NewGuid()
  42.                 IsolatedStorageSettings.ApplicationSettings("DeviceId") = deviceID
  43.             End If
  44.             'Next, create a notification channel which will have its own URI that the
  45.             'web service will need to know. We're naming the channel for this
  46.             'app "myChannel." Channels need only be created once per app;
  47.             'if the URI ever changes, the ChannelUriUpdated event will fire. This
  48.             'event also fires when the channel is created for the first time.
  49.             myPushChannel = HttpNotificationChannel.Find("myChannel")
  50.             'check to see if this channel has already been created; if so, reuse
  51.             If myPushChannel Is Nothing Then
  52.                 rawmessage.Text += " Channel was null."
  53.                 'This channel needs to be created. ChannelUriUpdated will fire upon completion.
  54.                 myPushChannel = New HttpNotificationChannel("myChannel")
  55.                 'create, then attach delegates, then Open()
  56.                 attachHandlerFunctions()
  57.                 ' will not fire ChannelUriUpdated if no handler is wired up first!
  58.                 myPushChannel.Open()
  59.             Else
  60.                 rawmessage.Text += " Channel was found!"
  61.                 'ChannelUriUpdated is not going to fire. Call subscribing method on
  62.                 'web service. Attach delegates.
  63.                 attachHandlerFunctions()
  64.                 myClient.SubscribeMyPhoneAsync(deviceID, myPushChannel.ChannelUri.ToString())
  65.             End If
  66.         End Sub
  67.         Private Sub attachHandlerFunctions()
  68.             'attaches delegates to push channel events
  69.             'if error, print onscreen
  70.             myPushChannel.ErrorOccurred += New EventHandler(Of NotificationChannelErrorEventArgs)(AddressOf myPushChannel_ErrorOccurred)
  71.             'After call to SubscribeMyPhone completes, notify of success
  72. myClient.SubscribeMyPhoneCompleted += New EventHandler(Of System.ComponentModel.AsyncCompletedEventArgs)(AddressOf
  73. myClient_SubscribeMyPhoneCompleted)
  74.             'ChannelUriUpdated fires when channel is first created or the channel URI changes
  75. myPushChannel.ChannelUriUpdated += New EventHandler(Of NotificationChannelUriEventArgs)(AddressOf
  76. myPushChannel_ChannelUriUpdated)
  77.             'Handle raw push notifications, which are received only while app is running.
  78. myPushChannel.HttpNotificationReceived += New EventHandler(Of HttpNotificationEventArgs)(AddressOf
  79. myPushChannel_HttpNotificationReceived)
  80.         End Sub
  81.         Private Sub myPushChannel_HttpNotificationReceived(sender As Object, e As HttpNotificationEventArgs)
  82.             'Fires from shell thread, so updates to UI have to use dispatcher's
  83.             'BeginInvoke() method. The body of the notification is a stream,
  84.             'per the MPNS standard, but we know it's just text per our web
  85.             'service design, so here we just decode, and display.
  86.             Deployment.Current.Dispatcher.BeginInvoke(Function()
  87.                                                           'this will fire in UI thread
  88.                                                           Dim myReader As New StreamReader(e.Notification.Body)
  89.                                                           rawmessage.Text = "Received Raw Notification: " & myReader.ReadToEnd()
  90.                                                       End Function)
  91.         End Sub
  92.         Private Sub myPushChannel_ChannelUriUpdated(sender As Object, e As NotificationChannelUriEventArgs)
  93.             'also fires in notification thread. There are a couple things we want to do
  94.             'here, once we know we have a valid channel from MPNS.
  95.             ' 1) Make sure phone's shell knows this channel is authorized to receive Tile
  96.             'updates when app is not running.
  97.             If myPushChannel.IsShellTileBound = False Then
  98.                 'Lists domains that can send tile updates and so forth as push notifications.
  99.                 'Only these authorized domains will be allowed by the shell to
  100.                 'push new tiles to the phone
  101.                 'e.g. if you published a webservice at https://foo.com/service1.svc -- put "https://foo.com" here.
  102.                 Dim ListOfAllowedDomains = New Collection(Of Uri)() From { _
  103.                 New Uri("https://YOUR WEB SERVICE'S DOMAIN GOES HERE") _
  104.                 }
  105.                 'Register this channel with the shell, pass on authorized
  106.                 'domain in way method expects
  107.                 myPushChannel.BindToShellTile(ListOfAllowedDomains)
  108.             End If
  109.             '2) Make sure phone's shell knows this channel is authorized to receive
  110.             'Toast messages when app is not running
  111.             If myPushChannel.IsShellToastBound = False Then
  112.                 myPushChannel.BindToShellToast()
  113.             End If
  114.             '3) Show that this event fired onscreen.
  115.             Deployment.Current.Dispatcher.BeginInvoke(Function()
  116.                                                           rawmessage.Text = "uri updated"
  117.                                                       End Function)
  118.             '4) Pass the new ChannelUri on to the subscription service.
  119.             myClient.SubscribeMyPhoneAsync(deviceID, e.ChannelUri.ToString())
  120.         End Sub
  121.         Private Sub myClient_SubscribeMyPhoneCompleted(sender As Object, e As System.ComponentModel.AsyncCompletedEventArgs)
  122.             'Handles completion of call to SubscribeMyPhone() on web service
  123.             If e.[Error] Is Nothing Then
  124.                 ' no server-side error occurred
  125.                 subscriptionStatus.Text = "Subscribed!"
  126.             Else
  127.                 'show error onscreen
  128.                 subscriptionStatus.Text = e.[Error].Message
  129.             End If
  130.             'As a last step, since we know at this point that we will have
  131.             'a valid ChannelUri, print its value onscreen. Don't do this in real
  132.             'life, obviously. Here, it's just to show how MPNS works.
  133.             channelURITextBlock.Text = myPushChannel.ChannelUri.ToString()
  134.         End Sub
  135.         Private Sub myPushChannel_ErrorOccurred(sender As Object, e As NotificationChannelErrorEventArgs)
  136.             'handles channel error caused from indirect exception
  137.             subscriptionStatus.Text = e.Message
  138.         End Sub
  139.     End Class
  140. End Namespace

Test

Si vous testez sur l’émulateur de Windows Phone, suivez ces instructions pour vous assurer qu’un proxy SOCKS a bien été inscrit dans le panneau de contrôle des options Internet de votre ordinateur.

Exécutez l’application mobile. Vous devriez voir la chaîne de caractère « Subscribed! » sur l’écran. Cela signifie que le téléphone est prêt à recevoir des Push Notifications. Pour envoyer ces notifications, nous utiliserons un outil pour invoquer le Push Service.

Lancez la commande de Visual Studio et saisissez “WCFTestClient”. Cet outil aussi peut être accédé en entrant les chemins suivants ; %ProgramFiles(x86)%\Microsoft Visual Studio 10.0\Common7\IDE (sur des systèmes 64-bit) et %ProgramFiles%\Microsoft Visual Studio 10.0\Common7\IDE (sur des systèmes 32-bit).

Dans l’outil WCF Test Client, allez dans « File » > « Add Service », et entrez l’url du .svc pour le Push Service (https://your_url_prefix.cloudapp.net/Service1.svc).

En utilisant l’outil WCF Test Client, vous invoquez la méthode PushRawData() pendant que l’application est en marche, elle enverra une chaîne de caractère à l’application. Celle-ci devrait rapidement apparaitre à l’écran.

Quittez l’application en appuyant sur le bouton de retour, et épinglez l’application sur le menu de démarrage du téléphone par un appui long sur l’icône de l’application et sélectionnez « Pin to Start » de la fenêtre contextuelle. Vous pouvez maintenant aller à la page de démarrage du téléphone et vous apercevoir que votre application est présente

En utilisant le WCF Test Client, vous invoquez la méthode PushTileUpdate(), saisissez l’url pour l’un des fichiers .png que vous avez inclus quand vous avez déployé le Push Service (https://your_url_prefix.doudapp.net/Service1.svc) comme valeur pour le paramètre TileImageURL.

Entrez ce que vous voulez pour les autres paramètres. Le Live Tile pour l’application présente sur le menu de démarrage devrait momentanément se mettre à jour en montrant toutes ces modifications.

Enfin, invoquez la méthode PuchToast(), entrez un sujet et le corps pour votre message. La notification apparaitra sur l’écran du téléphone et vous pouvez la toucher pour rentrer à nouveau dans l’application.

image

Voir aussi