Udostępnij za pośrednictwem


Szybki start: wysyłanie powiadomienia push (XAML)

Twój serwer w chmurze jest w stanie wysyłać powiadomienia push do Twojej aplikacji za pośrednictwem usług powiadomień systemu Windows (WNS). Ta procedura dotyczy kafelka, powiadomień typu toast, znaczka i nieprzetworzonych powiadomień push.

Cel: Utworzyć i wysłać kafelek, powiadomienie, znaczek lub powiadomienie push.

Wymagania wstępne

Aby zrozumieć ten temat lub użyć kodu, który zawiera, potrzebne są następujące elementy:

Instrukcje

1. Dołącz niezbędne odwołania do przestrzeni nazw

Przykłady podane w tym temacie mogą być używane, ale wymagają, aby kod zawierał następujące odwołania do przestrzeni nazw: as-is.

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

2. Tworzenie żądania HTTP POST

Parametr uri to kanał Uniform Resource Identifier (URI) żądany przez aplikację i przekazany do serwera w chmurze. Aby uzyskać więcej informacji, zobacz Jak zażądać, utworzyć i zapisać kanał powiadomień.

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

3. Dodaj wymagane nagłówki

Istnieją cztery wymagane nagłówki, które muszą być uwzględnione we wszystkich powiadomieniach wypychanych: X-WNS-Type, Content-Type, Content-Length i Authorization.

  • Nagłówek X-WNS-Type określa, czy jest to kafelek, wyskakujące, znaczek lub nieprzetworzone powiadomienie.
  • Typ zawartości jest ustawiany w zależności od wartości X-WNS-Type.
  • Właściwość Content-Length określa rozmiar zawartego ładunku danych powiadomień.
  • Nagłówek Autoryzacja określa poświadczenie uwierzytelniające, które umożliwia wysyłanie powiadomień push do tego użytkownika tym kanałem.

Parametr accessToken nagłówka Authorization określa token dostępu przechowywany na serwerze, który został odebrany z usługi WNS, gdy serwer w chmurze zażądał uwierzytelnienia. Bez tokenu dostępu powiadomienie zostanie odrzucone.

Aby uzyskać pełną listę możliwych nagłówków, zobacz Push notification service request and response headers (Żądania usługi powiadomień wypychanych i nagłówki odpowiedzi).

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

4. Dodawanie przygotowanej zawartości

Jeśli chodzi o żądanie HTTP, zawartość XML powiadomienia jest zbiorem danych w treści żądania. Na przykład nie dokonano weryfikacji, że kod XML jest zgodny ze specyfikacją X-WNS-Type. Zawartość jest określana jako ładunek XML i tutaj jest dodawana do żądania jako strumień bajtów.

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

5. Oczekuj odpowiedzi z usługi WNS, która potwierdza otrzymanie powiadomienia

Uwaga / Notatka

Nigdy nie otrzymasz potwierdzenia dostarczenia dla powiadomienia, po prostu potwierdzenie, że zostało odebrane przez usługę WNS.

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

6. Obsługa kodów odpowiedzi usługi WNS

Istnieje wiele kodów odpowiedzi, które usługa App Service może odbierać po wysłaniu powiadomienia. Niektóre z tych kodów odpowiedzi są bardziej powszechne niż inne i mogą być łatwo obsługiwane w bloku catch.

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

HttpStatusCode.Unauthorized: wyświetlony token dostępu wygasł. Pobierz nowy, a następnie spróbuj ponownie wysłać powiadomienie. Ponieważ buforowany token dostępu wygasa po 24 godzinach, możesz oczekiwać, że ta odpowiedź będzie uzyskiwana z usługi WNS co najmniej raz dziennie. Zalecamy zaimplementowanie maksymalnych zasad ponawiania prób.

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

HttpStatusCode.Gone / HttpStatusCode.NotFound: Identyfikator URI kanału nie jest już prawidłowy. Usuń ten kanał z bazy danych, aby uniemożliwić dalsze próby wysłania do niej powiadomienia. Następnym razem, gdy ten użytkownik uruchomi aplikację, zażądaj nowego kanału WNS. Aplikacja powinna wykryć, że jej kanał uległ zmianie, co powinno spowodować wysłanie nowego identyfikatora URI kanału do serwera aplikacji. Aby uzyskać więcej informacji, zobacz Jak zażądać, utworzyć i zapisać kanał powiadomień.

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

HttpStatusCode.NotAcceptable: ten kanał jest ograniczany przez usługę WNS. Zaimplementuj strategię ponawiania, która wykładniczo zmniejsza liczbę wysyłanych powiadomień, aby zapobiec ponownemu ograniczaniu przepustowości. Rozważ również scenariusze, które powodują ograniczanie powiadomień. Zapewnisz bogatsze doświadczenie użytkownika, ograniczając powiadomienia do tych, które rzeczywiście dodają prawdziwą wartość.

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

Inne kody odpowiedzi: WNS odpowiedział mniej typowym kodem odpowiedzi. Zarejestruj ten kod, aby ułatwić debugowanie. Aby uzyskać pełną listę kodów odpowiedzi WNS, zobacz Nagłówki żądań i odpowiedzi usługi powiadomień push.

    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. Hermetyzowanie kodu w jedną funkcję

Poniższy przykład pakuje kod podany w poprzednich krokach do pojedynczej funkcji. Ta funkcja komponuje żądanie HTTP POST zawierające powiadomienie wysyłane do usługi WNS. Zmieniając wartość parametru typu i dostosowując dodatkowe nagłówki, ten kod może być użyty do powiadomień toast, kafelki, odznaki lub surowych powiadomień push. Tej funkcji można używać jako części kodu serwera w chmurze.

Należy pamiętać, że obsługa błędów w tej funkcji obejmuje sytuację, w której token dostępu wygasł. W takim przypadku wywołuje inną funkcję serwera w chmurze, która ponownie uwierzytelnia się w usłudze WNS, aby uzyskać nowy token dostępu. Następnie wykonuje nowe wywołanie oryginalnej funkcji.

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

Poniżej przedstawiono przykładową zawartość żądania HTTP POST dla powiadomienia typu toast.

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>

Poniżej przedstawiono przykładową odpowiedź HTTP wysłaną do serwera w chmurze przez usługę WNS w odpowiedzi na żądanie 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

Podsumowanie

W tej sekcji Quickstart utworzono żądanie HTTP POST, aby wysłać je do usługi WNS. Z kolei usługa WNS dostarcza powiadomienie do aplikacji. W tym momencie zarejestrowano aplikację, uwierzytelniono serwer w chmurze za pomocą usługi WNS, utworzono zawartość XML w celu zdefiniowania powiadomienia i wysłano to powiadomienie z serwera do aplikacji.