(X) Hide this
    • Login
    • Join
      • Generate New Image
        By clicking 'Register' you accept the terms of use .

Windows 8 Metro: Implementing push notifications (part 2)

(3 votes)
Andrea Boschin
>
Andrea Boschin
Joined Nov 17, 2009
Articles:   91
Comments:   9
More Articles
3 comments   /   posted on Nov 08, 2012
Categories:   Windows 8
Tweet

In the previous number I've introduced push notifications in Windows 8, talking about architectural topics to understand the way this feature works, and about the authentication phase where the client and the cloud service both authenticate themselves to the WNS, to establish a working relation between the actors. Now that the service has been created and the client is connected, the time has come to send out first notification. In this article I will cover, from the simpler to the most complex, notifications that are automatically handled by the client runtime and become badge, tile and toasts.

Back to the cloud service

In my example, the service exposes a number of methods that are useful to ask for a notification. In a real world scenario, probably it should be the service itself that decide when, what and why to send a notification. The example I will talk about instead exposes method to the cloud that let a client to invoke a notification that is spreaded to all the connected clients included itself. You can think at it as a sort of "chat" made using notifications. In the previous article I shown the service contract:

   1: [ServiceContract]
   2: public interface INotificationService
   3: {
   4:     [OperationContract]
   5:     void Register(Uri uri);
   6:     [OperationContract]
   7:     void NotifyTile(string message);
   8:     [OperationContract]
   9:     void NotifyToast(string message);
  10:     [OperationContract]
  11:     void NotifyRaw(string message);
  12:     [OperationContract]
  13:     void NotifyBadge(string badge);
  14: }

The methods I would like to implement are the "NotifyBadge", "NotifyTile" and "NotifyToast". All these method require which the message is send in the same way, so the first task is to write a chunk of code that takes the message composed by the caller, packages it in a POST with some headers, then sends it to the WNS. This method should handle one notification at a time and will be called multiple times, one for each connected client. But here is the code.

   1:  
   2: private string SendToWNS(Uri uri, XDocument message, NotificationType notificationType)
   3: {
   4:     HttpWebRequest request = HttpWebRequest.Create(uri) as HttpWebRequest;
   5:  
   6:     request.Method = "POST";
   7:     request.Headers.Add("X-WNS-Type", this.GetNotificationType(notificationType));
   8:     request.Headers.Add("X-WNS-RequestForStatus", "true");
   9:     request.ContentType = "text/xml";
  10:     request.Headers.Add("Authorization", String.Format("Bearer {0}", this.Token.AccessToken));
  11:  
  12:     byte[] contentInBytes = Encoding.UTF8.GetBytes(message.ToString(SaveOptions.DisableFormatting));
  13:  
  14:     using (Stream requestStream = request.GetRequestStream())
  15:         requestStream.Write(contentInBytes, 0, contentInBytes.Length);
  16:  
  17:     using (HttpWebResponse webResponse = (HttpWebResponse)request.GetResponse())
  18:     {
  19:         Debug.WriteLine(webResponse.Headers["X-WNS-DEVICECONNECTIONSTATUS"]);
  20:         Debug.WriteLine(webResponse.Headers["X-WNS-NOTIFICATIONSTATUS"]);
  21:         Debug.WriteLine(webResponse.Headers["X-WNS-MSG-ID"]);
  22:         Debug.WriteLine(webResponse.Headers["X-WNS-DEBUG-TRACE"]);
  23:  
  24:         return webResponse.StatusCode.ToString();
  25:     }
  26: }
  27:  
  28: private string GetNotificationType(NotificationType notificationType)
  29: {
  30:     switch (notificationType)
  31:     {
  32:         case NotificationType.Badge:
  33:             return "wns/badge";
  34:         case NotificationType.Tile:
  35:             return "wns/tile";
  36:         case NotificationType.Toast:
  37:             return "wns/toast";
  38:         case NotificationType.Raw:
  39:             return "wns/raw";
  40:     }
  41:  
  42:     throw new NotSupportedException("Type is not supported");
  43: }

The body of the method creates an HttpWebRequest with the POST method. Then it adds a couple of headers:

X-WNS-Type: indicates the type of notification to send. It should be "wns/badge" for badge notifications, "wns/tile" for tiles and "wns/toast" for toast messages. In the case of raw notifications its value is "wns/raw".

X-WNS-RequestForStatus: if set to true asks to the WNS to return the status of the call to the client. This helps to know if the client has received the notification or if it has been dropped. On the basis of the return value the service should take some action to invalidate the Uri.

ContentType: This value is always "text/xml" for the type of notifications we have to implement. With raw notifications its value is "application/octet-stream".

Authorization: this header contains the access token emitted by the login accomplished by the service when it has started. The call to the service may result in an expired token so in this case the service should be repeat the autentication and then try again to send the notification. To remain simple in my example this part is omitted.

In the following part the body of the request (I will return later on the format of this body) is attached to the POST message and then it is wrote on the network. You get two result:

  1. the http status code indicates if the call to the WNS has been successfully completed (200) or if it has failed (a number of 400 codes). Depending on the code you can understand if the Uri is still valid or not.
  2. a number of http headers returns various details of the call. The most important are X-WNS-DEVICECONNECTIONSTATUS that indicate if the device is connected and X-WNS-NOTIFICATIONSTATUS that informs about the delivery of the notification. Other values may be used to notify problems of the WNS itself and track the call onto the WNS log.

Every time a notification occurs, the service should iterate all connected clients and try to send the notification to each one. It should also check that the notification has been sent successfully and in case of failure remove the Uri from its list:

   1: private void SendToWNS(XDocument message, NotificationType notificationType)
   2: {
   3:     foreach (Uri uri in this.Clients)
   4:     {
   5:         string status = this.SendToWNS(uri, message, notificationType);
   6:         Debug.WriteLine("{0} send {1}", notificationType, status);
   7:     }
   8: }

Sending an update to badge, tile and toasts require the creation of a message in xml. If you remember the content of my previous articles about tiles and badges, it becomes already clear how the message could be created. But for the sake of completeness I will show now the three case.

Sending a badge update

Badge updates are the most simple case. If you remember you have a number of predefined badges you can use that are the numbers from 1 to 99+ and a series of little images. The message to send is so simple that does not requires any explanation:

   1: <badge value="alert"" />

Given this message the NotifyBadge method of the service is created in this way:

   1: public void NotifyBadge(string badge)
   2: {
   3:     XDocument xml = XDocument.Parse(@"<badge value=""" + badge + @""" />");
   4:     this.SendToWNS(xml, NotificationType.Badge);
   5: }

This is oversimplified because it should check for the passed value to be valid but it give an idea of the required effort.

Sending a tile update

Tile update are also something of known. It is slightly more complex that the badge update because it let you specify different templates. You are in charge of specifying at least one template for each size of the tile (square and/or wide), but the message has to be unique. In the following snippet I reported a simple update that changes the text on the tile:

   1: <tile>
   2:     <visual>
   3:         <binding template="TileWideText03">
   4:             <text id=""1"">Here goes the message</text>
   5:         </binding>  
   6:     </visual>
   7: </tile>

The value specified in the template attribute determines the structure of the following part. In this page you can find the right template on the basis of the aspect you want to get for the tile. There are square and wide tiles, and beside you find the content of the message to send. So, the NotifyTile method is also simple:

   1: public void NotifyTile(string message)
   2: {
   3:     XDocument xml = XDocument.Parse(@"<tile>
   4:         <visual>
   5:             <binding template=""TileWideText03"">
   6:                 <text id=""1"">" + message + @"</text>
   7:             </binding>  
   8:         </visual>
   9:     </tile>");
  10:  
  11:     this.SendToWNS(xml, NotificationType.Tile);
  12: }

Sending a toast message

Finally the toast message. A Toast is a message that is shown on top of running application. The screen can host a maximum of three concurrent toasts and they are shown on the top right corner of the screen, one behind the other. After a timeout has passed without the user interaction the toast disappear. If you click the toast the related application is started. A toast, like a tile can be configured in a number of ways. It can contain only text, title and text or also a small image. Also these configurations correspond to a template that you can find in this page. In my example I use the simple text template:

   1: <toast launch="identifier">
   2:     <visual lang="en-US">
   3:         <binding template="ToastText01">
   4:             <text id="1">Here goes the message</text>
   5:         </binding>
   6:     </visual>
   7: </toast>

The "launch" attibute contains an argument that is passed to the OnLaunch method when the tile is clicked. My method that send a toast is made as follow:

   1: public void NotifyToast(string message)
   2: {
   3:     XDocument xml = XDocument.Parse(@"<toast launch=""" + Guid.NewGuid().ToString() + @""">
   4:         <visual lang=""en-US"">
   5:             <binding template=""ToastText01"">
   6:                 <text id=""1"">" + message + @"</text>
   7:             </binding>
   8:         </visual>
   9:     </toast>");
  10:  
  11:     this.SendToWNS(xml, NotificationType.Toast);
  12: }

Again, remember that is is oversimplified to leave it simple to understand. But you have to made a number of checks to avoid expected errors. In this case you should encode the message because the presence of symbols like <, > and & can lead to a malformed XML and then to an exception.

The client point of view

Up to here I've talked about the server side. But what it is in charge of the client when it receives one of the previous notifications? Almost nothing is the first answer. Badge, Tiles and Toast are automatically handled by the underlying operating system and they are automatically displayed when they arrives. There is two things the client have to do. First of all it have to ensure that the system is ready to receive notifications. Push Notifications are reserved to applications that are set for the Lock screen. If the app have not been added to the lock screen all the content of the articles I wrote is completely unuseful. So the client has to be proactive in asking to the user if he wants to add the application to the seven that are enabled to the lock screen. Here is an example:

   1: BackgroundAccessStatus status = BackgroundExecutionManager.GetAccessStatus();
   2:  
   3: if (status == BackgroundAccessStatus.Unspecified)
   4:     await BackgroundExecutionManager.RequestAccessAsync();

The second thing that the client can do is to handle activation from toasts and tiles. This happens handling the OnLaunched event in the App.xaml.cs. When the application is activated it gets a value in the "Arguments" property that should be used to discriminate from where the activation comes and eventually react in the right way.

Finally the developer. He is in charge of configuring the right capabilities from the manifest. He has to enable Toasts from the first screen and then provide the required images for the variuos sizes of the tiles. Then, given that we have to access the network, the application has to be granted with the "Internet" capability. A very low effort.

Other kind of notifications

I've omitted the topic of Raw notifications. These are subtle different and require an explanation that is someway too complex to be included into the article. Suffice to say that raw notifications require a greater effort from the client side because they can be handled by the running application or by a background task. Its goal is to provide messages that influence the behavior of the running application or that change the configuration. They are always invisible when they are handled in background but may become evident when handled from the running application. The example I provided in this two articles is for sure capable of sending also raw notification with some slight change, but handling it from the client is almost another story.


Subscribe

Comments

  • Rikar

    Re: Windows 8 Metro: Implementing push notifications (part 2)


    posted by Rikar on Jan 02, 2013 19:57

    Hi Andrea, thank you for your tutorials, they are very useful.

    I have a problem with push notifications: I'm using a JAVA web service to send the notifications to the windows 8 app. I must use JAVA for the WS.

    Anyway, I can authenticate the WS and, when I send the toast and the badge notifications, I get a HTTP code of 200, so I don't think that the problem is in the server-side.

    In the client side, I can register to get an URI and I have attached an handler for the PushNotificationReceived event.

    I have associated the app with the name I have reserved in the Windows Store Developer Center and I ask to the user to allow the notifications (in fact, when i go to settings > notifications I can see that my app is enabled). I have alse modified the manifest in order to enable the toast and the tileAndBadge notification.

    The problem arises when the web server sends a notification (actually i have tried only badge and toast) to the client. The server says 200, but the client does not receive anything. I have tried to lock the screen, to send the notification with the app closed on the start screen, I have tried with the app in background in debug mode. Nothing.

    I think I am missing something but I can't see what.... what do you think?

    Thank you,

        Rikar.

  • AndreaBoschin

    Re: Windows 8 Metro: Implementing push notifications (part 2)


    posted by AndreaBoschin on Jan 03, 2013 00:49

    Hi Rikar,

    It is hard to give you an answer. It seems you implemented the things correctly. I suggest you to double check the format of the notification and the content of returned http headers X-WNS-DEVICECONNECTIONSTATUS and X-WNS-NOTIFICATIONSTATUS to ensure the message has been delivered.

    Bye.

    Andrea

  • Rikar

    Re: Windows 8 Metro: Implementing push notifications (part 2)


    posted by Rikar on Jan 04, 2013 13:10
    Hi Andrea,

        Thank for your answer. Actually,  X-WNS-DEVICECONNECTIONSTATUS and X-WNS-NOTIFICATIONSTATUS return "connected" and "received", respectively.

    Anyway, I found my problem: when I sent the xml representation of the notification, I encoded it in a base64, as you show in your example. I tried not to encode it and, automagically, it worked. So, I suppose that java encode automatically the body of a request and so I do not need to encode it explicitly.

    I wrote these few lines hoping that they could help others that experience the same problem.

     Bye,

        Rikar

Add Comment

Login to comment:
  *      *       

From this series