Compartir a través de


Inicio rápido: Envío de una notificación push (XAML)

El servidor en la nube puede enviar una notificación push a la aplicación a través de los Servicios de notificaciones push de Windows (WNS). Este procedimiento se aplica a las notificaciones de icono, notificación del sistema, distintivo y inserción sin procesar.

Objetivo: Para crear y enviar un icono, notificación del sistema, distintivo o notificación de inserción sin procesar.

Requisitos previos

Para comprender este tema o para usar el código que proporciona, necesitará lo siguiente:

Instrucciones

1. Incluir las referencias de espacio de nombres necesarias

Los ejemplos que se proporcionan en este tema se pueden usar tal como está, pero requieren que el código incluya estas referencias de espacio de nombres:

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

2. Creación de una solicitud HTTP POST

El uri parámetro es el identificador uniforme de recursos (URI) del canal solicitado por la aplicación y pasado al servidor en la nube. Para obtener más información, consulte Cómo solicitar, crear y guardar un canal de notificación.

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

3. Agregar los encabezados necesarios

Hay cuatro encabezados necesarios que deben incluirse en todas las notificaciones push: X-WNS-Type, Content-Type, Content-Length y Authorization.

  • El encabezado X-WNS-Type especifica si se trata de un icono, notificación del sistema, distintivo o notificación sin procesar.
  • Content-Type se establece en función del valor del tipo X-WNS.
  • Content-Length proporciona el tamaño de la carga de notificación incluida.
  • El encabezado Authorization especifica la credencial de autenticación que le permite enviar una notificación push a este usuario a través de este canal.

El parámetro accessToken del encabezado Authorization especifica el token de acceso, almacenado en el servidor, que se recibió de WNS cuando el servidor en la nube solicitó la autenticación. Sin el token de acceso, se rechazará la notificación.

Para obtener una lista completa de los posibles encabezados, consulte Encabezados de solicitud y respuesta del servicio de notificaciones push.

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

4. Agregar el contenido preparado

En lo que respecta a la solicitud HTTP, el contenido XML de la notificación es un blob de datos en el cuerpo de la solicitud. Por ejemplo, no se realiza ninguna comprobación de que el XML coincida con la especificación X-WNS-Type. El contenido se especifica como una carga XML y aquí se agrega a la solicitud como un flujo de bytes.

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

5. Escuche una respuesta de WNS que confirme la recepción de la notificación.

Nota:

Nunca recibirá una confirmación de entrega para una notificación, solo una confirmación de que WNS la recibió.

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

6. Controlar códigos de respuesta WNS

Hay muchos códigos de respuesta que el servicio de aplicaciones puede recibir cuando envía una notificación. Algunos de estos códigos de respuesta son más comunes que otros y se pueden tratar fácilmente en un bloque catch.

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

HttpStatusCode.Unauthorized: el token de acceso que presentó ha expirado. Obtenga una nueva y vuelva a intentar enviar la notificación. Dado que el token de acceso almacenado en caché expira después de 24 horas, puede esperar obtener esta respuesta de WNS al menos una vez al día. Se recomienda implementar una directiva de reintento máxima.

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

HttpStatusCode.Gone / HttpStatusCode.NotFound: el URI del canal ya no es válido. Quite este canal de la base de datos para evitar más intentos de enviar notificaciones a ella. La próxima vez que este usuario inicie la aplicación, solicite un nuevo canal WNS. La aplicación debe detectar que su canal ha cambiado, que debe desencadenar la aplicación para enviar el nuevo URI del canal al servidor de aplicaciones. Para obtener más información, consulte Cómo solicitar, crear y guardar un canal de notificación.

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

HttpStatusCode.NotAcceptable: WNS limita este canal. Implemente una estrategia de reintento que reduzca exponencialmente la cantidad de notificaciones que se envían para evitar que se vuelva a limitar. Además, replantee los escenarios que hacen que las notificaciones se limiten. Proporcionará una experiencia de usuario más completa limitando las notificaciones que envíe a aquellos que agreguen un valor verdadero.

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

Otros códigos de respuesta: WNS respondió con un código de respuesta menos común. Registre este código para ayudar a depurar. Consulte Push notification service request and response headers (Encabezados de solicitud y respuesta de servicio de notificaciones push) para obtener una lista completa de códigos de respuesta de 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 el código en una sola función

En el ejemplo siguiente se empaqueta el código proporcionado en los pasos anteriores en una sola función. Esta función compone la solicitud HTTP POST que contiene una notificación que se enviará a WNS. Al cambiar el valor del parámetro de tipo y ajustar los encabezados adicionales, este código se puede usar para notificaciones del sistema, icono, distintivo o inserción sin procesar. Puede usar esta función como parte del código del servidor en la nube.

Tenga en cuenta que el control de errores de esta función incluye la situación en la que el token de acceso ha expirado. En este caso, llama a otra función de servidor en la nube que vuelve a autenticarse con WNS para obtener un nuevo token de acceso. A continuación, realiza una nueva llamada a la función 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);
}

A continuación se muestra el contenido de ejemplo de una solicitud HTTP POST para una notificación push del 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>

A continuación se muestra una respuesta HTTP de ejemplo, enviada al servidor en la nube por WNS en respuesta a la solicitud 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

Resumen

En este inicio rápido, ha compuesto una solicitud HTTP POST para enviar a WNS. WNS, a su vez, entrega la notificación a la aplicación. En este punto, ha registrado la aplicación, ha autenticado el servidor en la nube con WNS, ha creado contenido XML para definir la notificación y ha enviado esa notificación desde el servidor a la aplicación.