Registo a partir do seu Backend de Aplicação

Como mencionado nas secções anteriores, os dispositivos devem criar um ou mais registos num centro de notificação para receber notificações push. Uma forma de completar este registo é fazer com que os dispositivos móveis contactem diretamente o centro de notificação para especificar (ou atualizar) o seu cabo PNS e as suas etiquetas. Esta abordagem tem uma série de limitações e existem alguns cenários em que é aconselhável contactar a sua própria app backend quando um dispositivo atualiza o seu registo. O backend chama então o centro de notificação.

Quando se registar a partir do seu backend da sua aplicação

Existem dois cenários em que é aconselhável encaminhar os registos dos dispositivos através do seu fundo de aplicações.

As etiquetas devem ser seguras

Quando um dispositivo se regista diretamente com um centro de notificação, pode especificar qualquer etiqueta que pretenda. Isto não é um problema se as etiquetas são grupos de interesse público que qualquer dispositivo pode subscrever (por exemplo, feeds de notícias sobre equipas desportivas). No entanto, este pode ser um problema quando algumas tags estão disponíveis apenas para alguns utilizadores.

Para registar cada utilizador apenas nas etiquetas permitidas, deve encaminhar as operações de registo através do seu próprio backend de aplicações, que podem realizar a autenticação do utilizador e autorizar o registo das etiquetas requeridas.

O exemplo mais comum deste cenário é usar tags para representar iDs de utilizador. Neste caso, pretende-se evitar que os dispositivos se registem em etiquetas que representem outros utilizadores, uma vez que receberiam notificações desse outro utilizador.

As tags são modificadas pelo seu backend da aplicação

Registar-se no dispositivo é conveniente e permite-lhe configurar rapidamente notificações push e encaminhamento rico para grupos de interesse. No entanto, o registo do dispositivo não funciona muito bem se pretender alterar as etiquetas como resultado de eventos que ocorram noutros dispositivos.

Considere dois cenários: se as tags no telemóvel de Alice forem definidas como resultado de eventos que ocorrem no telemóvel de Alice, então é fácil para a app atualizar as tags no centro de notificação. Se, por outro lado, as tags tiverem de ser alteradas em resultado de eventos que ocorram noutros dispositivos (por exemplo, o portátil de Alice quando ligado a um website), então o dispositivo terá de esperar que a app volte a estar ativa para refletir as alterações no centro de notificação.

Um exemplo específico do cenário anterior é uma aplicação de música que inclui uma experiência web e uma aplicação móvel. Neste caso, um utilizador específico poderá seguir uma nova banda através do site, e pretender que o dispositivo comece a receber notificações sobre a nova banda o mais rapidamente possível. Outro exemplo é quando as etiquetas vêm de outras partes do seu backend (um CRM, por exemplo), que podem alterar o estado do utilizador de Silver para Gold. Esta alteração pode resultar na definição de uma nova etiqueta em todos os registos dos utilizadores.

Como registar-se a partir do backend

Ao registar um dispositivo, um centro de notificação deve distinguir entre diferentes dispositivos. Isto não pode ser conseguido apenas olhando para as pegas PNS, uma vez que são transitórias e não únicas. Para resolver este problema, os Centros de Notificação geram IDs de registo de longa duração que cada dispositivo deve armazenar localmente para poder consultar o seu próprio registo cada vez que atualiza o seu cabo, etiquetas ou modelo de PNS.

O seguinte número mostra o fluxo de registo das notificações nativas:

  1. No dispositivo, se não for armazenado nenhum id de registo localmente,

    1. Ligue para o aplicativo backend para obter identificação de registo.

    2. O backend da app chama os centros de notificação para criar um novo ID de registo e, em seguida, devolve o ID de volta ao dispositivo.

    3. Guarde o ID de registo no armazenamento local do dispositivo.

  2. No dispositivo, recupere o ID de registo do armazenamento local:

    1. Ligue para o backend da aplicação, fornecendo o ID de registo, o cabo PNS e as etiquetas.

    2. O backend da app cria ou atualiza o registo correspondente no centro de notificação.

    3. Se o backend da aplicação devolver o código de estado 410, deve ser criado um novo id de registo. Elimine o ID de registo do armazenamento local e reinicie a partir do passo 1.

Backend Registration

O fluxo para notificações de modelos é análogo. As únicas diferenças são as seguintes:

  1. Se um dispositivo utilizar vários modelos, então deve armazenar um ID de registo por modelo.

  2. Pode identificar os modelos utilizando a propriedade ModeloName do registo.

O seguinte código é um exemplo de pontos finais.

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

Note que no código anterior, deve adicionar a lógica para garantir que o cliente que liga para esse ponto final está autorizado a registar-se para as etiquetas solicitadas. Além disso, o seu backend pode adicionar as etiquetas em si (por exemplo, uma etiqueta userid ).

O seguinte exemplo de código mostra como implementar o método de registo de uma aplicação Windows Store, a partir do dispositivo, com os pontos finais anteriores:

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"];

        }
    }

Armazenar IDs de registo numa base de dados back-end

Por vezes, as aplicações pretendem manter os IDs de registo no backend da app em vez de no armazenamento local do dispositivo. Isto geralmente acontece quando o backend da aplicação já tem uma maneira de identificar dispositivos (por exemplo, umóide de instalação), e uma forma de armazenar informações do dispositivo no armazenamento de backend (por exemplo, quando migram de uma solução de push personalizado em que as pegas PNS foram armazenadas).

Como modificar tags a partir do backend

Se quiser modificar as etiquetas a partir do backend, deve ter uma maneira de identificar os registos que devem ser modificados. Isto é geralmente feito usando uma etiqueta.

Por exemplo, assuma que existe uma aplicação de música na qual um utilizador adiciona uma nova banda favorita da Web, e o backend adiciona uma etiqueta nas matrículas móveis do utilizador como resultado disso. Neste caso, a aplicação utiliza uma etiqueta para identificar o utilizador e, em seguida, utiliza essa etiqueta para recuperar os registos para ser atualizado e atualizá-los.

O seguinte exemplo de código recupera as inscrições e adiciona-lhes uma nova etiqueta.

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

Note que neste exemplo, se estiver a usar modelos, assumimos que está a adicionar a etiqueta em todos os seus modelos.