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

Exploring Raw Notifications in Windows Store apps

(1 votes)
Andrea Boschin
Andrea Boschin
Joined Nov 17, 2009
Articles:   91
Comments:   9
More Articles
0 comments   /   posted on Jan 28, 2013
Categories:   Windows 8

In a couple of articles I wrote in my last series, I've spoken about Push notifications, explaining deeply three types of notifications: Toast, Tiles and Badge. These are for sure the most common type of notifcations that affects directly, without nothing more than a careful configuration, these kind of messages in Windows 8. As an example, when your application gets a tile notification, it is able to show it on the application Tiles without virtually any intervention of additional code. This is the same with Toasts and Badges that are visually different but are automatically handled.

Differently, sometimes, you do not need to have your tile updated or a toast message to popup to capture the user attention, but you have to send your own notification with a custom payload that is handled by your code to show a totally different notification or doing someting totally alternative.

The raw way...

In the previous articles I've explained that Tile, Toast and Badge notifications are a way to exchange a short chunk of xml message that is directly understood by the operating system. This xml is the same message you have to build when you need to update these surfaces from your code. So, effectively the sole difference between a local notification and a push notification is in the way the message is sent to the "Windows Notification Service" to be spreaded across a moltitude of subscribers. The case of "raw notifications" is absolutely similar because the message is sent to the WNS, but you have not any constraints about the content and the form, of the message. What you send is a byte array and you are free of using this space as it is better for your needs.

In this article I'll show an example to create a simple chat using raw notifications. I will give a complete coverage about what you have to do to correcly setup and send a raw notification and, obviously, also to receive and handle incoming messages. But for the missing details please refer to my previous articles (part #1 and part #2). Please take this example only as a proof of concept and as a tutorial about raw notifications and not as a suggestion on how to use them. A chat for sure is not the right application to implement with push notifications.

The first thing to do is to get the tokens from the Windows Store dashboard. Once you created an application and reserved the name you can go to the "Advanced" section and enable push notifications. This task is shared for common and raw notification and finally gives you a couple of tokens you have to use in the WCF service that wraps the chat. Once you owns the tokens it is time to setup a simple WCF service. Refere to this article to understand how to implement authentication to WNS. The service exposes two methods:

   1: [ServiceContract]
   2: public interface INotificationService
   3: {
   4:     [OperationContract]
   5:     void Register(string name, Uri uri);
   6:     [OperationContract]
   7:     void NotifyMessage(Uri uri, string message);
   8: }

The "Register" method is in charge of associating an identity (the name) to the Uri that identifies the client. This Uri is got by the client when it creates an instance of the PushNotificationChannel. In this method the uri is added to a dictionary named Clients. This dictionary contains a reference to all clients that have previously called the Register method and is critical for concurrency. It is the reason why it is declared as ConcurrentDictionary.

   1: public void Register(string name, Uri uri)
   2: {
   3:     this.Clients.AddOrUpdate(uri, name, (s, u) => name);
   5:     XDocument xml = new XDocument(
   6:         new XElement("raw",
   7:             new XAttribute("sender", name),
   8:             new XAttribute("command", "enter"),
   9:             new XAttribute("timeStamp", DateTime.Now)));
  11:     this.SendToWNS(xml, NotificationType.Raw);
  12: }

At the end of the method a small xml message is composed and then it is sent as raw notification. The message has the following form:

<raw sender="andrea" command="enter" timeStamp="2013-01-27T16:55:00" />

The "NotifyMessage" method, instead, is in charge of getting the Uri and the message and deliver it to the connected clients. The uri is used to search the name of the registered user in the client dictionary. So the method  prepare another message in xml and sends it as a raw notification.

   1: public void NotifyMessage(Uri uri, string message)
   2: {
   3:     string client;
   5:     if (this.Clients.TryGetValue(uri, out client))
   6:     {
   7:         XDocument xml = new XDocument(
   8:             new XElement("raw",
   9:                 new XAttribute("sender", client),
  10:                 new XAttribute("command", "message"),
  11:                 new XAttribute("timeStamp", DateTime.Now),
  12:                 message));
  14:         this.SendToWNS(xml, NotificationType.Raw);
  15:     }
  16: }

The content of the message is very close to the previous xml I shown. It is in a format that I've decided, to transport the information I need to display messages in a chat. There is not any rule that limits what it contains. The choice of xml is only to be able to deserialize it easily but a binary format would be perfectly legal. Only be careful of staying under 5 kb in size because this is the limit for a raw notification's payload.

As for a tile notification, to send a raw message you have to post it to the WNS uri provided by the client. You have only to specify different parameters in message headers and then serialize the message to a byte array. Here is the content of the message that sends the raw notification:

   1: private void SendToWNS(XDocument message)
   2: {
   3:     foreach (Uri uri in from client in this.Clients
   4:                         select client.Key)
   5:     {
   6:         try
   7:         {
   8:             this.SendToWNS(uri, message);
   9:         }
  10:         catch (Exception ex)
  11:         {
  12:             Debug.WriteLine("{0}", ex);
  13:         }
  14:     }
  15: }
  17: private string SendToWNS(Uri uri, XDocument message)
  18: {
  19:     HttpWebRequest request = HttpWebRequest.Create(uri) as HttpWebRequest;
  20:     request.Method = "POST";
  21:     request.Headers.Add("X-WNS-Type", "wns/raw");
  22:     request.Headers.Add("X-WNS-RequestForStatus", "true");
  23:     request.ContentType = "application/octet-stream";
  24:     request.Headers.Add("Authorization", String.Format("Bearer {0}", this.Token.AccessToken));
  25:     byte[] contentInBytes = Encoding.UTF8.GetBytes(message.ToString(SaveOptions.DisableFormatting));
  27:     using (Stream requestStream = request.GetRequestStream())
  28:         requestStream.Write(contentInBytes, 0, contentInBytes.Length);
  30:     using (HttpWebResponse webResponse = (HttpWebResponse)request.GetResponse())
  31:     {
  32:         return webResponse.StatusCode.ToString();
  33:     }
  34: }

The rows in yellow show the differences of a raw notification. The X-WNS-Type report a "wns/raw" value and the "ContentType" is set to "application/octet-stream" that is a binary stream. All the other code is equal to the other notifications.

Receive raw notifications

To receive raw notifications you have two ways. The first is to create a Background Task, in a way similar to the other kind of notifications, or you can listen on the PushNotificationChannel while the application is running to be notified when a notification arrives. In this example I'll implement the second way, just because chatting when the application is closed is not so easy... First of all I'll initialize the notification channel:

   1: private async void HandlePageLoaded(object sender, RoutedEventArgs e)
   2: {
   3:     this.SetState(false);
   5:     try
   6:     {
   7:         this.Channel = await PushNotificationChannelManager.CreatePushNotificationChannelForApplicationAsync();
   8:         this.Channel.PushNotificationReceived += Channel_PushNotificationReceived;
   9:         this.Client = new NotificationServiceClient();
  10:     }
  11:     catch (Exception ex)
  12:     {
  13:         this.DisplayException(ex);
  14:     }
  15: }

After the channel has created I attach the PushNotificationReceived event to get a notification when an incoming message arrives. Then in the following code I send a notification after the user provides its name. This is done using a proxy to the WCF service. The method that sends a message is not shown but it is really close to this one.

   1: private async void HandleConnectButtonClick(object sender, RoutedEventArgs e)
   2: {
   3:     try
   4:     {
   5:         string name = GetName();
   7:         await this.Client.RegisterAsync(name, new Uri(this.Channel.Uri));
   8:         this.SetState(true);
   9:     }
  10:     catch (Exception ex)
  11:     {
  12:         this.DisplayException(ex);
  13:     }
  14: }

When the notification is delivered to the WCF service it push the raw notification to all the connected urls so the notification is forwarded to all the clients and this triggers the Channel_PushNotificationReceived method that have to handle the raw notification:

   1: private void Channel_PushNotificationReceived(PushNotificationChannel sender, PushNotificationReceivedEventArgs args)
   2: {
   3:     try
   4:     {
   5:         RawNotificationContent content = new RawNotificationContent(args.RawNotification.Content);
   7:         if (string.Compare(content.Command, "enter", StringComparison.OrdinalIgnoreCase) == 0)
   8:         {
   9:             Log("{0} entered the chat", content.Sender);
  10:         }
  11:         else if (string.Compare(content.Command, "message", StringComparison.OrdinalIgnoreCase) == 0)
  12:         {
  13:             Log("{0}: {1}", content.Sender, content.Message);
  14:         }
  16:         args.Cancel = true;
  17:     }
  18:     catch (Exception ex)
  19:     {
  20:         this.DisplayException(ex);
  21:     }
  22: }

The RawNotificationContent class is a simple deserializer that uses a XDocument to read my own format and fill out the properties of the class. In my example I have a sender, a timeStamp, a command and an optional message. The command identifies if I'm receiving a new user or a message from a known user. The result is a different message.





Proper usage of raw notifications

As I've already said, a chat is not a suggested use for raw notifications. The number of messages that may be handled by an active chat is really high and I suppose there may be a limit on the number of notifications you can send for free. But this does not means that raw notifications are totally unuseful. There is a number of usages I can imagine:

1) Conditional Tile and Toast notification

When you sends a tile or toast notification you know it is delivered to the client and automatically published. Using a raw notification, you can send a raw message and apply a filter to incoming notifications, and you can publish on tiles or toasts using some filtering logic on the client. Let say you post notifications about a list of topics but the user is interested only in "soccer". You can apply a filter to incoming notifications and open a tile only when one or more notification in the "soccer" topic has been received. All the other are discarded or stored to be shown only when the user opens the application.

2) Clear previous notifications

Let say you posted a number of tile notifications and you need to reset them because they are expired or you need to remove some kind of error. With a raw notification you can achieve this result easily.

3) Update application's configuration

Sometimes the configuration of the application, stored in the local storage may need to be changed to reflect some kind of updates in services. As an example you can update a limit that is removed because the user bought an additional service. Raw notifications and a background task may be the right way of doing this.

4) Ask the application to download something

Imagine you have an awesome background of your app and you need to update it weekly. With a raw notification you can push a message and ask the application to download the new background and cache it in the local storage.

Raw notification is for sure a good friend and gives you great opportunities to express your fantasy and create successful applications.



No comments

Add Comment

Login to comment:
  *      *       

From this series