Registrera från din appserverdel

Som vi nämnde i föregående avsnitt måste enheterna skapa en eller flera registreringar i en meddelandehubb för att kunna ta emot push-meddelanden. Ett sätt att slutföra registreringen är att låta de mobila enheterna kontakta meddelandehubben direkt för att ange (eller uppdatera) deras PNS-handtag och deras taggar. Den här metoden har ett antal begränsningar och det finns vissa scenarier där det är lämpligt att kontakta din egen appserverdel när en enhet uppdaterar registreringen. Serverdelen anropar sedan meddelandehubben.

När du ska registrera dig från appens serverdel

Det finns två scenarier där det är lämpligt att dirigera enhetsregistreringar via appens serverdel.

Taggar måste skyddas

När en enhet registreras direkt med en meddelandehubb kan den ange vilken tagg den vill. Detta är inte ett problem om taggar är grupper av allmänt intresse som alla enheter kan prenumerera på (till exempel nyhetsfeeds om sportlag). Detta kan dock vara ett problem när vissa taggar endast är tillgängliga för vissa användare.

För att endast registrera varje användare till de tillåtna taggarna måste du dirigera registreringsåtgärderna via din egen appserverdel, som kan utföra användarautentisering och auktorisera registreringen för de taggar som krävs.

Det vanligaste exemplet på det här scenariot är att använda taggar för att representera användar-ID:t. I det här fallet vill du förhindra att enheter registrerar sig för taggar som representerar andra användare, eftersom de får den andra användarens meddelanden.

Taggar ändras av appens serverdel

Registrering från enheten är praktiskt och gör att du snabbt kan konfigurera push-meddelanden och omfattande routning till intressegrupper. Registrering från enheten fungerar dock inte så bra om du vill ändra taggar till följd av händelser som inträffar på andra enheter.

Överväg två scenarier: om taggarna på Alice telefon anges till följd av händelser som inträffar på Alice telefon är det enkelt för appen att uppdatera taggarna i meddelandehubben. Om taggar å andra sidan måste ändras till följd av händelser som inträffar på andra enheter (till exempel Alice bärbara dator när den är inloggad på en webbplats) måste enheten vänta på att appen ska vara aktiv igen för att återspegla ändringarna i meddelandehubben.

Ett specifikt exempel på föregående scenario är en musikapp som innehåller en webbupplevelse och en mobilapp. I det här fallet kan en specifik användare följa ett nytt band via webbplatsen och vill att enheten ska börja ta emot meddelanden om det nya bandet så snart som möjligt. Ett annat exempel är när taggar kommer från andra delar av serverdelen (till exempel en CRM), som kan ändra status för användaren från Silver till Guld. Den här ändringen kan resultera i att en ny tagg anges för alla användares registreringar.

Så här registrerar du dig från serverdelen

När du registrerar en enhet måste en meddelandehubb skilja mellan olika enheter. Detta kan inte åstadkommas bara genom att titta på PNS-handtagen, eftersom de är tillfälliga och inte unika. För att lösa det här problemet genererar Notification Hubs långvariga registrerings-ID:n som varje enhet måste lagra lokalt för att kunna referera till sin egen registrering varje gång den uppdaterar sin PNS-handtag, taggar eller mall.

Följande bild visar registreringsflödet för interna meddelanden:

  1. Om inget registrerings-ID lagras lokalt på enheten

    1. Anropa appens serverdel för att få registrerings-ID.

    2. Appens serverdel anropar meddelandehubbar för att skapa ett nytt registrerings-ID och returnerar sedan ID:t tillbaka till enheten.

    3. Lagra registrerings-ID:t i enhetens lokala lagring.

  2. Hämta registrerings-ID:t från lokal lagring på enheten:

    1. Anropa appens serverdel och ange registrerings-ID, PNS-handtag och taggar.

    2. Appens serverdel skapar eller uppdaterar motsvarande registrering på meddelandehubben.

    3. Om appens serverdel returnerar statuskod 410 måste ett nytt registrerings-ID skapas. Ta bort registrerings-ID:t från lokal lagring och starta om från steg 1.

Backend Registration

Flödet för mallmeddelanden är detsamma som det. De enda skillnaderna är följande:

  1. Om en enhet använder flera mallar måste den lagra ett registrerings-ID per mall.

  2. Du kan identifiera mallarna med hjälp av egenskapen TemplateName för registreringen.

Följande kod är ett exempel på serverdelsslutpunkter.

public class RegisterController : ApiController
    {

        private NotificationHubClient hub;

        public RegisterController()
        {
            hub = NotificationHubClient.CreateClientFromConnectionString("Endpoint=sb://buildhub-ns.servicebus.windows.net/;SharedAccessKeyName=DefaultFullSharedAccessSignature;SharedAccessKey=DuWV4SQ08poV6HZly8O/KQNWv3YRTZlExJxu3pNCjGU=", "build2014_2");
        }
        
        public class DeviceRegistration
        {
            public string Platform { get; set; }
            public string Handle { get; set; }
            public string[] Tags { get; set; }
        }

        // POST api/register
        // This creates a registration id
        public async Task<string> Post()
        {
            return await hub.CreateRegistrationIdAsync();
        }

        // PUT api/register/5
        // This creates or updates a registration (with provided PNS handle) at the specified id
        public async void Put(string id, DeviceRegistration deviceUpdate)
        {
            // IMPORTANT: add logic to make sure that caller is allowed to register for the provided tags
            
            RegistrationDescription registration = null;
            switch (deviceUpdate.Platform)
            {
                case "mpns":
                    registration = new MpnsRegistrationDescription(deviceUpdate.Handle);
                    break;
                case "wns":
                    registration = new WindowsRegistrationDescription(deviceUpdate.Handle);
                    break;
                case "apns":
                    registration = new AppleRegistrationDescription(deviceUpdate.Handle);
                    break;
                case "gcm":
                    registration = new GcmRegistrationDescription(deviceUpdate.Handle);
                    break;
                default:
                    throw new HttpResponseException(HttpStatusCode.BadRequest);
            }

            registration.RegistrationId = id;
            registration.Tags = new HashSet<string>(deviceUpdate.Tags);

            try
            {
                await hub.CreateOrUpdateRegistrationAsync(registration);
            } catch (MessagingException e) {
                ReturnGoneIfHubResponseIsGone(e);
            }
        }

        // DELETE api/register/5
        public async void Delete(string id)
        {
            await hub.DeleteRegistrationAsync(id);
        }


        private static void ReturnGoneIfHubResponseIsGone(MessagingException e)
        {
            var webex = e.InnerException as WebException;
            if (webex.Status == WebExceptionStatus.ProtocolError)
            {
                var response = (HttpWebResponse)webex.Response;
                if (response.StatusCode == HttpStatusCode.Gone)
                    throw new HttpRequestException(HttpStatusCode.Gone.ToString());
            }
        }
    }

Observera att du i föregående kod måste lägga till logiken för att säkerställa att klienten som anropar slutpunkten har behörighet att registrera sig för de begärda taggarna. Dessutom kan din serverdel lägga till själva taggarna (till exempel en userid-tagg ).

Följande kodexempel visar hur du implementerar registreringsmetoden för en Windows Store-app från enheten med föregående slutpunkter:

class RegisterClient
    {
        private string POST_URL = "{your back-end endpoints}";

        private class DeviceRegistration
        {
            public string Platform { get; set; }
            public string Handle { get; set; }
            public string[] Tags { get; set; }
        }

        public async Task RegisterAsync(string handle, IEnumerable<string> tags)
        {
            var regId = await RetrieveRegistrationIdOrRequestNewOneAsync();

            var deviceRegistration = new DeviceRegistration
            {
                Platform = "wns",
                Handle = handle,
                Tags = tags.ToArray<string>()
            };

            var statusCode = await UpdateRegistrationAsync(regId, deviceRegistration);

            if (statusCode == HttpStatusCode.Gone)
            {
                // regId is expired, deleting from local storage & recreating
                var settings = ApplicationData.Current.LocalSettings.Values;
                settings.Remove("__NHRegistrationId");
                regId = await RetrieveRegistrationIdOrRequestNewOneAsync();
                statusCode = await UpdateRegistrationAsync(regId, deviceRegistration);
            }

            if (statusCode != HttpStatusCode.Accepted)
            {
                // log or throw
            }
        }

        private async Task<HttpStatusCode> UpdateRegistrationAsync(string regId, DeviceRegistration deviceRegistration)
        {
            using (var httpClient = new HttpClient())
            {
                var putUri = POST_URL + "/" + regId;
                var response = await httpClient.PutAsJsonAsync<DeviceRegistration>(putUri, deviceRegistration);
                return response.StatusCode;
            }
        }

        private async Task<string> RetrieveRegistrationIdOrRequestNewOneAsync()
        {
            var settings = ApplicationData.Current.LocalSettings.Values;
            if (!settings.ContainsKey("__NHRegistrationId"))
            {
                using (var httpClient = new HttpClient())
                {
                    var response = await httpClient.PostAsync(POST_URL, new StringContent(""));
                    if (response.IsSuccessStatusCode)
                    {
                        string regId = await response.Content.ReadAsStringAsync();
                        regId = regId.Substring(1, regId.Length - 2);
                        settings.Add("__NHRegistrationId", regId);
                    }
                    else
                    {
                        throw new Exception();
                    }
                }
            }
            return (string)settings["__NHRegistrationId"];

        }
    }

Lagra registrerings-ID:t i en serverdelsdatabas

Ibland vill program behålla registrerings-ID:n i appens serverdel i stället för i enhetens lokala lagring. Detta inträffar vanligtvis när appserverdelen redan har ett sätt att identifiera enheter (till exempel ett installationId) och ett sätt att lagra enhetsinformation på serverdelslagringen (till exempel när du migrerar från en anpassad push-lösning där PNS-referenser lagrades).

Ändra taggar från serverdelen

Om du vill ändra taggar från serverdelen måste du ha ett sätt för serverdelen att identifiera de registreringar som ska ändras. Detta görs vanligtvis med hjälp av en tagg.

Anta till exempel att det finns en musikapp där en användare lägger till ett nytt favoritband från webben, och serverdelen lägger till en tagg i användarens mobilregistreringar som ett resultat av detta. I det här fallet använder appen en tagg för att identifiera användaren och använder sedan taggen för att hämta de registreringar som ska uppdateras och uppdatera dem.

I följande kodexempel hämtas registreringarna och en ny tagg läggs till i dem.

var registrations = await hub.GetRegistrationsByTagAsync("{userId}", 10);
            foreach (var reg in registrations)
            {
                reg.Tags.Add("{newBand}");
                await hub.UpdateRegistrationAsync(reg);
            }

Observera att om du använder mallar i det här exemplet antar vi att du lägger till taggen på alla dina mallar.