Compartilhar via


Guia de início rápido: Enviando uma notificação por push (XAML)

Seu servidor de nuvem pode enviar uma notificação por push para seu aplicativo por meio dos Serviços de Notificação por Push do Windows (WNS). Este procedimento se aplica a notificações por push de bloco, notificação do sistema, notificação e não processadas.

Objetivo: criar e enviar um bloco, notificação do sistema, notificação ou notificação por push bruta.

Pré-requisitos

Para entender este tópico ou usar o código que ele fornece, você precisará de:

Instruções

1. Inclua as referências de namespace necessárias

Os exemplos fornecidos neste tópico podem ser usados no estado em que se encontram, mas exigem que seu código inclua estas referências de namespace:

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

2. Criar uma solicitação HTTP POST

O uri parâmetro é o URI (Uniform Resource Identifier) do canal solicitado pelo aplicativo e passado para o servidor em nuvem. Para obter mais informações, consulte Como solicitar, criar e salvar um canal de notificação.

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

3. Adicione os cabeçalhos necessários

Há quatro cabeçalhos obrigatórios que devem ser incluídos em todas as notificações por push: X-WNS-Type, Content-Type, Content-Length e Authorization.

  • O cabeçalho X-WNS-Type especifica se isso é um bloco, notificação do sistema, notificação ou notificação bruta.
  • O Content-Type é definido dependendo do valor do X-WNS-Type.
  • O Content-Length fornece o tamanho da carga de notificação incluída.
  • O cabeçalho Authorization especifica a credencial de autenticação que permite enviar uma notificação por push para esse usuário por esse canal.

O parâmetro accessToken do cabeçalho Authorization especifica o token de acesso, armazenado no servidor, que foi recebido do WNS quando o servidor de nuvem solicitou autenticação. Sem o token de acesso, sua notificação será rejeitada.

Para obter uma lista completa de cabeçalhos possíveis, consulte Cabeçalhos de solicitação e resposta do serviço de notificação por push.

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

4. Adicione o conteúdo preparado

No que diz respeito à solicitação HTTP, o conteúdo XML da notificação é um blob de dados no corpo da solicitação. Por exemplo, nenhuma verificação é feita se o XML corresponde à especificação X-WNS-Type. O conteúdo é especificado como uma carga XML e aqui é adicionado à solicitação como um fluxo de bytes.

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

5. Ouça uma resposta do WNS que confirme o recebimento da notificação

Observação

Você nunca receberá uma confirmação de entrega de uma notificação, apenas uma confirmação de que ela foi recebida pelo WNS.

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

6. Lidar com códigos de resposta do WNS

Há muitos códigos de resposta que seu serviço de aplicativo pode receber quando envia uma notificação. Alguns desses códigos de resposta são mais comuns do que outros e podem ser facilmente tratados em um bloco catch.

catch (WebException webException)
{
    HttpStatusCode status = ((HttpWebResponse)webException.Response).StatusCode;

HttpStatusCode.Unauthorized: o token de acesso que você apresentou expirou. Obtenha um novo e tente enviar sua notificação novamente. Como o token de acesso armazenado em cache expira após 24 horas, você pode esperar obter essa resposta do WNS pelo menos uma vez por dia. Recomendamos que você implemente uma política de repetição máxima.

    if (status == HttpStatusCode.Unauthorized)
    {
        GetAccessToken(secret, sid);
        return PostToWns(uri, xml, secret, sid, notificationType, contentType);
    }

HttpStatusCode.Gone / HttpStatusCode.NotFound: o URI do canal não é mais válido. Remova esse canal do banco de dados para evitar novas tentativas de enviar notificação para ele. Na próxima vez que esse usuário iniciar seu aplicativo, solicite um novo canal WNS. Seu aplicativo deve detectar que seu canal foi alterado, o que deve disparar o aplicativo para enviar o novo URI do canal para o servidor de aplicativos. Para obter mais informações, consulte Como solicitar, criar e salvar um canal de notificação.

    else if (status == HttpStatusCode.Gone || status == HttpStatusCode.NotFound)
    {
        return "";
    }

HttpStatusCode.NotAcceptable: esse canal está sendo limitado pelo WNS. Implemente uma estratégia de repetição que reduza exponencialmente a quantidade de notificações enviadas para evitar ser limitado novamente. Além disso, repense os cenários que estão fazendo com que suas notificações sejam limitadas. Você fornecerá uma experiência de usuário mais rica, limitando as notificações enviadas àquelas que agregam valor real.

    else if (status == HttpStatusCode.NotAcceptable)
    {
        return "";
    }

Outros códigos de resposta: o WNS respondeu com um código de resposta menos comum. Registre esse código para ajudar na depuração. Consulte Cabeçalhos de solicitação e resposta do serviço de notificação por push para obter uma lista completa de códigos de resposta do WNS.

    else
    {
        string[] debugOutput = {
                                   status.ToString(),
                                   webException.Response.Headers["X-WNS-Debug-Trace"],
                                   webException.Response.Headers["X-WNS-Error-Description"],
                                   webException.Response.Headers["X-WNS-Msg-ID"],
                                   webException.Response.Headers["X-WNS-Status"]
                               };
        return string.Join(" | ", debugOutput);            
    }

7. Encapsule o código em uma única função

O exemplo a seguir empacota o código fornecido nas etapas anteriores em uma única função. Essa função compõe a solicitação HTTP POST que contém uma notificação a ser enviada ao WNS. Alterando o valor do parâmetro type e ajustando cabeçalhos adicionais, esse código pode ser usado para notificações por push do sistema, bloco, notificação ou não processadas. Você pode usar essa função como parte do código do servidor em nuvem.

Observe que o tratamento de erros nessa função inclui a situação em que o token de acesso expirou. Nesse caso, ele chama outra função de servidor de nuvem que se autentica novamente com o WNS para obter um novo token de acesso. Em seguida, ele faz uma nova chamada para a função original.

// Post to WNS
public string PostToWns(string secret, string sid, string uri, string xml, string notificationType, string contentType)
{
    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", notificationType);
        request.ContentType = contentType;
        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)
    {
        HttpStatusCode status = ((HttpWebResponse)webException.Response).StatusCode;

        if (status == HttpStatusCode.Unauthorized)
        {
            // The access token you presented has expired. Get a new one and then try sending
            // your notification again.
              
            // Because your cached access token expires after 24 hours, you can expect to get 
            // this response from WNS at least once a day.

            GetAccessToken(secret, sid);

            // We recommend that you implement a maximum retry policy.
            return PostToWns(uri, xml, secret, sid, notificationType, contentType);
        }
        else if (status == HttpStatusCode.Gone || status == HttpStatusCode.NotFound)
        {
            // The channel URI is no longer valid.

            // Remove this channel from your database to prevent further attempts
            // to send notifications to it.

            // The next time that this user launches your app, request a new WNS channel.
            // Your app should detect that its channel has changed, which should trigger
            // the app to send the new channel URI to your app server.

            return "";
        }
        else if (status == HttpStatusCode.NotAcceptable)
        {
            // This channel is being throttled by WNS.

            // Implement a retry strategy that exponentially reduces the amount of
            // notifications being sent in order to prevent being throttled again.

            // Also, consider the scenarios that are causing your notifications to be throttled. 
            // You will provide a richer user experience by limiting the notifications you send 
            // to those that add true value.

            return "";
        }
        else
        {
            // WNS responded with a less common error. Log this error to assist in debugging.

            // You can see a full list of WNS response codes here:
            // https://msdn.microsoft.com/library/windows/apps/hh868245.aspx#wnsresponsecodes

            string[] debugOutput = {
                                       status.ToString(),
                                       webException.Response.Headers["X-WNS-Debug-Trace"],
                                       webException.Response.Headers["X-WNS-Error-Description"],
                                       webException.Response.Headers["X-WNS-Msg-ID"],
                                       webException.Response.Headers["X-WNS-Status"]
                                   };
            return string.Join(" | ", debugOutput);            
        }
    }

    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);
}

Veja a seguir um exemplo de conteúdo para uma solicitação HTTP POST para uma notificação por push do sistema.

POST https://db3.notify.windows.com/?token=AgUAAADCQmTg7OMlCg%2fK0K8rBPcBqHuy%2b1rTSNPMuIzF6BtvpRdT7DM4j%2fs%2bNNm8z5l1QKZMtyjByKW5uXqb9V7hIAeA3i8FoKR%2f49ZnGgyUkAhzix%2fuSuasL3jalk7562F4Bpw%3d HTTP/1.1
Authorization: Bearer EgAaAQMAAAAEgAAACoAAPzCGedIbQb9vRfPF2Lxy3K//QZB79mLTgK
X-WNS-RequestForStatus: true
X-WNS-Type: wns/toast
Content-Type: text/xml
Host: db3.notify.windows.com
Content-Length: 196

<toast launch="">
  <visual lang="en-US">
    <binding template="ToastImageAndText01">
      <image id="1" src="World" />
      <text id="1">Hello</text>
    </binding>
  </visual>
</toast>

Veja a seguir um exemplo de resposta HTTP, enviada ao servidor de nuvem pelo WNS em resposta à solicitação HTTP POST.

HTTP/1.1 200 OK
Content-Length: 0
X-WNS-DEVICECONNECTIONSTATUS: connected
X-WNS-STATUS: received
X-WNS-MSG-ID: 3CE38FF109E03A74
X-WNS-DEBUG-TRACE: DB3WNS4011534

Resumo

Neste Guia de início rápido, você compôs uma solicitação HTTP POST para enviar ao WNS. O WNS, por sua vez, entrega a notificação ao seu aplicativo. A essa altura, você registrou seu aplicativo, autenticou seu servidor de nuvem com o WNS, criou conteúdo XML para definir sua notificação e enviou essa notificação do servidor para seu aplicativo.