This blog post will explain how you can (using only the raw .NET Framework) implement push notifications for a Windows 8 Metro Application. Windows Push Notifications (WNS) in Windows 8 is actually quite similar to the model we are used to when working with a Windows Phone 7, so anyone of you that worked with those before will most likely recognize the tutorial coming up in this post.
But before I go any further I would like to thank whoever wrote the official Push Notification Sample, it helped me a lot. Also a big thanks to Nick Harris for his post dealing with push notifications and his and Darren Louie’s video from BUILD.
In order to get this to work we first need to register our application to receive push notifications. Once that is done we’ll continue with client and then server implementation. In my case I used an Azure server, but you could just as well host this anywhere else. The figure below illustrates the flow when sending a push notification. In this post I’ll show code written for the Win 8 Client and Azure Server.
Let’s get started.
Register your application to receive push notifications
The first thing that we need to do, before writing any code, is to register our application to actually be discoverable by WNS. For the moment, the address is https://manage.dev.live.com/build but I’m guessing that it will change later on.
At the site they have very clear instructions on how to proceed, but I’ll write down the steps in either case. First step is to enter your “Package display name” and “Publisher” to the website. Both can be found by opening your “Package.appxmanifest” file in your Metro client project.
And then enter those values in the form found on the website.
After pressing “I accept” you get this information.
Here you’ll copy the “Package name” and paste it into your “Package.appxmanifest” as seen below. The other two values, “Client secret” and “Package Security Identifier (SID)”, is necessary later on when our server fetches our access token from Live Services.
Notice that the “Package Family Name” at the bottom also changes. That’s it really, we can now continue with the client implementation.
Client implementation
First of all you need to open up a channel in order to receive push notifications. It can be done as in the code sample below.
PushNotificationChannel pushNotificationChannel; void OpenChannel() { var operation = PushNotificationChannelManager.CreatePushNotificationChannelForApplicationAsync(); operation.Completed = OnChannelCreationCompleted; operation.Start(); } void OnChannelCreationCompleted(IAsyncOperation<PushNotificationChannel> operation) { if (operation.Status == AsyncStatus.Completed) { pushNotificationChannel = operation.GetResults(); // Send these values together with user data to your server of choice var notificationUri = pushNotificationChannel.Uri; var expirationTime = pushNotificationChannel.ExpirationTime; } }
If the user accepts push notifications you would typically call OpenChannel() when the application starts. When opened it will call OnChannelCreationCompleted(…). Here you can extract two important properties of the PushNotificationChannel – Uri and ExpirationTime. Both of these should typically be posted to your server solution of choice. In our case, the Uri will be something like this (shortened).
https://db3.notify.windows.com/?token=AQQAAACL3PSmbrWaRkusVuK…
I didn’t write any code for actually sending the data to the server. I’ll leave it up to you if would like to do a simple POST, service reference or whatever. When I tried it, I just did a POST using a HttpWebRequest to a WCF Web API service that I hosted in Azure. In a normal scenario you would typically also post an user id so that you can identify which user the notification Uri belongs to.
Now, in order to actually se what was happening I needed to subscribe to PushNotificationReceived.
pushNotificationChannel.PushNotificationReceived += OnPushNotificationReceived;
OnPushNotificationReceived don’t actually do anything else than blocking the event from actually reaching the UI. When I tested it I just added a breakpoint to this method so that I could take a peak on whatever came in.
void OnPushNotificationReceived(PushNotificationChannel sender, PushNotificationReceivedEventArgs e) { string notificationContent = String.Empty; switch (e.NotificationType) { case PushNotificationType.Badge: notificationContent = e.BadgeNotification.Content.GetXml(); break; case PushNotificationType.Tile: notificationContent = e.TileNotification.Content.GetXml(); break; case PushNotificationType.Toast: notificationContent = e.ToastNotification.Content.GetXml(); break; } // prevent the notification from being delivered to the UI e.Cancel = true; }
Note that this will only be triggered if the application is in the foreground, if it’s in the background this method will not be executed.
That’s it for the client implementation; now let’s see what we need to do on the server side.
Server implementation
I’ll keep this code raw without wrapping up the logic in any classes. The whole idea with this exercise was for me to understand what was happening and in order to do that I needed to get as close the the raw web requests as possible. I should also mention that I wrote this code on a machine running Windows 7 OS and VS2010.
Fetching an access token
First of all I needed to get a hold of my access token, we’ll need it when we push data to the client. From what I understand you should actually cache this value until it expires, but I haven’t been able to figure out where you can see the expiration date… anyway, in order to get your access token you need to do a POST.
POST https://login.live.com/accesstoken.srf HTTP/1.1 Content-Type: application/x-www-form-urlencoded Host: login.live.com Content-Length: 212 grant_type=client_credentials&client_id=ms-app%3a%2f%2fs-1-15-2-2540850135-1066809635-1827421751-2963426696-2171157241-2579410831-1077576199&client_secret=Si7vgThlGhKrtILSs7BWXPTdE-9yaGGI&scope=notify.windows.com
As you probably noticed, the client_id is actually a html encoded version of the “Package Security Identifier (SID)” that we retrieved when registering our application (see images above). The same goes for the client_secret that is the… well “Client secret”. So, how are we going to express all of this in code?
private string GetAccessToken() {
string url = "https://login.live.com/accesstoken.srf"; var request = (HttpWebRequest)WebRequest.Create(url); request.Method = "POST"; request.ContentType = "application/x-www-form-urlencoded"; string sid = HttpUtility.UrlEncode("ms-app://s-1-15-2-2540850135-1066809635-…"); string secret = HttpUtility.UrlEncode("Si7vgThlGhKrtILSs7BWXPTdE-9yaGGI"); string content = "grant_type=client_credentials&client_id={0}&client_secret={1}&scope=notify.windows.com"; string data = string.Format(content, sid, secret); byte[] notificationMessage = Encoding.Default.GetBytes(data); request.ContentLength = notificationMessage.Length; using (Stream requestStream = request.GetRequestStream()) { requestStream.Write(notificationMessage, 0, notificationMessage.Length); } var response = (HttpWebResponse)request.GetResponse(); string result; using(Stream responseStream = response.GetResponseStream()) { var streamReader = new StreamReader(responseStream); result = streamReader.ReadToEnd(); } return result; }
Not pretty – I’m well aware of it. But you should get an idea of how the request is built up to match the POST described above. Important to note is that we need to UrlEncode both our SID and client secret. The result we receive will be.
HTTP/1.1 200 OK Cache-Control: no-store Content-Length: 426 Content-Type: application/json Connection: close { “access_token”:”EgAfAQMAAAAEg…”, “token_type”:”bearer” }
The access token is actually much longer, I just shortened it a bit.
Push data to the client
Now we can actually push the data to the client, in this example we’ll send a badge update. We will create a web request in a similar manner that we did when we fetched the access token. But this time we will do the following POST.
POST https://db3.notify.windows.com/?token=AQQAAACL3PSmbrWaRkusVuK… Content-Type: text/xml Host: db3.notify.windows.com
X-WNS-Type: wns/badge Authorization: Bearer EgAfAQMAAAAEg… Content-Length: 59 <?xml version='1.0' encoding='utf-8'?> <badge value="2"/>
Two things worth mentioning here. First of all we POST to the pushUri received from the client. Also, the authorization contains our accessToken. Then as content we send the information used by the client to actually update its tile. The code I used to accomplish this is below.
private HttpStatusCode Push(string pushUri, string accessToken) { var subscriptionUri = new Uri(pushUri); var request = (HttpWebRequest)WebRequest.Create(subscriptionUri); request.Method = "POST"; request.ContentType = "text/xml"; request.Headers = new WebHeaderCollection(); request.Headers.Add("X-WNS-Type", "wns/badge"); request.Headers.Add("Authorization","Bearer " + accessToken); string data = "<?xml version='1.0' encoding='utf-8'?><badge value="2"/>"; byte[] notificationMessage = Encoding.Default.GetBytes(data); request.ContentLength = notificationMessage.Length; using (Stream requestStream = request.GetRequestStream()) { requestStream.Write(notificationMessage, 0, notificationMessage.Length); } var response = (HttpWebResponse)request.GetResponse(); return response.StatusCode; }
The response we would get from this would typically look like.
HTTP/1.1 200 OK Content-Length: 0 X-WNS-NOTIFICATIONSTATUS: received X-WNS-MSG-ID: 1AE359FBBE342FFA X-WNS-DEBUG-TRACE: DB3WNS5044574
Important to note here is that a successful response only indicates that the message was sent, not that it was actually received by the client. So 200 OK only means that the request was processed by WNS. We also receive some debug information that you typically would like to log somewhere if you run into any issues and need support.
Summary
That’s it really. The push was received by the client and if I had actually implemented more support for it than a breakpoint it would work as expected. When it comes to finding documentation and online help for any issues or questions I can (while writing this) say that it’s as best sparse. Prepare for a lot of experimentation and guessing as you go along.
If you don’t want to reinvent the wheel as I did, there’s always Windows Azure Toolkit for Windows 8. It contains push notifications recipes that makes it really easy to create and send push notifications.
If you would like to learn more about developing Metro applications I recommend at visit to Øredev. It will feature a full day track covering Windows 8 development.
Hi Peter,
Where to write GetAccessToken and how can it the url value in the GetAccessToken method. Where to write Push method ? Please clarify me.
Hi Kondalo,
You would typically add GetAccessToken and Push on your server. There you will first call GetAccessToken and then pass in the value into Push. If you are running in Azure you could, for example, call them from your WorkerRole when it found something to report to the client.
I’m not quite sure what you mean with “how can it the url value GetAccessToken method”?
Hi.Peter,
I am a Chinese, my English is not good. How to get push method parameter on the server URL?
Do you have a source?
Thanks.
Hi Peter,
It’s so cool that you write this blog. It really helps me.
Thanks a lot.
Hi Peter,
I am a chinese too, My english is not good.Do you have a source code in win8 with javascript
Hi Peter,
Help Article.
I have a question, Can I use my own web service which is not hosted on the cloud instead of Azure Server.?
If you have any information how to implement. Please share me. That would be a great help.
Thanks
Karthik Vadla
Hi karthik,
Yes, you can use any server to send the push notifications.
You could even implement the app itself to send them, but that would be useless since the whole point of the notifications is to notify the app/user of some kind of external event.
Good luck!
Can I use push notifications, using HTML5/JS app?
Hi Peter,
I need to send push notifications to windows 8 mobile phones and i don’t want to use Widows Azure feature.
Could you please help me understand by answering the following questions?
1. Is steps 4 and 5 in the diagram necessary? what are the disadvantages of not going for steps 4 and 5 ?
2. Cant we directly go for 6 with uri, payload and headers ?
3. Can i write the logic of 4 and 5 and 6 in my own server code ?
Please do share your inputs on this as i am really struggling.
where do you put the client code, which file?
In order to send Push Notifications to your app, your app must be registered with the Windows Store.