4. Raw Notifications
The first type of push notification you can
send is a raw notification. This type of message is sent directly to a
running application. If your application isn’t
running when you send a raw notification, it is just dropped. Raw
notifications enable you to send any sort of message to your
application.
To send a raw notification, you have to use an HTTP call to POST
a message to MPNS. The messages you send to this service are simple
HTTP calls and are not using web services. So you can write your server
code to send a message using the HttpWebRequest
and HttpWebResponse
classes. First, you would set up your request like so:
HttpWebRequest request =
(HttpWebRequest)WebRequest.Create(pushUri);
// For Raw Update use type of body
// (text/plain or text/xml are typical)
request.ContentType = "text/plain";
// Specify the HTTP verb (must be POST)
request.Method = "POST";
This creates the web request, sets the content
type of the message (usually a string or XML fragment), and specifies
that the request is posting data. Next, you need to add some headers to
make the push notification message make sense to the MPNS:
// Use a generated unique ID to prevent duplicate push messages
request.Headers.Add("X-MessageID", Guid.NewGuid().ToString());
// Send Raw Immediate requires class == 3
request.Headers.Add("X-NotificationClass", "3");
To ensure that the message doesn’t get duplicated, you should add a message ID header with a unique ID. The X-NotificationClass
header is required for the MPNS to know how to handle the request. This header needs to be 3
for a raw request. The X-NotificationClass
header specifies the type of message (3
is a raw notification). This tells the MPNS to send the message
immediately. It also enables you to add 10 to the value if you want to
post it to be sent in 450 seconds (7.5 minutes), or you can add 20 to
send it in 900 seconds (15 minutes). So, for a raw notification, the
valid values are 3
, 13
, and 23
, respectively. Next, you will need to push the message into the request stream to have it become part of the message:
// Send it
byte[] notificationMessage = Encoding.UTF8.GetBytes(message);
request.ContentLength = notificationMessage.Length;
using (Stream requestStream = request.GetRequestStream())
{
requestStream.Write(notificationMessage,
0,
notificationMessage.Length);
}
First, the message is encoded into UTF-8 and
converted to a byte array so that you can stuff it into the request
stream. After the size of the message is known, you can specify the
length of the message (ContentLength
). Then you can use the stream to push the message into the request. Finally, you are ready to send the message:
// Sends the notification and gets the response.
try
{
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
return HandleResponse(response);
}
catch (Exception ex)
{
return string.
Concat("Exception during sending message", ex.Message);
}
By calling the GetResponse
method, you will retrieve an HttpWebResponse
,
which will tell you about the status of the message you just posted to
the server. Here is the entire example for pushing a raw notification
to a phone:
string SendRawMessage(string pushUri, string message)
{
HttpWebRequest request =
(HttpWebRequest)WebRequest.Create(pushUri);
// For Raw Update use type of body
// (text/plain or text/xml are typical)
request.ContentType = "text/plain";
// Specify the HTTP verb (must be POST)
request.Method = "POST";
// Use a generated unique ID to prevent duplicate push messages
request.Headers.Add("X-MessageID", Guid.NewGuid().ToString());
// Send Raw Immediate requires class == 3
request.Headers.Add("X-NotificationClass", "3");
// Send it
byte[] notificationMessage = Encoding.UTF8.GetBytes(message);
request.ContentLength = notificationMessage.Length;
using (Stream requestStream = request.GetRequestStream())
{
requestStream.Write(notificationMessage,
0,
notificationMessage.Length);
}
// Sends the notification and gets the response.
try
{
HttpWebResponse response = (HttpWebResponse)request.
GetResponse();
return HandleResponse(response);
}
catch (Exception ex)
{
return string.Concat("Exception during sending message",
ex.Message);
}
}
The response from the server takes the form of two pieces of information that are handled in the HandleResponse
method:
string HandleResponse(HttpWebResponse response)
{
// Pull status from headers if they exist
string notificationStatus =
response.Headers["X-NotificationStatus"];
string deviceStatus = response.Headers["X-DeviceConnectionStatus"];
string subscriptionStatus =
response.Headers["X-SubscriptionStatus"];
switch (response.StatusCode)
{
case HttpStatusCode.OK: // 200
{
//
return "Success";
}
case HttpStatusCode.BadRequest: // 400
{
return
"Failed, bad request";
}
case HttpStatusCode.Unauthorized: // 401
{
return
"Not authorized";
}
case HttpStatusCode.NotFound: // 404
{
return
"Not Found"; }
case HttpStatusCode.MethodNotAllowed: // 405
{
return "Only POST Allowed";
}
case HttpStatusCode.NotAcceptable: // 406
{
return "Request Not Acceptable";
}
case HttpStatusCode.PreconditionFailed: // 412
{
return "Failed to Meet Preconditions";
}
case HttpStatusCode.ServiceUnavailable: // 503
{
return "Service down";
}
}
return "Success";
}
First, the service returns three headers with
the response to indicate certain status information to help you
determine what the service actually did. Table 1 details these headers.
TABLE 1 Push Notification Response Headers
These header response values will mean different things depending on the HTTP status code that was returned. Table 2 shows the mix of HTTP status codes and these header values (from the Windows Phone OS documentation).
TABLE 2 Response Codes and Header Status Codes
Using the information, you
can glean from the HTTP status and the headers, you can determine what
to do with the message. This example does not show any retry mechanism
and simply loses the notification if the message fails. Depending on
the value of the message, you may choose which retry level you need to
accomplish on the server.
Now that you know how to send the message to
the phone, it’s time to discuss how the phone reacts to the message.
The only change in the phone code to receive raw notifications is to
handle the HttpNotificationReceived
event to receive the specific type of message:
_myChannel.HttpNotificationReceived +=
channel_HttpNotificationReceived;
This event is fired when the application receives a raw notification:
void channel_HttpNotificationReceived(object sender,
HttpNotificationEventArgs e)
{
StreamReader rdr = new StreamReader(e.Notification.Body);
string msg = rdr.ReadToEnd();
Deployment.Current.Dispatcher.BeginInvoke(() =>
{
MessageBox.Show(string.Concat("Raw received while app running:",
msg));
});
}
The event sends an object in the HttpNotificationEventArgs
object that contains information about the notification, including the
body of the message as well as the headers. Depending on how you intend
to use the raw message, you might add your information as the body of
the message or as headers. The event here gives you access to either.
It is entirely application-specific how you use raw notifications.
FIGURE 2 Debugging push notifications