Partilhar via


Início Rápido: enviar 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 aplica-se a notificações por push de bloco, informativo, selo e não processadas.

Objetivo: Criar e enviar um azulejo, toast, selo ou notificação por push simples.

Pré-requisitos

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

Instruções

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

Os exemplos fornecidos neste tópico podem ser usados as-is, 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. Crie uma solicitação HTTP POST

O parâmetro uri é o URI (Uniform Resource Identifier) do canal solicitado pelo aplicativo e passado para o servidor de 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 necessá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 se trata de um bloco, 'toast', selo ou notificação crua.
  • O Content-Type é definido dependendo do valor do X-WNS-Type.
  • O Content-Length fornece o tamanho da carga útil de notificação incluída.
  • O cabeçalho Autorização especifica a credencial de autenticação que permite enviar uma notificação por push a 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 dos 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 para 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. Manipular códigos de resposta 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 de captura.

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

HttpStatusCode.Unauthorized: O token de acesso apresentado expirou. Obtenha um novo e tente enviar sua notificação novamente. Como seu 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 seu banco de dados para evitar novas tentativas de enviar notificações para ele. Na próxima vez que esse usuário iniciar seu aplicativo, solicite um novo canal WNS. Seu aplicativo deve detetar que seu canal foi alterado, o que deve acionar o aplicativo para enviar o novo URI do canal para o servidor do aplicativo. 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: Este canal está sendo limitado pelo WNS. Implemente uma estratégia de repetição para reduzir exponencialmente o número de notificações enviadas, a fim de evitar ser novamente sujeito a restrições. Além disso, repense os cenários que estão fazendo com que suas notificações sejam limitadas. Você proporcionará 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 este 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 dos 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. Encapsular 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. Esta função compõe a solicitação HTTP POST que contém uma notificação a ser enviada ao WNS. Ao alterar o valor do parâmetro do tipo e ajustar cabeçalhos adicionais, este código pode ser usado para notificações de brinde, bloco dinâmico, emblema ou notificação push direta. Pode utilizar esta função como parte do código do seu servidor na nuvem.

Observe que o tratamento de erros nesta 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, 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);
}

O seguinte mostra o conteúdo de exemplo de uma solicitação HTTP POST para uma notificação push.

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>

A seguir mostra 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. Neste ponto, você registrou seu aplicativo, autenticou seu servidor de nuvem com WNS, criou conteúdo XML para definir sua notificação e enviou essa notificação do servidor para seu aplicativo.