Share via


Quickstart: Sending a toast push notification (Windows Store apps using C#/VB/C++ and XAML)

This Quickstart walks you through the steps necessary for your cloud server to send a toast push notification to your app through the Windows Push Notification Services (WNS).

Objective: To create and send a push notification.

Prerequisites

Instructions

1. Include the necessary namespace references

The examples given in this topic can be used as-is, but require that your code include these namespace references:

using System.Net;
using System.IO;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Json;
using System.Web;

2. Create an HTTP POST request.

The uri parameter is the channel Uniform Resource Identifier (URI) requested by the app and passed to the cloud server. For more information, see How to request, create, and save a notification channel.

HttpWebRequest request = HttpWebRequest.Create(uri) as HttpWebRequest;
request.Method = "POST";

3. Add the two required headers.

The accessToken parameter is the access token (stored on the server) that was received from WNS when the cloud server authenticated. Without the access token, you cannot send a notification.

For a complete list of possible headers, see Push notification service request and response headers.

request.Headers.Add("X-WNS-Type", type);
request.Headers.Add("Authorization", String.Format("Bearer {0}", accessToken.AccessToken));

4. Add the prepared toast content.

To the HTTP request, the XML content of the toast notification itself is a black box in the request body. The content is specified as an XML payload and here is added to the request as a stream of bytes.

byte[] contentInBytes = Encoding.UTF8.GetBytes(xml);
                        
using (Stream requestStream = request.GetRequestStream())
requestStream.Write(contentInBytes, 0, contentInBytes.Length);

5. Listen for a response from WNS acknowledging receipt of the notification

Note that you will never receive a delivery confirmation for a notification, just an acknowledgment that it was received by WNS.

using (HttpWebResponse webResponse = (HttpWebResponse)request.GetResponse())
return webResponse.StatusCode.ToString();

6. Encapsulate the code into a single function

The following example packages the code given in the steps of this procedure into a single function that could be part of your cloud server code. It composes the HTTP POST request that contains a notification to be sent to WNS. By changing the value of the type parameter and adjusting the necessary headers, this code can be used for toast, tile, or badge push notifications.

Note that the error handling in this function includes the situation where the access token has expired. In this case, it calls another cloud server function that reauthenticates with WNS to obtain a new access token, and then makes a new call to the original function.

// Post to WNS
public string PostToWns(string secret, string sid, string uri, string xml, string type = "wns/toast")
{
    try
    {
        // You should cache this access token
        var accessToken = GetAccessToken(secret, sid);

        byte[] contentInBytes = Encoding.UTF8.GetBytes(xml);

        HttpWebRequest request = HttpWebRequest.Create(uri) as HttpWebRequest;
        request.Method = "POST";

        request.Headers.Add("X-WNS-Type", type);
        request.Headers.Add("Authorization", String.Format("Bearer {0}", accessToken.AccessToken));

        using (Stream requestStream = request.GetRequestStream())
            requestStream.Write(contentInBytes, 0, contentInBytes.Length);

        using (HttpWebResponse webResponse = (HttpWebResponse)request.GetResponse())
            return webResponse.StatusCode.ToString();
    }
    catch (WebException webException)
    {
        string exceptionDetails = webException.Response.Headers["WWW-Authenticate"];
        if (exceptionDetails.Contains("Token expired"))
        {
            GetAccessToken(secret, sid);

            // Implement a maximum retry policy
            return PostToWns(uri, xml, secret, sid, type);
        }
        else
        {
            // Log the response
            return "EXCEPTION: " + webException.Message;
        }
    }
    catch (Exception ex)
    {
        return "EXCEPTION: " + ex.Message;
    }
}

// Authorization
[DataContract]
public class OAuthToken
{
    [DataMember(Name = "access_token")]
    public string AccessToken { get; set; }
    [DataMember(Name = "token_type")]
    public string TokenType { get; set; }
}

private OAuthToken GetOAuthTokenFromJson(string jsonString)
{
    using (var ms = new MemoryStream(Encoding.Unicode.GetBytes(jsonString)))
    {
        var ser = new DataContractJsonSerializer(typeof(OAuthToken));
        var oAuthToken = (OAuthToken)ser.ReadObject(ms);
        return oAuthToken;
    }
}

protected OAuthToken GetAccessToken(string secret, string sid)
{
    var urlEncodedSecret = HttpUtility.UrlEncode(secret);
    var urlEncodedSid = HttpUtility.UrlEncode(sid);

    var body = String.Format("grant_type=client_credentials&client_id={0}&client_secret={1}&scope=notify.windows.com", 
                             urlEncodedSid, 
                             urlEncodedSecret);

    string response;
    using (var client = new WebClient())
    {
        client.Headers.Add("Content-Type", "application/x-www-form-urlencoded");
        response = client.UploadString("https://login.live.com/accesstoken.srf", body);
    }
    return GetOAuthTokenFromJson(response);
}

Summary and next steps

In this Quickstart, you composed an HTTP POST request, including the toast notification content, to send to WNS. WNS, in turn, delivers the notification to your app.

By this point, you have registered your app, authenticated your cloud server with WNS, created XML content to define your notification, and sent that notification from your server to your app. Next, you can use an almost identical procedure to send a tile notification or badge push notification.

How to request, create, and save a notification channel

Push notification service request and response headers

 

 

Build date: 9/4/2012