Schnellstart: Senden einer Pushbenachrichtigung (XAML)

Ihr Cloudserver kann eine Pushbenachrichtigung über die Windows-Pushbenachrichtigungsdienste (Windows Push Notification Services, WNS) an Ihre App senden. Dieses Verfahren gilt für Kachel-, Popup-, Signal- und unformatierte Pushbenachrichtigungen.

Ziel: Zum Erstellen und Senden einer Kachel, eines Popups, eines Badges oder einer unformatierten Pushbenachrichtigung.

Voraussetzungen

Um dieses Thema zu verstehen oder den darin bereitgestellten Code zu verwenden, benötigen Sie Folgendes:

Anweisungen

1. Schließen Sie die erforderlichen Namespaceverweise ein.

Die in diesem Thema aufgeführten Beispiele können wie folgt verwendet werden, erfordern jedoch, dass Ihr Code die folgenden Namespaceverweise enthält:

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

2. Erstellen einer HTTP POST-Anforderung

Der uri Parameter ist der Kanal-URI (Uniform Resource Identifier), der von der App angefordert und an den Cloudserver übergeben wird. Weitere Informationen finden Sie unter "Anfordern, Erstellen und Speichern eines Benachrichtigungskanals".

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

3. Fügen Sie die erforderlichen Kopfzeilen hinzu.

Es gibt vier erforderliche Header, die in allen Pushbenachrichtigungen enthalten sein müssen: X-WNS-Type, Content-Type, Content-Length und Authorization.

  • Der X-WNS-Type-Header gibt an, ob es sich um eine Kachel, ein Popup, ein Signal oder eine unformatierte Benachrichtigung handelt.
  • Der Inhaltstyp wird abhängig vom Wert des X-WNS-Typs festgelegt.
  • Die Inhaltslänge gibt die Größe der enthaltenen Benachrichtigungsnutzlast an.
  • Der Autorisierungsheader gibt die Authentifizierungsanmeldeinformationen an, mit denen Sie über diesen Kanal eine Pushbenachrichtigung an diesen Benutzer senden können.

Der AccessToken-Parameter des Autorisierungsheaders gibt das Zugriffstoken an, das auf dem Server gespeichert wurde, das von WNS empfangen wurde, als der Cloudserver die Authentifizierung angefordert hat. Ohne das Zugriffstoken wird Ihre Benachrichtigung abgelehnt.

Eine vollständige Liste der möglichen Header finden Sie unter Anforderungs- und Antwortheader des Pushbenachrichtigungsdiensts.

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

4. Hinzufügen des vorbereiteten Inhalts

Was die HTTP-Anforderung betrifft, ist der XML-Inhalt der Benachrichtigung ein Datenblob im Anforderungstext. Beispielsweise wird keine Überprüfung vorgenommen, ob die XML mit der X-WNS-Type-Spezifikation übereinstimmt. Der Inhalt wird als XML-Nutzlast angegeben und hier wird der Anforderung als Bytedatenstrom hinzugefügt.

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

5. Lauschen Sie auf eine Antwort von WNS, die den Empfang der Benachrichtigung bestätigt.

Hinweis

Sie erhalten niemals eine Übermittlungsbestätigung für eine Benachrichtigung, nur eine Bestätigung, dass sie von WNS empfangen wurde.

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

6. Behandeln von WNS-Antwortcodes

Es gibt viele Antwortcodes, die Ihr App-Dienst empfangen kann, wenn er eine Benachrichtigung sendet. Einige dieser Antwortcodes sind häufiger als andere und können leicht in einem Catch-Block behandelt werden.

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

HttpStatusCode.Unauthorized: Das von Ihnen angezeigte Zugriffstoken ist abgelaufen. Rufen Sie eine neue ab, und versuchen Sie dann erneut, Ihre Benachrichtigung zu senden. Da Ihr zwischengespeichertes Zugriffstoken nach 24 Stunden abläuft, können Sie davon ausgehen, dass diese Antwort mindestens einmal pro Tag von WNS abgerufen wird. Es wird empfohlen, eine maximale Wiederholungsrichtlinie zu implementieren.

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

HttpStatusCode.Gone / HttpStatusCode.NotFound: Der Kanal-URI ist nicht mehr gültig. Entfernen Sie diesen Kanal aus Ihrer Datenbank, um weitere Versuche, Benachrichtigungen an sie zu senden, zu verhindern. Wenn dieser Benutzer ihre App das nächste Mal startet, fordern Sie einen neuen WNS-Kanal an. Ihre App sollte erkennen, dass sich der Kanal geändert hat, wodurch die App ausgelöst werden soll, um den neuen Kanal-URI an Ihren App-Server zu senden. Weitere Informationen finden Sie unter "Anfordern, Erstellen und Speichern eines Benachrichtigungskanals".

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

HttpStatusCode.NotAcceptable: Dieser Kanal wird von WNS gedrosselt. Implementieren Sie eine Wiederholungsstrategie, die die Anzahl der gesendeten Benachrichtigungen exponentiell reduziert, um zu verhindern, dass sie erneut gedrosselt werden. Denken Sie auch Szenarien um, die dazu führen, dass Ihre Benachrichtigungen gedrosselt werden. Sie bieten eine umfangreichere Benutzererfahrung, indem Sie die von Ihnen gesendeten Benachrichtigungen auf diejenigen beschränken, die einen echten Wert hinzufügen.

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

Andere Antwortcodes: WNS hat mit einem weniger häufig verwendeten Antwortcode geantwortet. Protokollieren Sie diesen Code, um das Debuggen zu unterstützen. Eine vollständige Liste der WNS-Antwortcodes finden Sie unter Anforderungs- und Antwortheader des Pushbenachrichtigungsdiensts .

    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. Kapseln des Codes in eine einzelne Funktion

Im folgenden Beispiel wird der code, der in den vorherigen Schritten angegeben wird, in eine einzelne Funktion verpackt. Diese Funktion verfasst die HTTP POST-Anforderung, die eine Benachrichtigung enthält, die an WNS gesendet werden soll. Durch Ändern des Werts des Typparameters und Anpassen zusätzlicher Header kann dieser Code für Popup-, Kachel-, Signal- oder unformatierte Pushbenachrichtigungen verwendet werden. Sie können diese Funktion als Teil Ihres Cloudservercodes verwenden.

Beachten Sie, dass die Fehlerbehandlung in dieser Funktion die Situation enthält, in der das Zugriffstoken abgelaufen ist. In diesem Fall ruft sie eine weitere Cloudserverfunktion auf, die sich mit WNS erneut authentifiziert, um ein neues Zugriffstoken abzurufen. Anschließend wird ein neuer Aufruf der ursprünglichen Funktion ausgeführt.

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

Im Folgenden sehen Sie Beispielinhalte für eine HTTP POST-Anforderung für eine Popup-Pushbenachrichtigung.

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>

Im Folgenden sehen Sie eine Beispiel-HTTP-Antwort, die von WNS als Antwort auf die HTTP POST-Anforderung an den Cloudserver gesendet wird.

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

Zusammenfassung

In dieser Schnellstartanleitung haben Sie eine HTTP POST-Anforderung zum Senden an WNS erstellt. WNS liefert wiederum die Benachrichtigung an Ihre App. Zu diesem Zeitpunkt haben Sie Ihre App registriert, Ihren Cloudserver mit WNS authentifiziert, XML-Inhalte erstellt, um Ihre Benachrichtigung zu definieren und diese Benachrichtigung von Ihrem Server an Ihre App gesendet.