Free Trial

Safari Books Online is a digital library providing on-demand subscription access to thousands of learning resources.

  • Create BookmarkCreate Bookmark
  • Create Note or TagCreate Note or Tag
  • PrintPrint
Share this Page URL
Help

13. Windows Phone 7 > Working with push notifications using the cloud

Working with push notifications using the cloud

Working with push notifications using the cloud In the previous recipes, we saw that the model of the WP7 OS is such that only one application can be running at any given moment (apart from a few built-in applications). The big advantage of this model is the performance benefit. No longer can an application that's running in the background leak memory and in the end, lock up the entire device. With the single running application model, all these are memories of the past. Of course, it's not all good. On some occasions, we may want to receive updates from an application, say a stock application. To receive these updates, the application must be running. On the other hand, we want to use the phone for other applications in the meantime as well. This seems, at first hand, an impossible thing to do. There is a solution, however, in the form of push notifications. As the word says, a push notification is a message being pushed to the device, wherever it may be, over a network connection from the cloud. The push service is a service hosted by Microsoft Windows Azure, Microsoft's cloud offering. In this recipe, we'll take a look at how we can work with these notifications and what other advantages they offer. Getting ready This recipe builds on an already existing WCF service that returns a list of Blu-rays, like we had at the end of the Getting data on your Windows phone 7: using WCF recipe. You can use the code from that recipe or, alternatively, use the starting solution located in the in Chapter13/ BluRayCollector_Push_Notifications_Starter. The completed solution is located in the Chapter13/ BluRayCollector_Push_Notifications_Completed folder. This recipe, just like almost all others in this chapter, uses the BluRayCollector database. How to do it... This recipe will guide you through the entire process of getting up and running with WP7 push notifications. We'll need to create server-side code and of course make changes in the WP7 application. To make things easier, in the following steps, we'll look at setting up toast notifications. A toast notification appears on top of any other running application at the top of the screen, as shown in the following screenshot: Complete the following steps to understand notifications in a WP7 application: We'll kick off with the "service" part. Why the quotes, you may ask. The notifications process involves several parties: The WP7 application.A service (created by us) that wants to send updates to the device(s) that are registered to receive messages. This can be any type of application though; in our case, this will be a webpage.A service from Microsoft in the cloud. Our service/application will ask this service to send specific content to the devices. The service, as mentioned, in our case will be a web page that we can use to trigger the sending of messages. In real-life scenarios, this is probably a web service as well, which can be called by any type of application. The web page we are using here is to be hosted in a new project. Add a new ASP.NET Empty Web Application to the solution and name it BluRayCollector.PushNotifications.Web. Also, add a blank page to this site called Default.aspx. The UI for this ASP.NET WebForms page is very trivial. Take a look in the code samples of the book for the full markup code for this. The following screenshot shows what the page looks like: As can be seen, the page needs a URL and some text for the Title and Content fields, in case of the toast notification type. The data that will be sent to the device is XML with a specific format. The URL is a unique URL, linked to a specific application on a specific device. When we click on the Send single push notification button, the following code will be executed: private void SendToastMessage() { string toastXml = "<?xml version=\"1.0\" encoding=\"utf-8\"?>" + "<wp:Notification xmlns:wp=\"WPNotification\">" + "<wp:Toast>" + "<wp:Text1>{0}</wp:Text1>" + "<wp:Text2>{1}</wp:Text2>" + "</wp:Toast>" + "</wp:Notification>"; string toastMessage = string.Format(toastXml, txtTitle.Text, txtContent.Text); byte[] bytes = new UTF8Encoding().GetBytes(toastMessage); SendMessage( new Uri(txtUrl.Text), bytes, MessageType.Toast); } First, the XML is shown. This XML can't be changed, it should be exactly this piece of text. We then paste in the values added by the user. Combined, this string can't exceed a maximum value of 1024 bytes. After that, we call the SendMessage() method, passing in the URI to which we want to send the message, a byte array containing the message, and an enumeration value.Next, add the enumeration MessageType as shown in the following code: public enum MessageType { Tile, Toast } Up next is the SendMessage() method we just used. This method starts by creating an HttpWebRequest to the Uri. private void SendMessage (Uri uri, byte[] bytes, MessageType messageType) { HttpWebRequest notificationRequest = (HttpWebRequest)WebRequest.Create(uri); } This request needs to be configured correctly, as shown in the following code. We specify that it uses a POST method, uses the text/XML application type, and then we add the correct headers. Finally, we specify the content length. notificationRequest.Method = WebRequestMethods.Http.Post; notificationRequest.Headers = new WebHeaderCollection(); notificationRequest.ContentType = "text/xml"; notificationRequest.Headers.Add("X-MessageID", Guid.NewGuid() .ToString()); switch (messageType) { case MessageType.Tile: notificationRequest.Headers .Add("X-WindowsPhone-Target", "token"); notificationRequest.Headers .Add("X-NotificationClass", "1"); break; case MessageType.Toast: notificationRequest.Headers .Add("X-WindowsPhone-Target", "toast"); notificationRequest.Headers .Add("X-NotificationClass", "2"); break; //case raw not implemented here } notificationRequest.ContentLength = bytes.Length; With the request configured, we can write the XML message to the request stream. The following code shows that we are writing the bytes parameter, passed in to the SendMessage() method earlier, to the request stream. using (Stream requestStream = notificationRequest.GetRequestStream()) { requestStream.Write(bytes, 0, bytes.Length); } In the next step, we fire off the request and read out the response. This is done in the following code: try { HttpWebResponse response = (HttpWebResponse)notificationRequest.GetResponse(); var notificationStatus = response.Headers["X-NotificationStatus"]; var subscriptionStatus = response.Headers["X-SubscriptionStatus"]; var deviceConnectionStatus = response.Headers["X-DeviceConnectionStatus"]; lblStatus.Text = string.Format("NotificationStatus: {0}<br/> SubscriptionStatus: {1}<br/>DeviceConnectionStatus: {2}", notificationStatus, subscriptionStatus, deviceConnectionStatus); } catch (Exception ex) { lblStatus.Text = "Sending the message failed: " + ex.Message; } We can see if everything went well by looking at the response headers. In this case, we are showing the result in the UI; in a real-life scenario, we could, based on these headers, take a specific measure such as trying to send again or logging the error.The web page is ready. Let's turn our attention to the WP7 application. If it doesn't exist yet, add a new page called Settings.xaml.From the BluRayOverview.xaml, we must be able to navigate to this page. Using the SettingsButton in the application bar on this page, we can navigate to the Settings.xaml using the following code: private void SettingsButton_Click(object sender, EventArgs e) { NavigationService.Navigate( new Uri("/Settings.xaml", UriKind.Relative)); } The Settings.xaml page has just a single button called CreateChannelButton, so for the XAML markup code, take a look at the code samples of the book.In the click event handler of this button, we call the CreateNotificationChannel() method as shown in the following code: private void CreateChannelButton_Click (object sender, RoutedEventArgs e) { CreateNotificationChannel(); } In this CreateNotificationChannel() method, we work with the HttpNotificationChannel, which represents a connection between the Microsoft push service and the WP7 application. It's possible that the channel already exists; the Find() method helps us to look for this channel. If it exists, we need to check if the ChannelUri method isn't null. If it is, we need to unbind the toast subscription from the HttpNotificationChannel using the UnbindToShellToast() method and call the CreateNotificationChannel() method again. If the ChannelUri isn't null, we set the ChannelUri property and call two methods we'll add in the next steps. If the channel doesn't exist yet, we create it and open it. We also call the two above mentioned methods. The code for this rather complex method is as follows: private void CreateNotificationChannel() { HttpNotificationChannel httpChannel = null; string channelName = "BluRayCollectorChannel"; try { httpChannel = HttpNotificationChannel.Find(channelName); if (httpChannel != null) { if (httpChannel.ChannelUri == null) { httpChannel.UnbindToShellToast(); httpChannel.Close(); CreateNotificationChannel(); return; } else { ChannelUri = httpChannel.ChannelUri; RegisterForChannelEvents(httpChannel); RegisterForNotifications(httpChannel); } } else { httpChannel = new HttpNotificationChannel(channelName); RegisterForChannelEvents(httpChannel); httpChannel.Open(); RegisterForNotifications(httpChannel); } } catch (Exception ex) { Debug.WriteLine("Creating the channel failed: " + ex.ToString()); } } The code in the previous step used the RegisterForChannelEvents() method, which is shown next. This method registers two event handlers on the HttpNotificationChannel created earlier. private void RegisterForChannelEvents (HttpNotificationChannel httpChannel) { httpChannel.ChannelUriUpdated += new EventHandler<NotificationChannelUriEventArgs> (httpChannel_ChannelUriUpdated); httpChannel.ErrorOccurred += new EventHandler<NotificationChannelErrorEventArgs> (httpChannel_ErrorOccurred); } The other method we used, RegisterForNotifications() is shown next. It calls the BindToShellToast() method on the channel, effectively creating the toast subscription on the channel. private static void RegisterForNotifications (HttpNotificationChannel httpChannel) { try { httpChannel.BindToShellToast(); } catch (Exception ex) { Debug.WriteLine("Binding to the shell failed: " + ex.ToString()); } } Finally, the last step shows some easy methods and properties referenced earlier. The OnChannelUriChanged() method is invoked when the URI of the channel changes. This happens also when the channel is created and opened and is assigned a URI. At this point, the application is registered to receive notifications. private Uri _channelUri; void httpChannel_ErrorOccurred (object sender, NotificationChannelErrorEventArgs e) { Debug.WriteLine(e.Message); } void httpChannel_ChannelUriUpdated (object sender, NotificationChannelUriEventArgs e) { ChannelUri = e.ChannelUri; } public Uri ChannelUri { get { return _channelUri; } set { _channelUri = value; OnChannelUriChanged(value); } } private void OnChannelUriChanged(Uri value) { Debug.WriteLine(value.ToString()); Dispatcher.BeginInvoke(() => { ResultTextBlock.Text = "Channel created"; }); } We have successfully created both sides of the application, but we aren't done yet—we still need to run the application to test it! Follow these steps to test that the application is working correctly. Make sure you have an Internet connection! It's quite logical that you won't be able to access the cloud service without it.Set the WP7 application as the startup project.Place a breakpoint in the OnChannelUriChanged (Settings.xaml.cs) method on the following line: ResultTextBlock.Text = "Channel created"; Run the application, navigate to the Settings page and press the button. After a few seconds, assuming you have implemented everything correctly, the breakpoint will be hit.In debug mode, take a look at the value of the ChannelUri property. This is of the form: http://db3.notify.live.net/throttledthirdparty/01.00/ AEuIbRo4qZFS6tX6kQMNqrFAgAAAAADAQAAAAQUZm52OjIzOEQ2NDJDRkI5MEVFMEQ Copy this link from Visual Studio.Keep the emulator open and press the Windows button so the WP7 start screen is displayed. If you are hitting the breakpoint, you can remove it.Within the Solution Explorer, right-click on the BluRayCollector.PushNotifications.Web project and select Debug | Start new instance.In the default page, paste the link in the URL field. Enter a value for the Title and Content fields and press the Send Single Push Notification button.After a few seconds, you'll hear a sound from the WP7 emulator as well as see a message, the toast message, being displayed at the top of the screen. How it works... Windows Phone 7 offers a notification system in the form of push notifications that are sent over the air to the device. The current model of the WP7 OS is such that at each point in time, only one application can be running. However, there are real-life scenarios imaginable in which we'd want to receive updates from a certain installed application, but we can't (for practical reasons) keep the application open at all times. Imagine that we want to be notified about a new Blu-ray being released while we are in the middle of playing a game. Because of the one-running-application model, our BluRayCollector application can't be running while we are playing a game and in normal circumstances, wouldn't be able to receive this update. Notifications, more specifically toast notifications, can be a life-saver here. Even while the application isn't running, we may receive updates from a service. That service is linked to an application on the device: when clicking on the message, which is shown at the top of the screen, we are taken to the related application. But wait, how does the device know which is the related application? Let's take a look at the architecture for push notifications, shown in the following figure: The numbers in the image are explained in the following bullets: We install an application that uses notifications. The application registers a so-called channel with a Microsoft cloud-based service, called the Microsoft Push Notifications Service.From that service, we get back a URI for the channel. This URI is a unique identifier for a particular application on a particular device.The WP7 application then sends this URI to a service that we create. In our sample, we have done this manually by copying the URL into the webpage. In a real-life application, the web page would be a service that is ready to accept incoming calls from new WP7 registrations. It is the responsibility of our service to keep a list of registered clients.At some point, our service needs to notify all clients about an event/action that occurs. This event/action may occur in another system, which then triggers the service.To notify all clients, it sends a notification to the Microsoft Push Notifications service in a specific XML format that is predefined by Microsoft, including the URIs to notify.Microsoft's cloud-based service sends the data to the WP7 device. Apart from allowing us to create a better experience in that we have the ability to notify a user about an event even when the application isn't running, push notifications also bring down battery usage and data usage: there's no need to make continuous calls from the device to check for a specific server message. There's more... The message type discussed above is toast notifications. That is actually only one of the three possible types of notifications. The two others are tile notifications and raw messages. Tile notifications refer to updates that are reflected in the tile of the application if it's pinned to the WP7 start screen. If there's no tile for the particular application, the message is suppressed and no further action happens. To be able to receive tile notifications, the application has to register that it wants to do so. Instead of using the BindToShellToast() method, we use the similar BindToShellTile() method on the HttpNotificationChannel, as follows: httpChannel.BindToShellTile(); On the service-side, sending tile notifications is entirely similar to toast notifications, apart from a few things. When creating the message, two headers are different as shown in the following code: switch (messageType) { case MessageType.Tile: notificationRequest.Headers .Add("X-WindowsPhone-Target", "token"); notificationRequest.Headers .Add("X-NotificationClass", "1"); break; case MessageType.Toast: notificationRequest.Headers .Add("X-WindowsPhone-Target", "toast"); notificationRequest.Headers .Add("X-NotificationClass", "2"); break; //case raw not implemented here } Also, the XML is somewhat different. We can notice a wp:Count element here as well as a wp:Title, whereas in the toast message, we had wp:Text1 and wp:Text2. The XML is as shown in the following code: string tileXml = "<?xml version=\"1.0\" encoding=\"utf-8\"?>" + "<wp:Notification xmlns:wp=\"WPNotification\">" + "<wp:Tile>" + "<wp:Count>{0}</wp:Count>" + "<wp:Title>{1}</wp:Title>" + "</wp:Tile>" + "</wp:Notification>"; The value of the wp:Count field will be shown on a specific place in the tile, while the wp:Title replaces the name of the application in the tile. The following screenshot shows how the tile looks after receiving this message: The third type of notification is raw messages. While the two previous types are meant to be received when the application isn't currently running in the foreground, raw messages are the opposite—they can be received by an application only when that application is currently running. This enables a sort-of duplex messaging: there's no call from the client required to receive a message from the notification service. Note Toast notifications can also, just like raw messages, be received while the application is running.

  

You are currently reading a PREVIEW of this book.

                                                                                                                    

Get instant access to over $1 million worth of books and videos.

  

Start a Free Trial


  
  • Safari Books Online
  • Create BookmarkCreate Bookmark
  • Create Note or TagCreate Note or Tag
  • PrintPrint