Orientação de arquitetura das notificações push empresariais

Hoje em dia, as empresas estão gradualmente a avançar para a criação de aplicações móveis quer para os seus utilizadores finais (externos) quer para os funcionários (internos). Eles têm sistemas de back-end existentes, sejam mainframes ou alguns aplicativos LoB, que devem ser integrados à arquitetura de aplicativos móveis. Este guia fala sobre a melhor forma de fazer essa integração, recomendando possíveis soluções para cenários comuns.

Um requisito frequente é o envio de notificações push aos usuários por meio de seu aplicativo móvel quando ocorre um evento de interesse nos sistemas de back-end. Por exemplo, um cliente bancário que tenha o aplicativo bancário do banco em um iPhone quer ser notificado quando um débito é feito acima de um determinado valor da conta ou um cenário de intranet em que um funcionário do departamento financeiro que tem um aplicativo de aprovação de orçamento em um Windows Phone deseja ser notificado quando a solicitação de aprovação é recebida.

É provável que o processamento da conta bancária ou aprovação seja feito em algum sistema de back-end, que deve iniciar um push para o usuário. Pode haver vários desses sistemas de back-end, que devem construir o mesmo tipo de lógica para enviar por push quando um evento dispara uma notificação. A complexidade aqui reside na integração de vários sistemas de back-end juntamente com um único sistema push, onde os usuários finais podem ter se inscrito em notificações diferentes e pode até haver vários aplicativos móveis. Por exemplo, aplicativos móveis de intranet em que um aplicativo móvel pode querer receber notificações de vários desses sistemas de back-end. Os sistemas de back-end não sabem ou precisam saber de semântica/tecnologia push, então uma solução comum aqui tradicionalmente tem sido introduzir um componente, que sonda os sistemas de backend para quaisquer eventos de interesse e é responsável por enviar as mensagens push para o cliente.

Uma solução melhor é usar o modelo Azure Service Bus - Topic/Subscription, que reduz a complexidade enquanto torna a solução escalável.

Aqui está a arquitetura geral da solução (generalizada com vários aplicativos móveis, mas igualmente aplicável quando há apenas um aplicativo móvel):

Arquitetura

Diagram of the enterprise architecture showing the flow through Events, Subscriptions, and Push Messages.

A peça-chave neste diagrama de arquitetura é o Barramento de Serviço do Azure, que fornece um modelo de programação de tópicos/assinaturas (mais sobre ele em Programação Pub/Sub do Service Bus). O recetor, que neste caso, é o back-end móvel (normalmente o Serviço Móvel do Azure, que inicia um push para os aplicativos móveis) não recebe mensagens diretamente dos sistemas de back-end, mas em vez disso, uma camada de abstração intermediária fornecida pelo Barramento de Serviço do Azure, que permite que o back-end móvel receba mensagens de um ou mais sistemas de back-end. Um Tópico do Service Bus precisa ser criado para cada um dos sistemas de back-end, por exemplo, Conta, RH, Finanças, que é basicamente "tópicos" de interesse, que inicia mensagens a serem enviadas como notificação push. Os sistemas de back-end enviam mensagens para esses tópicos. Um back-end móvel pode assinar um ou mais desses tópicos criando uma assinatura do Service Bus. Ele permite que o back-end móvel receba uma notificação do sistema de back-end correspondente. O back-end móvel continua a ouvir mensagens em suas assinaturas e, assim que uma mensagem chega, ele volta e a envia como notificação para seu hub de notificação. Em seguida, os hubs de notificação eventualmente entregam a mensagem ao aplicativo móvel. Aqui está a lista de componentes-chave:

  1. Sistemas de back-end (LoB/sistemas legados)
    • Cria tópico do Service Bus
    • Envia Mensagem
  2. Back-end móvel
    • Cria Subscrição de Serviço
    • Recebe mensagem (do sistema de back-end)
    • Envia notificação aos clientes (através do Hub de Notificação do Azure)
  3. Aplicação móvel
    • Recebe e exibe notificação

Benefícios

  1. O desacoplamento entre o recetor (aplicativo/serviço móvel via Hub de Notificação) e o remetente (sistemas de back-end) permite que sistemas de back-end adicionais sejam integrados com o mínimo de alterações.
  2. Ele também cria o cenário de vários aplicativos móveis serem capazes de receber eventos de um ou mais sistemas de back-end.

Exemplo

Pré-requisitos

Conclua os tutoriais a seguir para se familiarizar com os conceitos, bem como as etapas comuns de criação e configuração:

  1. Programação de Pub/Sub do Service Bus - Este tutorial explica os detalhes de trabalhar com Tópicos/Assinaturas do Service Bus, como criar um namespace para conter tópicos/assinaturas, como enviar & receber mensagens deles.
  2. Hubs de Notificação - Tutorial Universal do Windows - Este tutorial explica como configurar um aplicativo da Windows Store e usar os Hubs de Notificação para registrar e receber notificações.

Código de exemplo

O código de exemplo completo está disponível em Exemplos do Hub de Notificação. Divide-se em três componentes:

  1. EnterprisePushBackendSystem

    a. Este projeto usa o pacote NuGet Azure.Messaging.ServiceBus e é baseado na programação Pub/Sub do Service Bus.

    b. Este aplicativo é um aplicativo de console C# simples para simular um sistema LoB, que inicia a mensagem a ser entregue ao aplicativo móvel.

    static async Task Main(string[] args)
    {
        string connectionString =
            ConfigurationManager.AppSettings.Get("Azure.ServiceBus.ConnectionString");
    
        // Create the topic
        await CreateTopicAsync(connectionString);
    
        // Send message
        await SendMessageAsync(connectionString);
    }
    

    c. CreateTopicAsync é usado para criar o tópico do Service Bus.

    public static async Task CreateTopicAsync(string connectionString)
    {
        // Create the topic if it does not exist already
        ServiceBusAdministrationClient client = new ServiceBusAdministrationClient(connectionString);
    
        if (!await client.TopicExistsAsync(topicName))
        {
            await client.CreateTopicAsync(topicName);
        }
    }
    

    d. SendMessageAsync é usado para enviar as mensagens para este tópico do Service Bus. Este código simplesmente envia um conjunto de mensagens aleatórias para o tópico periodicamente para o propósito do exemplo. Normalmente, há um sistema de back-end, que envia mensagens quando ocorre um evento.

    public static sync Task SendMessageAsync(string connectionString)
    {
        await using var client = new ServiceBusClient(connectionString);
        ServiceBusSender sender = client.CreateSender(topicName);
    
        // Sends random messages every 10 seconds to the topic
        string[] messages =
        {
            "Employee Id '{0}' has joined.",
            "Employee Id '{0}' has left.",
            "Employee Id '{0}' has switched to a different team."
        };
    
        while (true)
        {
            Random rnd = new Random();
            string employeeId = rnd.Next(10000, 99999).ToString();
            string notification = String.Format(messages[rnd.Next(0,messages.Length)], employeeId);
    
            // Send Notification
            ServiceBusMessage message = new ServiceBusMessage(notification);
            await sender.SendMessageAsync(message);
    
            Console.WriteLine("{0} Message sent - '{1}'", DateTime.Now, notification);
    
            System.Threading.Thread.Sleep(new TimeSpan(0, 0, 10));
        }
    }
    
  2. ReceiveAndSendNotification

    a. Este projeto usa os pacotes Azure.Messaging.ServiceBus e Microsoft.Web.WebJobs.Publish NuGet e é baseado na programação Pub/Sub do Service Bus.

    b. O aplicativo de console a seguir é executado como um WebJob do Azure, pois precisa ser executado continuamente para ouvir mensagens dos sistemas LoB/back-end. Esta aplicação faz parte do seu back-end móvel.

    static async Task Main(string[] args)
    {
        string connectionString =
                 ConfigurationManager.AppSettings.Get("Azure.ServiceBus.ConnectionString");
    
        // Create the subscription that receives messages
        await CreateSubscriptionAsync(connectionString);
    
        // Receive message
        await ReceiveMessageAndSendNotificationAsync(connectionString);
    }
    

    c. CreateSubscriptionAsync é usado para criar uma assinatura do Service Bus para o tópico em que o sistema de back-end envia mensagens. Dependendo do cenário de negócios, esse componente cria uma ou mais assinaturas para tópicos correspondentes (por exemplo, alguns podem estar recebendo mensagens do sistema de RH, alguns do sistema de finanças e assim por diante)

    static async Task CreateSubscriptionAsync(string connectionString)
    {
        // Create the subscription if it does not exist already
        ServiceBusAdministrationClient client = new ServiceBusAdministrationClient(connectionString);
    
        if (!await client.SubscriptionExistsAsync(topicName, subscriptionName))
        {
            await client.CreateSubscriptionAsync(topicName, subscriptionName);
        }
    }
    

    d. ReceiveMessageAndSendNotificationAsync é usado para ler a mensagem do tópico usando sua assinatura e, se a leitura for bem-sucedida, crie uma notificação (no cenário de exemplo, uma notificação do sistema nativa do Windows) para ser enviada ao aplicativo móvel usando os Hubs de Notificação do Azure.

    static async Task ReceiveMessageAndSendNotificationAsync(string connectionString)
    {
        // Initialize the Notification Hub
        string hubConnectionString = ConfigurationManager.AppSettings.Get
                ("Microsoft.NotificationHub.ConnectionString");
        hub = NotificationHubClient.CreateClientFromConnectionString
                (hubConnectionString, "enterprisepushservicehub");
    
        ServiceBusClient Client = new ServiceBusClient(connectionString);
        ServiceBusReceiver receiver = Client.CreateReceiver(topicName, subscriptionName);
    
        // Continuously process messages received from the subscription
        while (true)
        {
            ServiceBusReceivedMessage message = await receiver.ReceiveMessageAsync();
            var toastMessage = @"<toast><visual><binding template=""ToastText01""><text id=""1"">{messagepayload}</text></binding></visual></toast>";
    
            if (message != null)
            {
                try
                {
                    Console.WriteLine(message.MessageId);
                    Console.WriteLine(message.SequenceNumber);
                    string messageBody = message.Body.ToString();
                    Console.WriteLine("Body: " + messageBody + "\n");
    
                    toastMessage = toastMessage.Replace("{messagepayload}", messageBody);
                    SendNotificationAsync(toastMessage);
    
                    // Remove message from subscription
                    await receiver.CompleteMessageAsync(message);
                }
                catch (Exception)
                {
                    // Indicate a problem, unlock message in subscription
                    await receiver.AbandonMessageAsync(message);
                }
            }
        }
    }
    static async void SendNotificationAsync(string message)
    {
        await hub.SendWindowsNativeNotificationAsync(message);
    }
    

    e. Para publicar este aplicativo como um WebJob, clique com o botão direito do mouse na solução no Visual Studio e selecione Publicar como WebJob

    Screenshot of the right-click options being displayed with Publish as Azure WebJob outlined in red.

    f. Selecione seu perfil de publicação e crie um novo Site do Azure, se ele ainda não existir, que hospede esse WebJob e, uma vez que você tenha o Site, publique.

    Screenshot showing the workflow to create a site on Azure.

    Captura de ecrã da caixa de diálogo Publicar Web com a opção Web do Microsoft Azure selecionada, uma seta verde apontando para a caixa de diálogo Selecionar Web site Existente com a opção Novo delineada a vermelho e uma seta verde apontando para a caixa de diálogo Criar site no Microsoft Azure com as opções Nome do site e Criar delineadas a vermelho.

    g. Configure o trabalho para ser "Executar continuamente" para que, ao fazer logon no portal do Azure, você veja algo como o seguinte:

    Screenshot of the Azure Portal with the enterprise push backend webjobs displayed and the Name, Schedule, and Logs values outlined in red.

  3. EnterprisePushMobileApp

    a. Este aplicativo é um aplicativo da Windows Store, que recebe notificações do sistema do WebJob em execução como parte do back-end móvel e o exibe. Este código é baseado no tutorial Hubs de Notificação - Windows Universal.

    b. Verifique se seu aplicativo está habilitado para receber notificações do sistema.

    c. Verifique se o seguinte código de registro dos Hubs de Notificação está sendo chamado na inicialização do aplicativo (depois de substituir os HubName valores e DefaultListenSharedAccessSignature :

    private async void InitNotificationsAsync()
    {
        var channel = await PushNotificationChannelManager.CreatePushNotificationChannelForApplicationAsync();
    
        var hub = new NotificationHub("[HubName]", "[DefaultListenSharedAccessSignature]");
        var result = await hub.RegisterNativeAsync(channel.Uri);
    
        // Displays the registration ID so you know it was successful
        if (result.RegistrationId != null)
        {
            var dialog = new MessageDialog("Registration successful: " + result.RegistrationId);
            dialog.Commands.Add(new UICommand("OK"));
            await dialog.ShowAsync();
        }
    }
    

Executar o exemplo

  1. Certifique-se de que seu WebJob está sendo executado com êxito e agendado para ser executado continuamente.

  2. Execute o EnterprisePushMobileApp, que inicia o aplicativo da Windows Store.

  3. Execute o aplicativo de console EnterprisePushBackendSystem, que simula o back-end LoB e começa a enviar mensagens, e você verá notificações do sistema aparecendo como a seguinte imagem:

    Screenshot of a console running the Enterprise Push Backend System app and the message that is sent by the app.

  4. As mensagens foram originalmente enviadas para tópicos do Service Bus, que estava sendo monitorado por assinaturas do Service Bus em seu trabalho na Web. Assim que uma mensagem foi recebida, uma notificação foi criada e enviada para o aplicativo móvel. Você pode examinar os logs do WebJob para confirmar o processamento quando acessar o link Logs no portal do Azure para seu Web Job:

    Screenshot of the Continuous WebJob Details dialog box with the message that is sent outlined in red.