In the previous post, Understanding How Microsoft Push Notification Works – Part 2, we explained how Microsoft Push Notification (MPN) works and the different players that are required. This post focuses on how to write your WP application so it can use MPN.
The namespace you need to become familiar with is Microsoft.Phone.Notification. This namespace includes the HttpNotificationChannel class, which is the main class you will be using while working with MPN in your WP application. This class includes functions like Open and Close, a few events, and a set of BindToXXXX functions that let you bind your application to the Windows Phone Start page tile and toast notifications.
When you’re ready to implement MPN in your WP application, you will need to follow these steps:
Step #1 – Try to find an existing channel
There is a good chance that if your WP application is using MPN, a persistent channel (as explained in the previous post) already exists for your application. If it does exist, trying to create a new one will fail and throw an exception (NotificationChannelOpenException); therefore, it is better to start by trying to find one before attempting to create a new one.
To determine if a channel already exists, you need to call the Find function. As shown in the following code snippet, this will return an HttpNotificationChannel if a channel with the name you passed as a parameter does exist. If the Find function returns an HttpNotificationChannel you can safely assume that it is already open and functional.
using (StreamReader sr = new StreamReader(isfs))
{
string uri = sr.ReadLine();
Trace("Finding channel");
httpChannel = HttpNotificationChannel.Find(channelName);
if (null != httpChannel)
{
if (httpChannel.ChannelUri.ToString() == uri)
{
Dispatcher.BeginInvoke(() => UpdateStatus("Channel retrieved"));
SubscribeToChannelEvents();
SubscribeToNotifications();
RegisterUriWithService();
bRes = true;
}
sr.Close();
}
}
As you can see, we called the Find function passing the channelName as the channel name for this application. If such a channel exists, we check to see if the channel URI is the one we saved before (in persistent store). You don’t really have to follow that pattern, but it is another failsafe mechanism to ensure the right channel is opened.
Next, we call a set of functions that subscribe the application to the tile and toast notifications on the phone. Lastly, we call the RegisterUriWithService, which we describe at length in step #3 below.
Step #2 – Create a new channel
If you didn’t find an existing channel, it is time to create a new channel. The following code snippet is part of the Connect method implemented in the WP Weather sample application we are using throughout this Windows Push Notification blog posts series. To create a new MPN channel, you need to create a new instance of the HttpNotificationChannel class. The CTOR of this class takes two strings:
- The first string – channelName is the name that your WP application uses to identify the notification channel instance
- The second string – ServiceName is your application cloud service name that is associated with the MPN service
Trace("Creating new channel");
//Create the channel
httpChannel = new HttpNotificationChannel(channelName, "HOLWeatherService");
Trace("Subscribing to channel events");
//Register to UriUpdated event - occurs when channel successfully open
httpChannel.ChannelUriUpdated += new EventHandler<NotificationChannelUriEventArgs>
(httpChannel_ChannelUriUpdated);
SubscribeToChannelEvents();
Trace("Opening channel");
httpChannel.Open();
Here you can see that we are attaching an event handler to the ChannelUriUpdate. This is the event that notifies you when the channel is successfully opened. The Open channel (a few lines of code later) is an asynchronous operation (therefore the need to attach an event handler that gets triggered once the open operation completes). If it is successful, the ChannelUriUpdate event is raised, if it fails, most probably HttpNotificationChannel will raise an ExceptionOccurred event.
Next you call the SubscribeToChannelEvents helper function that assigns an event handler to each notification type (raw, tile and toast) and to the ExceptionOccurred event.
private void SubscribeToChannelEvents()
{
//Subscribe to the channel events
httpChannel.HttpNotificationReceived +=
new EventHandler<HttpNotificationEventArgs>
(httpChannel_HttpNotificationReceived);
httpChannel.ShellEntryPointNotificationReceived +=
new EventHandler<NotificationEventArgs>
(httpChannel_ShellEntryPointNotificationReceived);
httpChannel.ShellNotificationReceived +=
new EventHandler<NotificationEventArgs>
(httpChannel_ShellNotificationReceived);
httpChannel.ExceptionOccurred +=
new EventHandler<NotificationChannelExceptionEventArgs>
(httpChannel_ExceptionOccurred);
}
The last thing you need to do in this step is to open the channel by calling the Open function. If something is very wrong, you will get an exception right away. If you do get this exception, make sure you have the latest Windows Phone Tools (April CTP). You also might get an exception through the ExceptionOccurred event, which implies that the device tried to open the channel, but something (also very bad) happened. For example the backend services might be down (most unlikely, but still a possibility). If such an error were to happens in real life, your application should take care of it by retrying later, notifying the user, or taking some other course of action.
At this point, your ChannelUriUpdated event handler should be called because the MPN Service backend returned a URI as a response to your request (you just opened the channel). The NotificationChannelUriEventArgs includes a single public property – the ChannelUri. As we explained in previous posts, this is the address to which your backend service needs to POST HTTP messages that it wishes to send to a WP device as MPN messages.
Step #3 – Send the channel URI to your cloud service
Whether or not you found an existing URI, or your ChannelUriUpdated event handler was called due to opening an HttpNotificationChannel, it is still highly recommended that you send to your backend cloud service the push notification channel URI that you received. This is a good practice even if it is not the first time you’ve passed it or that it is likely that you’ve passed it before.
To do so, you should call the RegisterUriWithService helper function. This function posts the URI that you received as a result of opening HttpNotificationChannel. This URI represents an HTTP address on Microsoft Push Notification backend servers to which your backend server needs to POST a message to send MPN messages to a WP device.
The RegisterUriWithService function sends this URI to a hardcoded HTTP address that mimics your backend service. The Weather Client application is a WPF application that hosts a WCF REST service used to receive URI registrations and to instruct MPN Service to POST HTTP messages as push notification messages to be sent to WP devices. You need to run this application in Admin mode because the Weather Client needs to run a WCF service.
private void RegisterUriWithService()
{
//Hardcode for solution - need to be updated in case the REST WCF service
//address change
string baseUri = "http://localhost:8000/RegirstatorService/Register?uri={0}";
string theUri = String.Format(baseUri, httpChannel.ChannelUri.ToString());
WebClient client = new WebClient();
client.DownloadStringCompleted += (s, e) =>
{
if (null == e.Error)
Dispatcher.BeginInvoke(() => UpdateStatus("Registration succeeded"));
else
Dispatcher.BeginInvoke(() =>
UpdateStatus("Registration failed: " + e.Error.Message));
};
client.DownloadStringAsync(new Uri(theUri));
}
As you can see we have a hardcoded base URI that points to the local host on port 8000. In the code you can find the WPF application App.config file that contains the service and its behavior definitions. We are not going to dive into the WCF portion of the service, just enough to note that this is a RESTful WCF service,
Step #4 – Register to receive tile and toast MPN messages
So far you have learned how to find existing MPN channels, open a new one, and then register that channel’s associated URI with your backend server. But the whole idea behind MPN is that it lets you receive push notification messages while your application is running and, far more importantly, while your application is not running. To be able to do this, you need to register your WP application to these messages. This registration creates a bind between WP shell and your application, binding your application tile to receive WP notification messages as well as toast messages.
private void SubscribeToNotifications()
{
try
{
Trace("Registering to Toast Notifications");
httpChannel.BindToShellNotification();
}
catch (NotificationChannelExistsException)
{
//Nothing to do - channel already exists and subscribed
}
try
{
Trace("Registering to Tile Notifications");
ShellEntryPoint shellEntryPoint = new ShellEntryPoint();
shellEntryPoint.RemoteImageUri =
new Uri("YourImageURIGoesHere.png", UriKind.Absolute);
httpChannel.BindToShellEntryPoint(shellEntryPoint);
}
catch (NotificationChannelExistsException)
{
//Nothing to do - channel already exists and subscribed
}
}
You can also receive raw notification messages, which are explained in step #5. While raw notification messages are designed to support messaging scenarios when your application is running, tile and toast notifications are more for times when your application is not running. With that said, you can still register your event handlers to receive these notifications when they arrive, as shown in the following code snippet. SubscribeToChannelEvents is a helper function that we call from multiple locations in the application to register to all the notification channel in-application events. In our implementation these event handlers simply update a label in the WP UI. When your WP application is not running and the WP device receives a push notification message, and your application tile is pinned to the Start page, the tile will be updated as shown in the following image. On the left, the default WP application icon is shown as I pinned the Push Notification Weather Client to the Start page, and on the right, you can see the live tile after I sent a tile PN message with weather information about the city of London.
Since tile and toast messages don’t include a lot of information in their payload (their main purpose is to ask your backend service for any updates), once you receive such a message while your application is running, you should contact your backend service to get the update on which it sent the tile notification. Your backend service should be smart enough to understand that the push notification message received was asking for an update.
Steps #5 – Handle incoming push notification messages
httpChannel_ShellNotificationReceived and httpChannel_ShellEntryPointNotificationReceived handle toast and tile notifications respectively. In this last step, we will look at how our application receives raw notifications. In the sample application below, we just present a little data we received from the different push notifications. You should find it easy to follow the code in the sample.For example, the following code snippet, updates the status label in the WP UI with the PN tile message.
void httpChannel_ShellEntryPointNotificationReceived
(object sender, NotificationEventArgs e)
{
Trace("===============================================");
Trace("Tile notification arrived:");
foreach (var key in e.Collection.Keys)
{
string msg = e.Collection[key];
Trace(msg);
Dispatcher.BeginInvoke(() => UpdateStatus("Tile message: " + msg));
}
Trace("===============================================");
}
Handling a raw notification, designated as an HTTP notification in the sample, involves understanding the payload that was sent. httpChannel_HttpNotificationReceived does just that by calling the ParseRAWPayload and then updating the application’s weather status and icon. ParseRAWPayload is a helper function that breaks down the different XML elements from the PN payload to values that the application can use as shown in the following code snippet. Raw notification is basically any type of payload that your backend service wish to send. It can be an XML format or a binary blob. As long as your PN message do not exceeds 1024 bytes, you should be just fine.
private void ParseRAWPayload(Stream e, out string weather,
out string location, out string temperature)
{
XDocument document;
using (var reader = new StreamReader(e))
{
string payload = reader.ReadToEnd().Replace('