WP7 notifications
Windows Phone 7 provides a push notification mechanism to allow you to communicate with your application or the user even when your application is not running. The documentation describes the different headers and values you need to use in order to make your notification appear on the phone but I like to have a more seamless developer experience so I wrapped the MSDN code in a helper class so that I don’t need to worry about those details. The only thing I need to know is which phone am I sending to (the notification Uri) and what type of notification do I need. So I want to facilitate code that looks like this
WPNotificationSender wpns = new WPNotificationSender(PhoneNotificationUri);
// send a Toast notification
string messageID = Guid.NewGuid().ToString();
wpns.SendToastNotification(messageID, "Hello", "World!");
// send a Tile update notification
messageID = Guid.NewGuid().ToString();
int count = 5; // set the tile count to 5
string title = "Cloudy"; // set the tile title to "Cloudy"
wpns.SendTileNotification(messageID, "https://example.com/newTile.png", count, title);
// send a raw byte payload to the app
messageID = Guid.NewGuid().ToString();
byte[] payload = new byte[] { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08 };
wpns.SendRawNotification(messageID, payload);
Of course I don’t necessarily want to require all of the objects each time so each parameter should happily accept a null value (including the tile count). In that case sending a notification becomes brain dead simple. Just send the data I want to show up.
WPNotificationSender wpns = new WPNotificationSender(PhoneNotificationUri);
// send a Toast notification
wpns.SendToastNotification(null, "Hello", "World!");
// send a Tile update notification
wpns.SendTileNotification(null, null, 5, null);
Then to check the response to make sure your notification went through I want to examine the three status variables after each SendXXX call.
notificationStatus.Text = wpns.NotificationStatus;
notificationChannelStatus.Text = wpns.NotificationChannelStatus;
deviceConnectionStatus.TemplateControl = wpns.DeviceConnectionStatus;
This works beautifully if you just wrapped the MSDN push notification like so
public class WPNotificationSender
{
public string NotificationUri { get; set; }
private string notificationStatus;
public string NotificationStatus
{
get { return notificationStatus; }
}
private string notificationChannelStatus;
public string NotificationChannelStatus
{
get { return notificationChannelStatus; }
}
private string deviceConnectionStatus;
public string DeviceConnectionStatus
{
get { return deviceConnectionStatus; }
}
public WPNotificationSender(string notificationUri)
{
this.NotificationUri = notificationUri;
}
public void SendTileNotification(string msgID, string backgroundImage, int? count, string title)
{
string tileMessageFormat = "<?xml version=\"1.0\" encoding=\"utf-8\"?>" +
"<wp:Notification xmlns:wp=\"WPNotification\">" +
"<wp:Tile>" +
"<wp:BackgroundImage>{0}</wp:BackgroundImage>" +
"<wp:Count>{1}</wp:Count>" +
"<wp:Title>{2}</wp:Title>" +
"</wp:Tile> " +
"</wp:Notification>";
string tileMessage = string.Format(tileMessageFormat, backgroundImage, count, title);
byte[] payload = Encoding.UTF8.GetBytes(tileMessage);
SendNotification(NotificationType.Tile, msgID, payload);
}
public void SendToastNotification(string msgID, string msg1, string msg2)
{
var strFormat = "<?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>";
var str = string.Format(strFormat, msg1, msg2);
byte[] payload = Encoding.UTF8.GetBytes(str);
SendNotification(NotificationType.Toast, msgID, payload);
}
public void SendRawNotification(string msgID, byte[] payload)
{
SendNotification(NotificationType.Raw, msgID, payload);
}
public void SendNotification(NotificationType type, string msgID, byte[] payload)
{
// The URI that the Push Notification Service returns to the Push Client when creating a notification channel.
string subscriptionUri = NotificationUri;
HttpWebRequest sendNotificationRequest = (HttpWebRequest)WebRequest.Create(subscriptionUri);
// HTTP POST is the only allowed method to send the notification.
sendNotificationRequest.Method = "POST";
// The optional custom header X-MessageID uniquely identifies a notification message. If it is present, the
// same value is returned in the notification response. It must be a string that contains a UUID.
if (!string.IsNullOrEmpty(msgID))
{
sendNotificationRequest.Headers.Add("X-MessageID", msgID);
}
switch (type)
{
case NotificationType.Raw:
sendNotificationRequest.Headers.Add("X-NotificationClass", "3");
break;
case NotificationType.Toast:
sendNotificationRequest.ContentType = "text/xml";
sendNotificationRequest.Headers.Add("X-WindowsPhone-Target", "toast");
sendNotificationRequest.Headers.Add("X-NotificationClass", "2");
break;
case NotificationType.Tile:
sendNotificationRequest.ContentType = "text/xml";
sendNotificationRequest.Headers.Add("X-WindowsPhone-Target", "token");
sendNotificationRequest.Headers.Add("X-NotificationClass", "1");
break;
}
// Sets the web request content length.
sendNotificationRequest.ContentLength = payload.Length;
using (Stream requestStream = sendNotificationRequest.GetRequestStream())
{
requestStream.Write(payload, 0, payload.Length);
}
HttpWebResponse response = null;
try
{
// Sends the notification and gets the response.
response = (HttpWebResponse)sendNotificationRequest.GetResponse();
notificationStatus = response.Headers["X-NotificationStatus"];
notificationChannelStatus = response.Headers["X-SubscriptionStatus"];
deviceConnectionStatus = response.Headers["X-DeviceConnectionStatus"];
}
catch (Exception ex)
{
notificationStatus = ex.Message;
notificationChannelStatus = string.Empty;
deviceConnectionStatus = string.Empty;
}
}
}
public enum NotificationType
{
Raw,
Toast,
Tile
}