private void HandleResponse(NotificationResponse response) { var notificationItem = response.NotificationItem; // Handle responses according to: // http://msdn.microsoft.com/en-us/library/ff941100(v=VS.92).aspx // Notification was sent to the queue and will be received. All is good. if (response.NotificationStatus == NotificationStatusReceived) { /*if (response.DeviceConnectionStatus == DeviceConnectionStatusTemporarilyDisconnected) { // We may want to do something clever here though, like not send anything else // to this device for an hour or so. }*/ return; } // If the notification was suppressed, don't do anything. // This could happen because the tile isn't pinned to the start page // or that the client isn't properly configured. // We could potentially implement the "Ask user to pin"-recipe if (response.NotificationStatus == NotificationStatusSuppressed) { return; } // If the subscription has expired, remove it if (response.SubscriptionStatus == SubscriptionStatusExpired) { _registrator.Unregister(notificationItem.ClientUniqueId); return; } // If the queue is full, retry in a few minutes if (response.NotificationStatus == NotificationStatusQueueFull && ( response.DeviceConnectionStatus == DeviceConnectionStatusConnected || response.DeviceConnectionStatus == DeviceConnectionStatusTemporarilyDisconnected ) ) { notificationItem.FailedAttempts++; if (notificationItem.FailedAttempts <= notificationItem.MaxNumberOfAttempts) { // Wait exponentially longer for each failed attempt // Start with 2 minutes, then 4, then 8 etc. var minutesToWait = (2 ^ notificationItem.FailedAttempts); // Re-send this notification in a few minutes _queue.EnqueueItem(notificationItem, DateTime.Now.AddMinutes(minutesToWait)); } return; } // If server returned a 503, retry in a few minutes if (response.StatusCode == 503) { notificationItem.FailedAttempts++; if (notificationItem.FailedAttempts <= notificationItem.MaxNumberOfAttempts) { // Wait exponentially longer for each failed attempt // Start with 2 minutes, then 4, then 8 etc. var minutesToWait = (2 ^ notificationItem.FailedAttempts); // Re-send this notification in a few minutes _queue.EnqueueItem(notificationItem, DateTime.Now.AddMinutes(minutesToWait)); } return; } // Device is in an inactive state. We may retry once every hour if (response.StatusCode == 412 && response.NotificationStatus == NotificationStatusDropped && response.DeviceConnectionStatus == DeviceConnectionStatusInactive) { notificationItem.FailedAttempts++; if (notificationItem.FailedAttempts <= notificationItem.MaxNumberOfAttempts) { // Re-send this notification in an hour _queue.EnqueueItem(notificationItem, DateTime.Now.AddHours(1)); } return; } // Throttling limit reached, let's try again in an hour if (response.NotificationStatus == NotificationStatusDropped && response.SubscriptionStatus == SubscriptionStatusActive) { notificationItem.FailedAttempts++; if (notificationItem.FailedAttempts <= notificationItem.MaxNumberOfAttempts) { // Re-send this notification in an hour _queue.EnqueueItem(notificationItem, DateTime.Now.AddHours(1)); } return; } }
private NotificationResponse SendRequest(string subscriptionUri, byte[] notificationMessage, NotificationKind kind) { 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. sendNotificationRequest.Headers.Add("X-MessageID", Guid.NewGuid().ToString()); if (kind == NotificationKind.Tile) { sendNotificationRequest.ContentType = "text/xml"; sendNotificationRequest.Headers.Add("X-WindowsPhone-Target", "token"); } else if (kind == NotificationKind.Toast) { sendNotificationRequest.ContentType = "text/xml"; sendNotificationRequest.Headers.Add("X-WindowsPhone-Target", "toast"); } // TODO Add support for other notification classes var notificationClass = ((int)NotificationClass.Immediately) + (int)kind; sendNotificationRequest.Headers.Add("X-NotificationClass", notificationClass.ToString()); // Sets the web request content length. sendNotificationRequest.ContentLength = notificationMessage.Length; using (Stream requestStream = sendNotificationRequest.GetRequestStream()) { requestStream.Write(notificationMessage, 0, notificationMessage.Length); } // Sends the notification and make sure we handle the response eventually HttpWebResponse response; try { response = (HttpWebResponse)sendNotificationRequest.GetResponse(); } catch(WebException ex) { response = ex.Response as HttpWebResponse; } var notResponse = new NotificationResponse { StatusCode = (int)response.StatusCode, NotificationStatus = response.Headers["X-NotificationStatus"], SubscriptionStatus = response.Headers["X-SubscriptionStatus"], DeviceConnectionStatus = response.Headers["X-DeviceConnectionStatus"] }; return notResponse; }