public static NotificationSendResult Send(Uri channelUri, IAccessTokenProvider accessTokenProvider, string payload, NotificationType type, int? secondsTTL = null, bool? cache = null, bool? requestForStatus = null, string tag = null, NotificationPriority priority = NotificationPriority.Normal, int tokenRetry = 0)
        {
            NotificationSendResult result;
            byte[] payloadBytes;
            HttpWebRequest request = null;

            try
            {
                WnsDiagnostics.TraceVerbose(
                       DiagnosticsConstants.SendingWNSNotificationID,
                       "Sending WNS notification.\r\n\r\n{0}",
                       NotificationRequestStatus(channelUri.ToString(), payload, secondsTTL, cache, requestForStatus, tag, priority, tokenRetry));

                var accessToken = string.Empty;

                try
                {
                    accessToken = accessTokenProvider.GetAccessToken(true);
                }
                catch (WebException e)
                {
                    if (e.Response != null)
                    {
                        var accessTokenError = GetAccessTokenError(e.Response);
                        WnsDiagnostics.TraceError(DiagnosticsConstants.WnsAccessTokenSendResultErrorID, AccessTokenLogMessage(e.Response, accessTokenError));
                        return new WnsAccessTokenSendResult(channelUri, e, accessTokenError);
                    }
                    else
                    {
                        WnsDiagnostics.TraceError(DiagnosticsConstants.ServiceUnavailableErrorID, e.Message);
                        return new NotificationSendResult(channelUri, e.Message, HttpStatusCode.ServiceUnavailable);
                    }
                }

                request = CreateWebRequest(channelUri, accessToken, payload, type, secondsTTL, cache, requestForStatus, tag, priority, out payloadBytes);

                using (Stream requestStream = request.GetRequestStream())
                {
                    requestStream.Write(payloadBytes, 0, payloadBytes.Length);
                }

                var response = (HttpWebResponse)request.GetResponse();
                result = new NotificationSendResult(channelUri, response);

                WnsDiagnostics.TraceInformation(DiagnosticsConstants.SentWNSNotificationID, NotificationLogMessage("Sent WNS notification", result.NotificationStatus.ToString(), result, payload, request, response));
            }
            catch (WebException e)
            {
                if (e.Response != null)
                {
                    string exceptionDetails = e.Response.Headers[WnsHeaders.WWWAuthenticate];
                    if (!string.IsNullOrWhiteSpace(exceptionDetails) && exceptionDetails.Contains("Token expired"))
                    {
                        accessTokenProvider.ResetCachedToken();

                        tokenRetry++;
                        if (tokenRetry <= MaxSendRetries)
                        {
                            result = Send(channelUri, accessTokenProvider, payload, type, secondsTTL, cache, requestForStatus, tag, priority, tokenRetry);
                        }
                        else
                        {
                            result = new NotificationSendResult(channelUri, e);
                        }
                    }
                    else
                    {
                        result = new NotificationSendResult(channelUri, e);
                    }

                    WnsDiagnostics.TraceError(DiagnosticsConstants.WNSNotificationFailureID, NotificationLogMessage("WNS notification failure", e.Message, result, payload, request, e.Response));
                }
                else
                {
                    WnsDiagnostics.TraceError(DiagnosticsConstants.ServiceUnavailableErrorID, e.Message);
                    return new NotificationSendResult(channelUri, e.Message, HttpStatusCode.ServiceUnavailable);
                }
            }
            catch (Exception e)
            {
                result = new NotificationSendResult(channelUri, e);

                WnsDiagnostics.TraceException(DiagnosticsConstants.WNSNotificationFailureID, e, "WNS notification failure: {0}\r\n\r\n{1}", e.Message, result);
            }

            return result;
        }
        public static void SendAsynchronously(Uri channelUri, IAccessTokenProvider accessTokenProvider, string payload, Action<NotificationSendResult> sent, Action<NotificationSendResult> error, NotificationType type, int? secondsTTL = null, bool? cache = null, bool? requestForStatus = null, string tag = null, NotificationPriority priority = NotificationPriority.Normal, int tokenRetry = 0)
        {
            byte[] payloadBytes;

            try
            {
                WnsDiagnostics.TraceVerbose(
                    DiagnosticsConstants.SendingWNSNotificationID,
                    "Sending WNS notification.\r\n\r\n{0}",
                    NotificationRequestStatus(channelUri.ToString(), payload, secondsTTL, cache, requestForStatus, tag, priority, tokenRetry));

                var accessToken = string.Empty;

                try
                {
                    accessToken = accessTokenProvider.GetAccessToken(true);
                }
                catch (WebException e)
                {
                    if (e.Response != null)
                    {
                        var accessTokenError = GetAccessTokenError(e.Response);
                        WnsDiagnostics.TraceError(DiagnosticsConstants.WnsAccessTokenSendResultErrorID, AccessTokenLogMessage(e.Response, accessTokenError));
                        error(new WnsAccessTokenSendResult(channelUri, e, accessTokenError));
                    }
                    else
                    {
                        WnsDiagnostics.TraceError(DiagnosticsConstants.ServiceUnavailableErrorID, e.Message);
                        error(new NotificationSendResult(channelUri, e.Message, HttpStatusCode.ServiceUnavailable));
                    }
                }

                if (!string.IsNullOrEmpty(accessToken))
                {
                    var request = CreateWebRequest(channelUri, accessToken, payload, type, secondsTTL, cache, requestForStatus, tag, priority, out payloadBytes);

                    // Get the request stream asynchronously.
                    request.BeginGetRequestStream(
                        requestAsyncResult =>
                        {
                            try
                            {
                                using (Stream requestStream = request.EndGetRequestStream(requestAsyncResult))
                                {
                                    // Start writing the payload to the stream.
                                    requestStream.Write(payloadBytes, 0, payloadBytes.Length);
                                }

                                // Switch to receiving the response from WNS asynchronously.
                                request.BeginGetResponse(
                                    responseAsyncResult =>
                                    {
                                        try
                                        {
                                            using (
                                                var response =
                                                    (HttpWebResponse)request.EndGetResponse(responseAsyncResult))
                                            {
                                                var result = new NotificationSendResult(channelUri, response);
                                                if (result.StatusCode == HttpStatusCode.OK)
                                                {
                                                    WnsDiagnostics.TraceInformation(DiagnosticsConstants.SentWNSNotificationID, NotificationLogMessage("Sent WNS notification", result.NotificationStatus.ToString(), result, payload, request, response));
                                                    sent(result);
                                                }
                                                else
                                                {
                                                    error(result);
                                                    WnsDiagnostics.TraceError(DiagnosticsConstants.WNSNotificationFailureID, "WNS notification failure:\r\n\r\n{0}", result);
                                                }
                                            }
                                        }
                                        catch (WebException e)
                                        {
                                            if (e.Response != null)
                                            {
                                                var result = new NotificationSendResult(channelUri, e);

                                                string exceptionDetails = e.Response.Headers[WnsHeaders.WWWAuthenticate];
                                                if (!string.IsNullOrWhiteSpace(exceptionDetails) &&
                                                    exceptionDetails.Contains("Token expired"))
                                                {
                                                    accessTokenProvider.ResetCachedToken();

                                                    tokenRetry++;
                                                    if (tokenRetry <= MaxSendRetries)
                                                    {
                                                        SendAsynchronously(channelUri, accessTokenProvider, payload, sent, error, type, secondsTTL, cache, requestForStatus, tag, priority, tokenRetry);
                                                    }
                                                    else
                                                    {
                                                        WnsDiagnostics.TraceError(DiagnosticsConstants.WNSNotificationFailureID, NotificationLogMessage("WNS notification failure", e.Message, result, payload, request, e.Response));
                                                        error(result);
                                                    }
                                                }
                                                else
                                                {
                                                    WnsDiagnostics.TraceError(DiagnosticsConstants.WNSNotificationFailureID, NotificationLogMessage("WNS notification failure", e.Message, result, payload, request, e.Response));
                                                    error(result);
                                                }
                                            }
                                            else
                                            {
                                                WnsDiagnostics.TraceError(DiagnosticsConstants.ServiceUnavailableErrorID, e.Message);
                                                error(new NotificationSendResult(channelUri, e.Message, HttpStatusCode.ServiceUnavailable));
                                            }
                                        }
                                        catch (Exception ex3)
                                        {
                                            var result = new NotificationSendResult(channelUri, ex3);
                                            WnsDiagnostics.TraceException(DiagnosticsConstants.GeneralNotificationFailureID, ex3, "WNS notification failure: {0}\r\n\r\n{1}", ex3.Message, result);
                                            error(result);
                                        }
                                    },
                                    null);
                            }
                            catch (Exception ex2)
                            {
                                var result = new NotificationSendResult(channelUri, ex2);
                                WnsDiagnostics.TraceException(DiagnosticsConstants.GeneralNotificationFailureID, ex2, "WNS notification failure: {0}\r\n\r\n{1}", ex2.Message, result);
                                error(result);
                            }
                        },
                        null);
                }
            }
            catch (Exception ex1)
            {
                var result = new NotificationSendResult(channelUri, ex1);
                WnsDiagnostics.TraceException(DiagnosticsConstants.GeneralNotificationFailureID, ex1, "WNS notification failure: {0}\r\n\r\n{1}", ex1.Message, result);
                error(result);
            }
        }