Windows Phone 7 - London Tube Companion Application
As part of my continual learning of Windows Phone 7, I decided to develop an application which displays the status of tube lines for the London Underground. As well as displaying the line status, the application also allows users to request push notifications when the status of a tube line changes.
Windows Phone 7 architecture allows for several types of push notifications, all of which are delivered by the cloud based Push Notification service. The notification types are as follows:
- Raw Notification : Raw Data is sent to the application. Only available when the application is open.
- Tile Notification: If the application is pinned to the phone’s start screen, then the application’s tile can be modified.
- Toast Application: Text based notification is displayed to the currently active screen. This does not require the application to be open.
The article here details the push notification architecture. In my example the Windows Phone application is the Tube Companion windows phone application, and the cloud application is a service which periodically polls for changes in tube status, and then sends out notifications to the relevant subscribers.
Setting up the phone application to receive toast notifications
In order for the phone to receive toast notifications, the phone application must carry out the following:
- Create a channel to the Push Notification service. Although the phone application itself does not create the notifications, it is the phone’s responsibility to create the notification channel between itself and the push notification service. Once the channel has been created and opened, a unique Uri for the application and device instance is created, and this can passed to any external cloud based service. It is then the responsibility of the cloud based service to post messages to the Uri, which results in the notification being sent to the device.
- Register to receive the relevant channel events. The ChannelUriUpdated event is fired when the channel has been opened. Once this occurs the application and device specific Uri is available. The ShellNotificationReceived event is fired once a toast notification is received and the application is running. This would allow you to apply additional application logic when the application has context. If the application is not running then this event would not fire and a standard toast notification would be received in the normal manner.
- Open the channel.
- Bind to the relevant notification type. In order to receive toast notifications from the Push Notification service we have to explicitly request to receive toast notifications, otherwise only raw notification types would be sent to the application.
- Subscribe to notifications. The Channel Uri is sent from the phone application to my cloud service, and stored in it’s notification subscription database. The cloud service then uses this Uri in order to send notifications back to the device.
_httpChannel = new HttpNotificationChannel(CHANNEL_NAME, "TubeCompanionService");
_httpChannel.ChannelUriUpdated += new EventHandler
void _httpChannel_ChannelUriUpdated(object sender, NotificationChannelUriEventArgs e)
System.Diagnostics.Debug.WriteLine("Received application uri: " + e.ChannelUri.ToString());
_httpChannel.HttpNotificationReceived += new EventHandler
_httpChannel.ShellEntryPointNotificationReceived += new EventHandler
_httpChannel.ShellNotificationReceived += new EventHandler
_httpChannel.ExceptionOccurred += new EventHandler
Setting up the service to send toast notifications
In order for the service to send toast notifications, the following needs to occur:
- The toast notification XML message is created. The XML message must conform to the schema documented here, and essentially details the notification message to be displayed.
- A HttpWebRequest object is created, and is passed the phone/device instance Uri as it’s constructor.
- The toast notification XML is converted to a byte array and passed as the content of the HttpWebRequest .
- Request headers are set. Documented here
- The HttpWebRequest is posted. This results in the notification being sent to the application on the device.
const string MESSAGE_ID = "X-MessageID";
const string NOTIFICATION_CLASS = "X-NotificationClass";
const string NOTIFICATION_STATUS = "X-NotificationStatus";
const string SUBSCRIPTION_STATUS = "X-SubscriptionStatus";
const string DEVICE_CONNECTION_STATUS = "X-DeviceConnectionStatus";
const string WINDOWSPHONE_TARGET_HEADER = "X-WindowsPhone-Target";
public void SendToastNotification(Uri channelUri, string message)
ToastNotificationMessage toastMessage = new ToastNotificationMessage();
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(channelUri);
request.Method = "POST";
request.ContentType = "text/xml";
request.Headers = new WebHeaderCollection();
//request.Headers[WINDOWSPHONE_TARGET_HEADER] = "toast";
byte toastMessageBytes = toastMessage.CreateToastMessage(message);
request.ContentLength = toastMessageBytes.Length;
using (Stream requestStream = request.GetRequestStream())
requestStream.Write(toastMessageBytes, 0, toastMessageBytes.Length);
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
string notificationStatus = response.Headers[NOTIFICATION_STATUS];
string subscriptionStatus = response.Headers[SUBSCRIPTION_STATUS];
string deviceConnectionStatus = response.Headers[DEVICE_CONNECTION_STATUS];
public class ToastNotificationMessage
public byte CreateToastMessage(string message)
string prefix = "Content-Type: text/xml\r\nX-WindowsPhone-Target: toast\r\n\r\n";
StringBuilder builder = new StringBuilder();
ASCIIEncoding encoding = new ASCIIEncoding();
string messageXML = builder.ToString();
messageXML = prefix + messageXML;
Windows Phone 7 CTP April Refresh
This application was built with the Windows Phone 7 CTP April refresh, and it is worth stating that there is currently an issue with this version of the emulator whereby the notification channel cannot be opened until the emulator has been running for around two minutes. Therefore a delay has to be introduced prior to creating and opening this channel.
Additionally changes to the WMAppManifest.xml also have to be made and these are documented here