Silverlight for Windows Phone 7: Push Notifications (Part 1 of 2)

July 12, 2010

Now, after Beta tools released it is a time to start talking about new features and changes since Apirl CTP.


This is the first part of two parts blog post about push notification mechanism in Windows Phone 7. The API described in this article according to recently released Beta version of Windows Phone Development Tools (WPDT).


Windows Phone 7 application can’t run in the background (performance, battery life, usage of radio) and therefore there is a need to have a mechanism that facilitates a communication channel between backend services and application on the phone. Push Notification is the mechanism through which backend services can send “messages” to the phone to notify the user for any state changes. The Push Notification service is designed to provide a cloud service with a dedicated, resilient, and persistent channel for pushing a notification to a mobile device.


image


When a cloud service needs to send a push notification to a device, it sends a notification request to the Push Notification service, which in turn routes the notification to the application, or to the device as a toast or tile notification, depending on the type of notification that is sent.


The Push Client on the device receives push notifications through a notification channel. When the channel is created, a subscription is also created which allows the cloud service to push notifications to that channel. A channel is represented by a URI which contains all of the information associated with the subscription.


Once an application receives the push notification, it can access the cloud service using the cloud service’s protocol to retrieve any needed information.


Since, applications today tends to share multiple screens running on local computer, in the cloud and on the phone. The push notification services, enables seamless integration between all three with a simple and unified API.


This post will talk about creating the Cloud Service (in my case IIS hosted WCF service) which will talk to Microsoft Push Notification Service (MPNS). In addition I’ll use Silverlight application to send a messages through this WCF service to registered phone clients.


I’ll start from creating the WCF service (Actually two of them, but second is not related to Push Notification directly).


Notification messages sent through MPNS could be from 3 types:


RAW HTTP notification – notification passed to the phone application in user defined format. The data constructed by cloud service, and need to be parsed in phone application according to application logic


TOAST notification – special kind of push notification which displays as an overlay onto the user’s current screen. For example, a weather application may wish to display a toast notification if a severe weather alert is in effect. If the user decides to click the toast notification, the application can launch and perform other actions. A cloud service can control a toast notification’s title and sub-title. The toast notification will also display the application’s icon that is included in the application’s deployment package. Notification format:
Content-Type: text/xml
X-WindowsPhone-Target: toast
   
<?xmlversion=”1.0″encoding=”utf-8″?>
<
wp:Notification xmlns:wp=”WPNotification”>
   <
wp:Toast>
      <
wp:Text1><string></wp:Text1>
      <
wp:Text2><string></wp:Text2>
   </
wp:Toast>
</
wp:Notification>



Tile notification – is a visual, dynamic representation of an application or its content within the Quick Launch area of the phone’s Start experience. For example, a weather application may choose to display the user’s local time and climate conditions in a tile. Because a cloud service can alter its tile’s appearance at any time, this mechanism can be used to communicate information to the user on an ongoing basis. A cloud service can control a tile’s background image, counter (or ‘badge’), and title properties. Notification format:
Content-Type: text/xml
X-WindowsPhone-Target: token
   
<?xmlversion=”1.0″encoding=”utf-8″?>
<
wp:Notification xmlns:wp=”WPNotification”>
   <
wp:Tile>
      <
wp:BackgroundImage><backgroundimage path></wp:BackgroundImage>
      <
wp:Count><count></wp:Count>
      <
wp:Title><title></wp:Title>
   </
wp:Tile>
</
wp:Notification>


My WCF service will expose 3 functions (each one for corresponding notification type) and will use Silverlight 4 polling duplex mechanism (http://msdn.microsoft.com/en-us/library/cc645027(VS.95).aspx) to callback client once message being dispatched through MPNS.


Service interface:

[ServiceContract(Namespace = “http://www.alexgolesh.com/services/NotificationService”, CallbackContract = 
typeof(INotificationClient))]
public interface INotificationService
{
[OperationContract]
void SendRAWNotification(List<Uri> Uris, byte[] payload);

[OperationContract]
void SendToastNotification(List<Uri> Uris, string message1, string message2);

[OperationContract]
void SendTileNotification(List<Uri> Uris, string TokenID, string BackgroundImageUri, int Count, string Title);

}



Callback interface:

[ServiceContract]
public interface INotificationClient
{
[OperationContract(IsOneWay = true)]
void NotifyOnMessageSend(WindowsPhone.PushNotificationManager.CallbackArgs args);
}

The service implementation is very easy – I’ll use external reusable library to communicate with MPNS:

public class NotificationService : INotificationService
{
INotificationClient client;

#region INotificationService Members

public void SendRAWNotification(List<Uri> Uris, byte[] payload)
{
client = OperationContext.Current.GetCallbackChannel<INotificationClient>();

NotificationSenderUtility.SendRawNotification(Uris, payload, SendNotificationToMPNSCompleted);
}

public void SendToastNotification(List<Uri> Uris, string message1, string message2)
{
client = OperationContext.Current.GetCallbackChannel<INotificationClient>();

NotificationSenderUtility.SendToastNotification(Uris, message1, message2, SendNotificationToMPNSCompleted);
}

public void SendTileNotification(List<Uri> Uris, string TokenID, string BackgroundImageUri, int Count, string Title)
{
client = OperationContext.Current.GetCallbackChannel<INotificationClient>();

NotificationSenderUtility.SendTileNotification(Uris, TokenID, BackgroundImageUri, Count, Title,
SendNotificationToMPNSCompleted);
}

private void SendNotificationToMPNSCompleted(CallbackArgs response)
{
client.NotifyOnMessageSend(response);
}

#endregion
}



Not the interesting part – the NotificationSenderUtility. This utility handles all the communications to MPNS. All the “main” functions will work according to simple algorithm: prepare payload (the message in format according to notification type – will use “helper” functions), and send the message to each URI in the list received from Cloud Service Client. The payload should be the XML messages (as defined above), in byte array format. To communicate with MPNS I’ll use HttpWebRequest class. Method used in communication – POST. In addition I have to set some request headers in order to make MPNS handle my request correctly.


Let’s see for example one of “PrepareXXXPayload” helper functions:

private static byte[] prepareToastPayload(string text1, string text2)
{
MemoryStream stream = new MemoryStream();

byte[] prefix = Encoding.UTF8.GetBytes(“Content-Type: text/xml\r\nX-WindowsPhone-Target: toast\r\n\r\n”);
stream.Write(prefix, 0, prefix.Length);

XmlWriterSettings settings = new XmlWriterSettings() { Indent = true, Encoding = Encoding.UTF8 };
XmlWriter writer = XmlWriter.Create(stream, settings);
writer.WriteStartDocument();
writer.WriteStartElement(“wp”, “Notification”, “WPNotification”);
writer.WriteStartElement(“wp”, “Toast”, “WPNotification”);
writer.WriteStartElement(“wp”, “Text1”, “WPNotification”);
writer.WriteValue(text1);
writer.WriteEndElement();
writer.WriteStartElement(“wp”, “Text2”, “WPNotification”);
writer.WriteValue(text2);
writer.WriteEndElement();
writer.WriteEndElement();
writer.WriteEndDocument();
writer.Close();

byte[] payload = stream.ToArray();
return payload;
}


In this function I’m using XmlWriter to create XML according to format described above and write it to MemoryStream. Once I finished I’m returning the byte array from the memory stream. This is exactly the payload I need to send to MPNS.


Function which uses this prepareToastPayload method is public function being executed from my WCF:

public static void SendToastNotification(List<Uri> Uris, string message1, string message2, 
SendNotificationToMPNSCompleted callback)
{
byte[] payload = prepareToastPayload(message1, message2);

foreach (var uri in Uris)
SendNotificationByType(uri, payload, NotificationType.Toast, callback);
}  


Now the main “communication part” of the utility – the SendMessgae function. This function is used by SendNotificationByType and prepares an HttpWebRequest, sets the headers according to the message types and handles the Request/Response events to the MPNS:

private static void SendMessage(Uri channelUri, byte[] payload, NotificationType notificationType, 
SendNotificationToMPNSCompleted callback)
{
//Check the length of the payload and reject it if too long
if (payload.Length > MAX_PAYLOAD_LENGTH)
throw new ArgumentOutOfRangeException(“Payload is too long. Maximum payload size shouldn’t exceed ”
+ MAX_PAYLOAD_LENGTH.ToString() + ” bytes”);

try
{
//Create and initialize the request object
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(channelUri);
request.Method = WebRequestMethods.Http.Post;
request.ContentType = “text/xml; charset=utf-8”;
request.ContentLength = payload.Length;
request.Headers[MESSAGE_ID_HEADER] = Guid.NewGuid().ToString();
request.Headers[NOTIFICATION_CLASS_HEADER] = ((int)notificationType).ToString();

if (notificationType == NotificationType.Toast)
request.Headers[WINDOWSPHONE_TARGET_HEADER] = “toast”;
else if (notificationType == NotificationType.Token)
request.Headers[WINDOWSPHONE_TARGET_HEADER] = “token”;

request.BeginGetRequestStream((ar) =>
{
//Once async call returns get the Stream object
Stream requestStream = request.EndGetRequestStream(ar);

//and start to write the payload to the stream asynchronously
requestStream.BeginWrite(payload, 0, payload.Length, (iar) =>
{
//When the writing is done, close the stream
requestStream.EndWrite(iar);
requestStream.Close();

//and switch to receiving the response from MPNS
request.BeginGetResponse((iarr) =>
{
using (WebResponse response = request.EndGetResponse(iarr))
{
//Notify the caller with the MPNS results
OnNotified(notificationType, (HttpWebResponse)response, callback);
}
},
null);
},
null);
},
null);
}
catch (WebException ex)
{
if (ex.Status == WebExceptionStatus.ProtocolError)
{
//Notify client on exception
OnNotified(notificationType, (HttpWebResponse)ex.Response, callback);
}
throw;
}

}


Constants used in this function defined as follows:

public const string MESSAGE_ID_HEADER = “X-MessageID”;
public const string NOTIFICATION_CLASS_HEADER = “X-NotificationClass”;
public const string NOTIFICATION_STATUS_HEADER = “X-NotificationStatus”;
public const string DEVICE_CONNECTION_STATUS_HEADER = “X-DeviceConnectionStatus”;
public const string SUBSCRIPTION_STATUS_HEADER = “X-SubscriptionStatus”;
public const string WINDOWSPHONE_TARGET_HEADER = “X-WindowsPhone-Target”;
public const int MAX_PAYLOAD_LENGTH = 1024;

The very same way done the rest of this communication service…


The second service I have is a “RegistrationService”, which registers the Windows Phone 7 client applications, and provides the registrants data to Cloud Service Client application. The service is super simple – here the interface it implements:

[ServiceContract(Namespace = “http://www.alexgolesh.com/services/RegistrationService”)]
public interface IRegistrationService
{
[OperationContract, WebGet]
void Register(string uri);

[OperationContract, WebGet]
void Unregister(string uri);

[OperationContract, WebGet]
List<Uri> GetRegisteredSubscribers();
}


Now the client – simple Silverlight 4 application, which uses provides an “operator” the UI to send weather information to registered clients. It uses Registration services to get the list of connected clients, and Notification service to sent message with data according to type user selects to send. The UI is pretty simple:


image


The client application (and services) are available online here.


Sources here.


Stay tuned for the next part – I’ll show the phone part of the picture.


Alex

Add comment
facebook linkedin twitter email

Leave a Reply

Your email address will not be published.

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

*

22 comments

  1. Janiv RatsonJuly 13, 2010 ב 22:10

    Great article Alex,

    How do I send push notification to a specific wp7 phone (using device token or similar)?

    Thanks,
    Janiv Ratson.

    Reply
  2. forex robotJuly 14, 2010 ב 0:14

    What a great resource!

    Reply
  3. Alex GoleshJuly 14, 2010 ב 5:57

    Janiv: To send push notification to specific device you have to know device’s specific push channel address. See second part of this article – when device opens a push channel it received some unique URI. To send notification to the deviec you should send you notification to this specific URI.

    Regards,
    Alex

    Reply
  4. SayathSeptember 16, 2010 ב 15:28

    Thanks for article. Everytime like to read you.

    Reply
  5. Kissing guideDecember 22, 2010 ב 23:30

    I am Glad i came across this web site.Added blogs.microsoft.co.il to my bookmark!

    Reply
  6. used cars parkersburg, wv April 3, 2011 ב 19:07

    I find myself coming to your blog more and more often to the point where my visits are almost daily now!

    Reply
  7. sdfsdgfdApril 22, 2011 ב 14:40

    Thanks For This Blog, was added to my bookmarks.

    Reply
  8. low cost auto insurance in texasMay 22, 2011 ב 10:19

    I would like to thank you for the efforts you have put in writing this site. I’m hoping the same high-grade site post from you in the upcoming as well. In fact your creative writing abilities has encouraged me to get my own blog now. Actually the blogging is spreading its wings rapidly. Your write up is a good example of it. affordable car insurance for young adults

    Reply
  9. tiffany and co outletJune 17, 2011 ב 9:57

    Thanks for you sharing.That is good article.I like it.

    Reply
  10. tiffany and co outletJune 17, 2011 ב 9:58

    Thanks for you sharing.That is good article.I like it.

    Reply
  11. tiffany and co outletJune 17, 2011 ב 9:59

    Thanks for you sharing.That is good article.I like it.That is good article.I like it.That is good article.I like it.

    Reply
  12. True religion jeans outletJune 17, 2011 ב 9:59

    I read with great interest.Thanks for you sharing.

    Reply
  13. tiffany and co outletJune 17, 2011 ב 10:01

    Thanks for you sharing.That is good article.I like it.

    Reply
  14. True religion jeans outletJune 17, 2011 ב 10:01

    I read with great interest.Thanks for you sharing.

    Reply
  15. tiffany's outletJune 17, 2011 ב 10:01

    Your article looks great!Thanks for you sharing. I love it.

    Reply
  16. MBTJune 17, 2011 ב 10:57

    Woo,It is my pleasure to share this ,good luck for you!

    Reply
  17. suzanelykFebruary 6, 2012 ב 6:09

    All not so is simple, as it seems

    Reply
  18. WillAugust 14, 2012 ב 10:54

    Thank you, I’ve recently been searching for information about this topic for ages and yours is the greatest I have found out till now. However, what in regards to the conclusion? Are you sure in regards to the source?

    Reply
  19. SalcedoJanuary 25, 2013 ב 6:58

    Can I simply just say what a comfort to discover a person that really knows what they’re talking about online. You definitely understand how to bring an issue to light and make it important. More people need to read this and understand this side of the story. It’s
    surprising you are not more popular because you surely have the
    gift.
    choose dining tables

    Reply
  20. BaruchOIJanuary 31, 2013 ב 4:39

    just stopping by to say hello

    Reply