Tutorial: Atualizar estoque usando o portal do Azure e tópicos/assinaturas

O Barramento de Serviço do Azure é um serviço de mensagens na nuvem multilocatário que envia informações entre aplicativos e serviços. Operações assíncronas oferecem um sistema de mensagens agenciado e flexível, juntamente com recursos de mensagens PEPS (primeiro a entrar, primeiro a sair) e de publicação/assinatura. Para ter uma visão geral detalhada do Barramento de Serviço do Azure, consulte O que é o Barramento de Serviço?.

Este tutorial mostra como usar tópicos e assinaturas do Barramento de Serviço em um cenário de estoque de varejo com canais de publicação/assinatura usando o portal do Azure e .NET. Um exemplo desse cenário é uma atualização de sortimento de estoque para várias lojas de varejo. Nesse cenário, cada loja ou conjunto de lojas recebe mensagens que são destinadas para atualizar os respectivos sortimentos. Este tutorial mostra como implementar esse cenário usando assinaturas e filtros. Primeiro, você cria um tópico com três assinaturas, adiciona algumas regras e filtros e envia e recebe mensagens do tópico e das assinaturas.

Image showing a sender, a topic with three subscriptions, and three receivers.

Neste tutorial, você aprenderá a:

  • Criar um tópico do Barramento de Serviço e três assinaturas para esse tópico usando o portal do Azure
  • Adicionar filtros para assinaturas usando código .NET
  • Criar mensagens com conteúdo diferente
  • Enviar mensagens e verificar se chegaram nas assinaturas esperadas
  • Receber mensagens das assinaturas

Pré-requisitos

Para concluir este tutorial, verifique se você tem:

  • Assinatura do Azure. Para usar os serviços do Azure, incluindo o Barramento de Serviço do Azure, você precisa ter uma assinatura. Se você não tiver uma assinatura do Azure, poderá criar uma conta gratuita antes de começar.
  • Visual Studio 2019 ou posterior.

Tópicos e assinaturas do Barramento de Serviço

Cada assinatura a um tópico pode receber uma cópia de cada mensagem. Os tópicos tem total compatibilidade de protocolo e semântica com filas do Barramento de Serviço. Os tópicos do Barramento de Serviço dão suporte a uma ampla matriz de regras de seleção com condições de filtro, com ações opcionais que definem ou modificam as propriedades da mensagem. Cada vez que uma regra corresponde, é produzida uma mensagem. Para saber mais sobre regras, filtros e ações, consulte este link.

Criar um namespace no Portal do Azure

Para começar a usar as entidades de mensagens do Barramento de Serviço no Azure, primeiro é necessário criar um namespace com um nome exclusivo no Azure. Um namespace fornece um contêiner de escopo para recursos do Barramento de Serviço (filas, tópicos, etc.) dentro de seu aplicativo.

Para criar um namespace:

  1. Entre no portal do Azure.

  2. Navegue até a página Todos os serviços.

  3. Na barra de navegação à esquerda, selecione Integração na lista de categorias. Passe o mouse sobre Barramento de Serviço e, em seguida, selecione o botão + no bloco do Barramento de Serviço.

    Image showing selection of Create a resource, Integration, and then Service Bus in the menu.

  4. Na marca Informações Básicas da página Criar namespace, siga estas etapas:

    1. Em Assinatura, escolha uma assinatura do Azure na qual criar o namespace.

    2. Em Grupo de recursos, escolha um grupo de recursos existente no qual o namespace residirá ou então crie um novo.

    3. Insira um nome para o namespace. O nome do namespace deve estar de acordo com as convenções de nomenclatura abaixo:

      • O nome deve ser exclusivo em todo o Azure. O sistema imediatamente verifica para ver se o nome está disponível.
      • O nome deve ter no mínimo seis e no máximo 50 caracteres.
      • O campo pode conter apenas letras, números e hifens "-".
      • O nome precisa começar com uma letra e terminar com uma letra ou um número.
      • O nome não termina com “-sb“ nem “-mgmt“.
    4. Em Localização, escolha a região na qual o namespace deve ser hospedado.

    5. Selecione o Tipo de preço (Básico, Standard ou Premium) do namespace. Para esse início rápido, selecione Padrão.

      Importante

      Se você quiser usar tópicos e assinaturas, escolha Standard ou Premium. Não há suporte para os tópicos/assinaturas no tipo de preço básico.

      Se você selecionou o tipo de preço Premium, especifique o número de unidades do sistema de mensagens. A camada Premium fornece isolamento de recursos no nível de CPU e memória, de modo que cada carga de trabalho seja executada isoladamente. Esse contêiner de recursos é chamado de unidade do sistema de mensagens. Um namespace premium tem pelo menos uma unidade do sistema de mensagens. Você pode selecionar 1, 2, 4, 8 ou 16 unidades do sistema de mensagens para cada namespace Premium do Barramento de Serviço. Para saber mais, confira Sistema de Mensagens Premium do Barramento de Serviço.

    6. Selecione Revisar + criar na parte inferior da página.

      Image showing the Create a namespace page

    7. Na páginaRevisar + criar,revise as configurações e selecioneCriar.

  5. Depois que a implantação do recurso for bem-sucedida, selecione Ir para o recurso na página de implantação.

    Image showing the deployment succeeded page with the Go to resource link.

  6. Você verá a home page do namespace do barramento de serviço.

    Image showing the home page of the Service Bus namespace created.

Obter a cadeia de conexão para o namespace (portal do Azure)

Criar um namespace gera automaticamente uma política inicial de SAS (Assinatura de Acesso Compartilhado) com chaves primárias e secundárias e cadeias de conexão primárias e secundárias que concedem controle total sobre todos os aspectos do namespace. Consulte Autenticação e autorização do Barramento de Serviço para obter informações sobre como criar regras com direitos mais restritos para remetentes e destinatários regulares.

Um cliente pode usar a cadeia de conexão para se conectar ao namespace do Barramento de Serviço. Para copiar a cadeia de conexão primária para seu namespace, siga estas etapas:

  1. Na página Namespace do Barramento de Serviço, selecione Políticas de acesso compartilhado no menu à esquerda.

  2. Na página Políticas de acesso compartilhado, selecione RootManageSharedAccessKey.

  3. Na janela Política: RootManageSharedAccessKey, selecione o botão Copiar próximo à Cadeia de Conexão Primária para copiar a cadeia de conexão na área de transferência para uso posterior. Cole esse valor no Bloco de notas ou em outro local temporário.

    Screenshot shows an S A S policy called RootManageSharedAccessKey, which includes keys and connection strings.

    Você pode usar essa página para copiar a chave primária, a chave secundária, a cadeia de conexão primária e a cadeia de conexão secundária.

Criar um tópico usando o portal do Azure

  1. Na página Namespace de Barramento de Serviço, selecione Tópicos no menu à esquerda.

  2. Selecione + Tópico na barra de ferramentas.

  3. Insira um nome para o tópico. Deixe as outras opções com os valores padrão.

  4. Selecione Criar.

    Screenshot of the Create topic page.

Criar duas assinaturas do tópico

  1. Selecione o tópico que você criou na seção anterior.

    Screenshot of the Topics page with your topic selected.

  2. Na página Tópico de Barramento de Serviço, selecione Assinaturas no menu à esquerda e em seguida, selecione + Assinatura na barra de ferramentas.

    Screenshot of the Subscriptions page with the Add subscription button selected.

  3. Na página Criar assinatura, siga estas etapas:

    1. Insira S1 em Nome da assinatura.

    2. Em seguida, selecione Criar para criar a assinatura.

      Screenshot of the Create subscription page.

  4. Repita a etapa anterior mais duas vezes, criando assinaturas nomeadas como S2 e S3.

Criar regras de filtro nas assinaturas

Depois que o namespace e os tópicos/as assinaturas forem provisionados e você tiver a cadeia de conexão para o namespace, poderá criar regras de filtro nas assinaturas e depois enviar e receber mensagens. É possível examinar o código nesta pasta de exemplo do GitHub.

Enviar e receber mensagens

Para executar o código, siga estas etapas:

  1. Em um prompt de comando ou no prompt do PowerShell, clone o repositório GitHub do Barramento de Serviço, emitindo o comando a seguir:

    git clone https://github.com/Azure/azure-service-bus.git
    
  2. Navegue até a pasta de exemplo azure-service-bus\samples\DotNet\Azure.Messaging.ServiceBus\BasicSendReceiveTutorialWithFilters.

  3. Obtenha a cadeia de conexão copiada para o Bloco de notas anteriormente neste tutorial. Também será necessário o nome do tópico que você criou na seção anterior.

  4. No prompt de comando, digite o comando a seguir:

    dotnet build
    
  5. Navegue até a pasta BasicSendReceiveTutorialWithFilters\bin\Debug\netcoreapp3.1.

  6. Digite o comando a seguir para executar o programa. Certifique-se de substituir myConnectionString pelo valor obtido anteriormente e myTopicName pelo nome do tópico que você criou:

    dotnet --roll-forward Major BasicSendReceiveTutorialWithFilters.dll -ConnectionString "myConnectionString" -TopicName "myTopicName"
    
  7. Siga as instruções no console para selecionar a criação do filtro primeiro. Parte da criação do filtro é remover os filtros padrão. Ao utilizar o PowerShell ou a CLI, você não precisa remover o filtro padrão mas, se fizer isso no código, precisará removê-los. Os comandos dos consoles 1 e 3 ajudam a gerenciar os filtros nas assinaturas criadas anteriormente:

    • Execute 1: para remover os filtros padrão.

    • Execute 2: para adicionar seus próprios filtros.

    • Execute 3: Ignore esta etapa para o tutorial. Opcionalmente, fazer isso remove seus filtros. Isso não vai recriar os filtros padrão.

      Showing output of 2

  8. Após a criação do filtro, será possível enviar mensagens. Pressione 4 e observe 10 mensagens sendo enviadas para o tópico:

    Send output

  9. Pressione 5 e observe as mensagens sendo recebidas. Se você não recebeu 10 mensagens de volta, pressione "m" para exibir o menu e pressione 5 novamente.

    Receive output

Limpar os recursos

Execute estas etapas para limpar os recursos quando eles deixarem de ser necessários.

  1. Navegue até o namespace no portal do Azure.
  2. Na página Namespace do Barramento de Serviço, selecione Excluir na barra de comandos para excluir o namespace e os recursos (filas, tópicos e assinaturas) nele.

Entender o código de exemplo

Esta seção contém mais detalhes sobre o que o código de exemplo faz.

Obter cadeia de conexão e tópico

Primeiro, o código declara um conjunto de variáveis, que conduz a execução restante do programa.

string ServiceBusConnectionString;
string TopicName;

static string[] Subscriptions = { "S1", "S2", "S3" };
static IDictionary<string, string[]> SubscriptionFilters = new Dictionary<string, string[]> {
    { "S1", new[] { "StoreId IN('Store1', 'Store2', 'Store3')", "StoreId = 'Store4'"} },
    { "S2", new[] { "sys.To IN ('Store5','Store6','Store7') OR StoreId = 'Store8'" } },
    { "S3", new[] { "sys.To NOT IN ('Store1','Store2','Store3','Store4','Store5','Store6','Store7','Store8') OR StoreId NOT IN ('Store1','Store2','Store3','Store4','Store5','Store6','Store7','Store8')" } }
};
// You can have only have one action per rule and this sample code supports only one action for the first filter, which is used to create the first rule. 
static IDictionary<string, string> SubscriptionAction = new Dictionary<string, string> {
    { "S1", "" },
    { "S2", "" },
    { "S3", "SET sys.Label = 'SalesEvent'"  }
};
static string[] Store = { "Store1", "Store2", "Store3", "Store4", "Store5", "Store6", "Store7", "Store8", "Store9", "Store10" };
static string SysField = "sys.To";
static string CustomField = "StoreId";
static int NrOfMessagesPerStore = 1; // Send at least 1.

A cadeia de conexão e o nome do tópico são passados por meio dos parâmetros da linha de comando, conforme mostrado e, em seguida, são lidos no método Main():

static void Main(string[] args)
{
    string ServiceBusConnectionString = "";
    string TopicName = "";

    for (int i = 0; i < args.Length; i++)
    {
        if (args[i] == "-ConnectionString")
        {
            Console.WriteLine($"ConnectionString: {args[i + 1]}");
            ServiceBusConnectionString = args[i + 1]; // Alternatively enter your connection string here.
        }
        else if (args[i] == "-TopicName")
        {
            Console.WriteLine($"TopicName: {args[i + 1]}");
            TopicName = args[i + 1]; // Alternatively enter your queue name here.
        }
    }

    if (ServiceBusConnectionString != "" && TopicName != "")
    {
        Program P = StartProgram(ServiceBusConnectionString, TopicName);
        P.PresentMenu().GetAwaiter().GetResult();
    }
    else
    {
        Console.WriteLine("Specify -Connectionstring and -TopicName to execute the example.");
        Console.ReadKey();
    }
}

Remover filtros padrão

Quando você cria uma assinatura, o Barramento de Serviço cria um filtro padrão por assinatura. Este filtro permite receber todas as mensagens enviadas para o tópico. Se você quiser usar filtros personalizados, poderá remover o filtro padrão, conforme mostrado no código a seguir:

private async Task RemoveDefaultFilters()
{
    Console.WriteLine($"Starting to remove default filters.");

    try
    {
        var client = new ServiceBusAdministrationClient(ServiceBusConnectionString);
        foreach (var subscription in Subscriptions)
        {
            await client.DeleteRuleAsync(TopicName, subscription, CreateRuleOptions.DefaultRuleName);
            Console.WriteLine($"Default filter for {subscription} has been removed.");
        }

        Console.WriteLine("All default Rules have been removed.\n");
    }
    catch (Exception ex)
    {
        Console.WriteLine(ex.ToString());
    }

    await PresentMenu();
}

Criar filtros

O código a seguir inclui os filtros personalizados definidos neste tutorial:

private async Task CreateCustomFilters()
{
    try
    {
        for (int i = 0; i < Subscriptions.Length; i++)
        {
            var client = new ServiceBusAdministrationClient(ServiceBusConnectionString);
            string[] filters = SubscriptionFilters[Subscriptions[i]];
            if (filters[0] != "")
            {
                int count = 0;
                foreach (var myFilter in filters)
                {
                    count++;

                    string action = SubscriptionAction[Subscriptions[i]];
                    if (action != "")
                    {
                        await client.CreateRuleAsync(TopicName, Subscriptions[i], new CreateRuleOptions
                        {
                            Filter = new SqlRuleFilter(myFilter),
                            Action = new SqlRuleAction(action),
                            Name = $"MyRule{count}"
                        });
                    }
                    else
                    {
                        await client.CreateRuleAsync(TopicName, Subscriptions[i], new CreateRuleOptions
                        {
                            Filter = new SqlRuleFilter(myFilter),
                            Name = $"MyRule{count}"
                        });
                    }
                }
            }

            Console.WriteLine($"Filters and actions for {Subscriptions[i]} have been created.");
        }

        Console.WriteLine("All filters and actions have been created.\n");
    }
    catch (Exception ex)
    {
        Console.WriteLine(ex.ToString());
    }

    await PresentMenu();
}

Remover os filtros personalizados criados

Se você quiser remover todos os filtros da assinatura, o código a seguir mostra como fazer isso:

private async Task CleanUpCustomFilters()
{
    foreach (var subscription in Subscriptions)
    {
        try
        {
            var client = new ServiceBusAdministrationClient(ServiceBusConnectionString);
            IAsyncEnumerator<RuleProperties> rules = client.GetRulesAsync(TopicName, subscription).GetAsyncEnumerator();
            while (await rules.MoveNextAsync())
            {
                await client.DeleteRuleAsync(TopicName, subscription, rules.Current.Name);
                Console.WriteLine($"Rule {rules.Current.Name} has been removed.");
            }
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex.ToString());
        }
    }
    Console.WriteLine("All default filters have been removed.\n");

    await PresentMenu();
}

Enviar mensagens

Enviar mensagens para um tópico é semelhante ao envio de mensagens para uma fila. Este exemplo mostra como enviar mensagens usando uma lista de tarefas e um processamento assíncrono:

public async Task SendMessages()
{
    try
    {
        await using var client = new ServiceBusClient(ServiceBusConnectionString);
        var taskList = new List<Task>();
        for (int i = 0; i < Store.Length; i++)
        {
            taskList.Add(SendItems(client, Store[i]));
        }

        await Task.WhenAll(taskList);
    }
    catch (Exception ex)
    {
        Console.WriteLine(ex.ToString());
    }
    Console.WriteLine("\nAll messages sent.\n");
}

private async Task SendItems(ServiceBusClient client, string store)
{
    // create the sender
    ServiceBusSender tc = client.CreateSender(TopicName);

    for (int i = 0; i < NrOfMessagesPerStore; i++)
    {
        Random r = new Random();
        Item item = new Item(r.Next(5), r.Next(5), r.Next(5));

        // Note the extension class which is serializing an deserializing messages
        ServiceBusMessage message = item.AsMessage();
        message.To = store;
        message.ApplicationProperties.Add("StoreId", store);
        message.ApplicationProperties.Add("Price", item.GetPrice().ToString());
        message.ApplicationProperties.Add("Color", item.GetColor());
        message.ApplicationProperties.Add("Category", item.GetItemCategory());

        await tc.SendMessageAsync(message);
        Console.WriteLine($"Sent item to Store {store}. Price={item.GetPrice()}, Color={item.GetColor()}, Category={item.GetItemCategory()}"); ;
    }
}

Receber mensagens

As mensagens são recebidas novamente por meio de uma lista de tarefas e o código usa envio em lote. Você pode enviar e receber usando envio em lote, mas este exemplo mostra apenas como receber em lote. Na verdado, você não sairia do loop, mas continuaria no loop e definiria um período maior, como um minuto. A chamada de recebimento para o agente permanece aberta durante esse período e, se mensagens chegarem, serão retornadas imediatamente e uma nova chamada de recebimento será emitida. Esse conceito é chamado de sondagem longa. Usar a bomba de recebimento, que você pode ver no guia de início rápido e em vários outros exemplos no repositório, é uma opção mais típica.

public async Task Receive()
{
    var taskList = new List<Task>();
    for (var i = 0; i < Subscriptions.Length; i++)
    {
        taskList.Add(this.ReceiveMessages(Subscriptions[i]));
    }

    await Task.WhenAll(taskList);
}

private async Task ReceiveMessages(string subscription)
{
    await using var client = new ServiceBusClient(ServiceBusConnectionString);
    ServiceBusReceiver receiver = client.CreateReceiver(TopicName, subscription);

    // In reality you would not break out of the loop like in this example but would keep looping. The receiver keeps the connection open
    // to the broker for the specified amount of seconds and the broker returns messages as soon as they arrive. The client then initiates
    // a new connection. So in reality you would not want to break out of the loop. 
    // Also note that the code shows how to batch receive, which you would do for performance reasons. For convenience you can also always
    // use the regular receive pump which we show in our Quick Start and in other GitHub samples.
    while (true)
    {
        try
        {
            //IList<Message> messages = await receiver.ReceiveAsync(10, TimeSpan.FromSeconds(2));
            // Note the extension class which is serializing an deserializing messages and testing messages is null or 0.
            // If you think you did not receive all messages, just press M and receive again via the menu.
            IReadOnlyList<ServiceBusReceivedMessage> messages = await receiver.ReceiveMessagesAsync(maxMessages: 100);

            if (messages.Any())
            {
                foreach (ServiceBusReceivedMessage message in messages)
                {
                    lock (Console.Out)
                    {
                        Item item = message.As<Item>();
                        IReadOnlyDictionary<string, object> myApplicationProperties = message.ApplicationProperties;
                        Console.WriteLine($"StoreId={myApplicationProperties["StoreId"]}");
                        if (message.Subject != null)
                        {
                            Console.WriteLine($"Subject={message.Subject}");
                        }
                        Console.WriteLine(
                            $"Item data: Price={item.GetPrice()}, Color={item.GetColor()}, Category={item.GetItemCategory()}");
                    }

                    await receiver.CompleteMessageAsync(message);
                }
            }
            else
            {
                break;
            }
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex.ToString());
        }
    }
}

Observação

É possível gerenciar os recursos do Barramento de Serviço com o Gerenciador de Barramento de Serviço. O Gerenciador de Barramento de Serviço permite que usuários se conectem a um namespace de serviço do Barramento de Serviço e administrem entidades de mensagens de uma maneira fácil. A ferramenta fornece recursos avançados, como a funcionalidade de importação/exportação ou a capacidade de testar tópicos, filas, assinaturas, serviços de retransmissão, hubs de notificação e hubs de eventos.

Próximas etapas

Neste tutorial, você provisionou recursos usando o portal do Azure e, em seguida, enviou e recebeu mensagens de um tópico do Barramento de Serviço e as respectivas assinaturas. Você aprendeu a:

  • Criar um tópico de Barramento de Serviço e uma ou mais assinaturas para esse tópico usando o portal do Azure
  • Adicionar filtros de tópicos usando código .NET
  • Criar duas mensagens com conteúdo diferente
  • Enviar as mensagens e verificar se chegaram nas assinaturas esperadas
  • Receber mensagens das assinaturas

Para obter mais exemplos de envio e recebimento de mensagens, comece com os Exemplos de Barramento de Serviço no GitHub.

Avance para o próximo tutorial para saber mais sobre como usar os recursos de publicação/assinatura do Barramento de Serviço.