Share via


Tutorial: atualizar inventário utilizando o portal do Azure e tópicos/subscrições

O Azure Service Bus é um serviço de mensagens na cloud multi-inquilino que envia informações entre aplicações e serviços. As operações assíncronas permitem o envio flexível de mensagens mediadas, juntamente com mensagens FIFO (first in, first out) e funcionalidades de publicação/subscrição. Para obter uma visão geral detalhada do Barramento de Serviço do Azure, consulte O que é o Service Bus?.

Este tutorial mostra como utilizar tópicos e subscrições do Service Bus num cenário de inventário de comércio a retalho, com canais de publicação/subscrição utilizando o portal do Azure e .NET. Um exemplo deste cenário é uma atualização da variedade de inventário para várias lojas de comércio a retalho. Neste cenário, cada loja ou grupo de lojas recebe mensagens dirigidas a elas para atualizar a respetiva variedade. Este tutorial mostra como implementar este cenário com subscrições e filtros. Primeiro, você cria um tópico com três assinaturas, adiciona algumas regras e filtros e, em seguida, envia e recebe mensagens do tópico e das assinaturas.

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

Neste tutorial, irá aprender a:

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

Pré-requisitos

Para concluir este tutorial, confirme que tem:

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

Tópicos e subscrições do Service Bus

Cada subscrição de um tópico pode receber uma cópia de cada mensagem. Os tópicos são totalmente compatíveis no que diz respeito a protocolo e semântica com as filas do Service Bus. Os tópicos do Service Bus suportam uma vasta gama de regras de seleção com condições de filtro, com ações opcionais que definem ou modificam propriedades de mensagem. Sempre que uma regra tem correspondência, é criada uma mensagem. Para saber mais sobre regras, filtros e ações, clique nesta hiperligação.

Criar um espaço de nomes no portal do Azure

Para começar a utilizar as entidades de mensagens do Service Bus no Azure, tem de, primeiro, criar um espaço de nomes que seja exclusivo em todo o Azure. Um namespace fornece um contêiner de escopo para recursos do Service Bus (filas, tópicos, etc.) em seu aplicativo.

Para criar um espaço de nomes:

  1. Inicie sessão 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 o Service Bus e selecione + o botão no bloco do Service Bus.

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

  4. Na marca Basics da página Criar namespace, siga estas etapas:

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

    2. Para Grupo de recursos, escolha um grupo de recursos existente no qual o namespace viverá ou crie um novo.

    3. Insira um nome para o namespace. O nome do namespace deve aderir às seguintes convenções de nomenclatura:

      • O nome deve ser exclusivo no Azure. O sistema verifica imediatamente a disponibilidade do nome.
      • O comprimento do nome é de pelo menos 6 e no máximo 50 caracteres.
      • O nome pode conter apenas letras, números hífenes "-".
      • O nome deve começar com uma letra e terminar com uma letra ou número.
      • O nome não termina com "-sb" ou "-mgmt".
    4. Em Local, escolha a região na qual seu namespace deve ser hospedado.

    5. Em Nível de preço, selecione o nível de preço (Básico, Standard ou Premium) para o namespace. Para este 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 tópicos/assinaturas no nível de preço Básico.

      Se você selecionou o nível de preço Premium, especifique o número de unidades de mensagens. A camada premium fornece isolamento de recursos no nível de CPU e memória para que cada carga de trabalho seja executada isoladamente. Este contentor de recursos é designado por unidade de mensagens. Um namespace premium tem pelo menos uma unidade de mensagens. Você pode selecionar 1, 2, 4, 8 ou 16 unidades de mensagens para cada namespace Premium do Service Bus. Para obter mais informações, consulte Mensagens Premium do Service Bus.

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

      Image showing the Create a namespace page

    7. Na página Rever + criar, reveja as definições e selecione Criar.

  5. Quando 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ê vê a home page do namespace do barramento de serviço.

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

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

A criação de um novo namespace gera automaticamente uma política inicial de Assinatura de Acesso Compartilhado (SAS) com chaves primárias e secundárias e cadeias de conexão primárias e secundárias que concedem controle total sobre todos os aspetos do namespace. Consulte Autenticação e autorização do Service Bus 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 Service Bus. Para copiar a cadeia de conexão primária para seu namespace, execute estas etapas:

  1. Na página Namespace do Service Bus, selecione Políticas de acesso compartilhado no menu à esquerda.

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

  3. Na janela Policy: RootManageSharedAccessKey, selecione o botão de cópia ao lado de Cadeia de conexão primária, para copiar a cadeia de conexão para a área de transferência para uso posterior. Cole este valor no Bloco de Notas ou noutra localização temporária.

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

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

Criar um tópico com o portal do Azure

  1. Na página Namespace do Service Bus, 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 predefinidos.

  4. Selecione Criar.

    Screenshot of the Create topic page.

Criar subscrições para o 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 do Service Bus, selecione Assinaturas no menu esquerdo e selecione + Assinatura na barra de ferramentas.

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

  3. Na página Criar subscrição, siga estes passos:

    1. Digite S1 para o nome da assinatura.

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

      Screenshot of the Create subscription page.

  4. Repita a etapa anterior duas vezes para criar assinaturas chamadas S2 e S3.

Criar regras de filtro nas subscrições

Depois que o namespace e o tópico/assinaturas forem provisionados e você tiver a cadeia de conexão com o namespace, estará pronto para criar regras de filtro nas assinaturas e, em seguida, enviar e receber mensagens. Pode examinar o código nesta pasta de exemplo do GitHub.

Enviar e receber mensagens

Para executar o código, siga estes passos:

  1. Numa linha de comandos ou na linha de comandos do PowerShell, clone o repositório do GitHub do Service Bus indicando o seguinte comando:

    git clone https://github.com/Azure/azure-service-bus.git
    
  2. Navegue para 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 necessita do nome do tópico criado na secção anterior.

  4. Na linha de comandos, escreva o seguinte comando:

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

  6. Escreva o seguinte comando para executar o programa. Não se esqueça de substituir myConnectionString pelo valor obtido anteriormente e myTopicName pelo nome do tópico que criou:

    dotnet --roll-forward Major BasicSendReceiveTutorialWithFilters.dll -ConnectionString "myConnectionString" -TopicName "myTopicName"
    
  7. Siga as instruções na consola para selecionar a criação do filtro primeiro. Parte da criação de filtros consiste na remoção dos filtros predefinidos. Quando você usa o PowerShell ou a CLI, não precisa remover o filtro padrão, mas se você fizer isso no código, deverá removê-los. Os comandos 1 e 3 da consola ajudam a gerir os filtros nas subscrições criadas anteriormente:

    • Execute 1: para remover os filtros predefinidos.

    • Execute 2: para adicionar os seus filtros.

    • Executar 3: Ignore esta etapa para o tutorial. Esta opção opcionalmente remove os seus próprios filtros. Ele não recriará os filtros padrão.

      Showing output of 2

  8. Depois da criação do filtro, pode enviar mensagens. Prima 4 e observe o envio de 10 mensagens para o tópico:

    Send output

  9. Prima 5 e observe as mensagens a serem recebidas. Se você não recebeu 10 mensagens de volta, pressione "m" para exibir o menu e, em seguida, pressione 5 novamente.

    Receive output

Clean up resources (Limpar recursos)

Quando não for mais necessário, siga estas etapas para limpar recursos.

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

Compreender o código de exemplo

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

Obter a cadeia de ligação e o tópico

Primeiro, o código declara um conjunto de variáveis, que aciona 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 ligação e o nome do tópico são transmitidos através dos parâmetros da linha de comandos como mostrado e 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 predefinidos

Quando cria uma subscrição, o Service Bus cria um filtro predefinido por subscrição. Este tópico permite a receção de cada mensagem enviada para o tópico. Se pretender utilizar filtros personalizados, poderá remover o filtro predefinido, como mostrado no código seguinte:

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 seguinte adiciona 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 criados personalizados

Se pretender remover todos os filtros na sua subscrição, o código seguinte mostrará como fazê-lo:

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

O envio de mensagens para um tópico é semelhante ao envio de mensagens para uma fila. Este exemplo mostra como enviar mensagens, utilizando uma lista de tarefas e 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 novamente recebidas através de uma lista de tarefas e o código utiliza a criação de lotes. Pode enviar e receber utilizando a criação de lotes, mas este exemplo só mostra como receber lotes. Na realidade, você não sairia do loop, mas continuaria fazendo looping e definiria um período de tempo maior, como um minuto. A chamada de recebimento para o corretor é mantida aberta por esse período de tempo e, se as mensagens chegarem, elas serão retornadas imediatamente e uma nova chamada de recebimento será emitida. Este conceito é denominado consulta longa. Usar a bomba de receção, que você pode ver no início rápido, e em várias outras amostras 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());
        }
    }
}

Nota

Você pode gerenciar recursos do Service Bus com o Service Bus Explorer. O Service Bus Explorer permite que os usuários se conectem a um namespace do Service Bus e administrem entidades de mensagens de maneira fácil. A ferramenta fornece recursos avançados, como 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óximos passos

Neste tutorial, aprovisionou recursos utilizando o portal do Azure e enviou e recebeu mensagens de um tópico do Service Bus e respetivas subscrições. Aprendeu a:

  • Criar um tópico e uma ou mais subscrições do Service Bus para esse tópico com o portal do Azure
  • Adicionar filtros de tópico com o código .NET
  • Criar duas mensagens com conteúdo diferente
  • Enviar as mensagens e verificar que chegaram nas subscrições previstas
  • Receber mensagens das subscrições

Para ver mais exemplos sobre o envio e receção de mensagens, comece com os exemplos do Service Bus do GitHub.

Avance para o próximo tutorial para saber mais sobre a utilização de capacidades de publicação/subscrição do Service Bus.