Exercício – enviar e receber mensagens usando uma fila

Concluído

Você optou por usar uma fila do Barramento de Serviço para gerenciar mensagens sobre vendas individuais entre o aplicativo móvel, que a sua equipe de vendas usa, e o serviço Web hospedado no Azure, que armazenará os detalhes de cada venda em uma instância do Banco de Dados SQL do Azure.

No exercício anterior, você implementou os objetos necessários na sua assinatura do Azure. Agora, convém escrever um código que envie mensagens para essa fila e recupere mensagens.

Nesta unidade, você criará dois aplicativos de console: um que coloca mensagens em uma fila do Barramento de Serviço e um que recupera mensagens de uma fila do Barramento de Serviço. Os aplicativos fazem parte de uma única solução .NET Core.

Obter a cadeia de conexão para o namespace do Barramento de Serviço

Você precisa configurar duas informações nos seus dois aplicativos de console para acessar o namespace do Barramento de Serviço e usar a fila dentro desse namespace:

  • Ponto de extremidade do namespace
  • Chave de acesso compartilhada para autenticação

Você pode obter esses valores da cadeia de conexão.

  1. No Azure Cloud Shell à direita, execute o seguinte comando, substituindo <namespace-name> pelo namespace do Barramento de Serviço que você criou no exercício anterior.

    az servicebus namespace authorization-rule keys list \
        --resource-group <rgn>[sandbox resource group name]</rgn> \
        --name RootManageSharedAccessKey \
        --query primaryConnectionString \
        --output tsv \
        --namespace-name <namespace-name>
    

    A última linha na resposta é a cadeia de conexão, que contém o ponto de extremidade do namespace e a chave de acesso compartilhado. Ela deve ser parecida com o seguinte exemplo:

    Endpoint=sb://example.servicebus.windows.net/;SharedAccessKeyName=RootManageSharedAccessKey;SharedAccessKey=AbCdEfGhIjKlMnOpQrStUvWxYz==
    
  2. Copie a cadeia de conexão do Cloud Shell. Você precisará dessa cadeia de conexão várias vezes ao longo do módulo, portanto, salve-a em algum lugar prático.

Clonar e abrir o aplicativo inicial

Observação

Para simplificar, as tarefas a seguir instruirão você a embutir a cadeia de conexão em código no arquivo Program.cs de ambos os aplicativos de console. Em um aplicativo de produção, você deve usar um arquivo de configuração ou o Azure Key Vault para armazenar a cadeia de conexão.

  1. Execute o comando a seguir no Cloud Shell para clonar a solução de projeto Git:

    cd ~
    git clone https://github.com/MicrosoftDocs/mslearn-connect-services-together.git
    
  2. Execute o comando a seguir para acessar a pasta de início no projeto clonado e abrir o editor do Cloud Shell:

    cd ~/mslearn-connect-services-together/implement-message-workflows-with-service-bus/src/start
    code .
    

Escrever código para enviar uma mensagem para uma fila

  1. No editor do Cloud Shell, abra privatemessagesender/Program.cs e localize a linha de código a seguir:

    const string ServiceBusConnectionString = "";
    

    Cole a cadeia de conexão entre as aspas.

  2. Se você usou um nome diferente de salesmessages como nome da fila, atualize o valor da propriedade QueueName no código:

    const string QueueName = "salesmessages";
    
  3. Para concluir o componente que envia mensagens sobre vendas, você precisa adicionar um operador await para suspender a avaliação do método assíncrono até que a operação assíncrona seja concluída. Encontre o método SendSalesMessageAsync(). Nesse método, localize a seguinte linha de código:

    // Create a Service Bus client here
    

    Substitua essa linha de código pelo código a seguir:

    // By leveraging "await using", the DisposeAsync method will be called automatically once the client variable goes out of scope. 
    // In more realistic scenarios, you would want to store off a class reference to the client (rather than a local variable) so that it can be used throughout your program.
    
    await using var client = new ServiceBusClient(ServiceBusConnectionString);
    
  4. Dentro do método SendSalesMessageAsync(), localize a seguinte linha de código:

    // Create a sender here
    

    Substitua este comentário pelo código a seguir:

    await using ServiceBusSender sender = client.CreateSender(QueueName);
    
  5. No bloco try...catch, localize a seguinte linha de código:

    // Create and send a message here
    

    Substitua essa linha de código pelas a seguir:

    string messageBody = $"$10,000 order for bicycle parts from retailer Adventure Works.";
    var message = new ServiceBusMessage(messageBody);
    
  6. Insira o código a seguir em uma nova linha diretamente abaixo do que você acabou de adicionar para exibir a mensagem no console:

    Console.WriteLine($"Sending message: {messageBody}");
    
  7. Insira o código a seguir na próxima linha:

    await sender.SendMessageAsync(message);
    
  8. Para descartar objetos de remetente e cliente, próximo ao final do arquivo, localize o seguinte comentário:

    // Close the connection to the sender here
    

    Substitua essa linha pelo seguinte código:

    finally
    {
        // Calling DisposeAsync on client types is required to ensure that network
        // resources and other unmanaged objects are properly cleaned up.
        await sender.DisposeAsync();
        await client.DisposeAsync();
    }
    
  9. Verifique se o seu código final para privatemessagesender/Program.cs tem a seguinte aparência:

    using System;
    using System.Text;
    using System.Threading.Tasks;
    using Azure.Messaging.ServiceBus;
    
    namespace privatemessagesender
    {
        class Program
        {
            const string ServiceBusConnectionString = "Endpoint=sb://example.servicebus.windows.net/;SharedAccessKeyName=RootManageSharedAccessKey;SharedAccessKey=AbCdEfGhIjKlMnOpQrStUvWxYz==";
            const string QueueName = "salesmessages";
    
            static void Main(string[] args)
            {
                Console.WriteLine("Sending a message to the Sales Messages queue...");
                SendSalesMessageAsync().GetAwaiter().GetResult();
                Console.WriteLine("Message was sent successfully.");
            }
    
            static async Task SendSalesMessageAsync()
            {
                await using var client = new ServiceBusClient(ServiceBusConnectionString);
    
                await using ServiceBusSender sender = client.CreateSender(QueueName);
                try
                {
                    string messageBody = $"$10,000 order for bicycle parts from retailer Adventure Works.";
                    var message = new ServiceBusMessage(messageBody);
                    Console.WriteLine($"Sending message: {messageBody}");
                    await sender.SendMessageAsync(message);
                }
                catch (Exception exception)
                {
                    Console.WriteLine($"{DateTime.Now} :: Exception: {exception.Message}");
                }
                finally
                {
                    // Calling DisposeAsync on client types is required to ensure that network
                    // resources and other unmanaged objects are properly cleaned up.
                    await sender.DisposeAsync();
                    await client.DisposeAsync();
                }
            }
        }
    }
    
  10. Para salvar as alterações, selecione Ctrl+S e depois Ctrl+Q para fechar o editor.

Enviar uma mensagem para a fila

  1. Para enviar uma mensagem sobre uma promoção, execute o seguinte comando no Cloud Shell. A primeira linha garante que você está no caminho correto.

    cd ~/mslearn-connect-services-together/implement-message-workflows-with-service-bus/src/start
    dotnet run --project ./privatemessagesender
    

    Observação

    Na primeira vez que você executar os aplicativos neste exercício, permita que dotnet restaure os pacotes de fontes remotas e crie os aplicativos.

    À medida que o programa é executado, as mensagens são impressas no console, indicando que o aplicativo está enviando uma mensagem:

    Sending a message to the Sales Messages queue...
    Sending message: $10,000 order for bicycle parts from retailer Adventure Works.
    Message was sent successfully.
    
  2. Quando o aplicativo for concluído, execute o comando a seguir substituindo <namespace-name> pelo nome do namespace do Barramento de Serviço. Esse comando retornará o número de mensagens que estão na fila.

    az servicebus queue show \
        --resource-group <rgn>[sandbox resource group name]</rgn> \
        --name salesmessages \
        --query messageCount \
        --namespace-name <namespace-name>
    
  3. Execute o comando dotnet run da etapa 1 novamente e, após isso, execute o comando servicebus queue show mais uma vez. Sempre que você executar o aplicativo dotnet, uma nova mensagem será adicionada à fila. Você verá messageCount aumentar sempre que executar o comando do Azure.

Escrever código para receber mensagens da fila

  1. Execute o comando a seguir para abrir o editor novamente:

    code .
    
  2. No editor, abra privatemessagereceiver/Program.cs e localize a seguinte linha de código:

    const string ServiceBusConnectionString = "";
    

    Entre as aspas, cole a cadeia de conexão que você salvou anteriormente.

  3. Encontre o método ReceiveSalesMessageAsync(). Nesse método, localize a seguinte linha de código:

    // Create a Service Bus client that will authenticate using a connection string
    

    Substitua essa linha pelo seguinte código:

    var client = new ServiceBusClient(ServiceBusConnectionString);
    
  4. Para configurar as opções de tratamento de mensagens, localize a seguinte linha de código:

    // Create the options to use for configuring the processor
    

    Substitua essa linha pelas seguintes linhas de código:

    var processorOptions = new ServiceBusProcessorOptions
    {
        MaxConcurrentCalls = 1,
        AutoCompleteMessages = false
    };
    
  5. Para criar um processador, encontre a seguinte linha de código:

    // Create a processor that we can use to process the messages
    

    Substitua essa linha pelo seguinte código:

    await using ServiceBusProcessor processor = client.CreateProcessor(QueueName, processorOptions);
    
  6. Para configurar os manipuladores, encontre a seguinte linha de código:

    // Configure the message and error handler to use
    

    Substitua essa linha pelo seguinte código:

    processor.ProcessMessageAsync += MessageHandler;
    processor.ProcessErrorAsync += ErrorHandler;
    
  7. Para iniciar o processamento, encontre a seguinte linha de código:

    // Start processing
    

    Substitua essa linha pelo seguinte código:

    await processor.StartProcessingAsync();
    
  8. Para fechar a conexão com o Barramento de Serviço, encontre a seguinte linha de código:

    // Close the processor here
    

    Substitua essa linha pelo seguinte código:

    await processor.CloseAsync();
    
  9. Revise o código no método MessageHandler:

    // handle received messages
    static async Task MessageHandler(ProcessMessageEventArgs args)
    {
        // extract the message
        string body = args.Message.Body.ToString();
    
        // print the message
        Console.WriteLine($"Received: {body}");
    
        // complete the message so that message is deleted from the queue. 
        await args.CompleteMessageAsync(args.Message);
    }
    
  10. Revise o código no método ErrorHandler:

    // handle any errors when receiving messages
    static Task ErrorHandler(ProcessErrorEventArgs args)
    {
        // print the exception message
        Console.WriteLine(args.Exception.ToString());
        return Task.CompletedTask;
    }    
    
  11. Verifique se o código final de privatemessagereceiver/Program.cs é semelhante ao seguinte exemplo:

    using System;
    using System.Text;
    using System.Threading.Tasks;
    using Azure.Messaging.ServiceBus;
    
    namespace privatemessagereceiver
    {
        class Program
        {
    
            const string ServiceBusConnectionString = "Endpoint=sb://<examplenamespace.servicebus.windows.net/;SharedAccessKeyName=RootManageSharedAccessKey;SharedAccessKey=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
            const string QueueName = "salesmessages";
    
            static void Main(string[] args)
            {
    
                ReceiveSalesMessageAsync().GetAwaiter().GetResult();
    
            }
    
            static async Task ReceiveSalesMessageAsync()
            {
    
                Console.WriteLine("======================================================");
                Console.WriteLine("Press ENTER key to exit after receiving all the messages.");
                Console.WriteLine("======================================================");
    
    
                var client = new ServiceBusClient(ServiceBusConnectionString);
    
                var processorOptions = new ServiceBusProcessorOptions
                {
                    MaxConcurrentCalls = 1,
                    AutoCompleteMessages = false
                };
    
                await using ServiceBusProcessor processor = client.CreateProcessor(QueueName, processorOptions);
    
                processor.ProcessMessageAsync += MessageHandler;
                processor.ProcessErrorAsync += ErrorHandler;
    
    
                await processor.StartProcessingAsync();
    
                Console.Read();
    
                await processor.CloseAsync();
    
            }
    
            // handle received messages
            static async Task MessageHandler(ProcessMessageEventArgs args)
            {
                string body = args.Message.Body.ToString();
                Console.WriteLine($"Received: {body}");
    
                // complete the message. messages is deleted from the queue. 
                await args.CompleteMessageAsync(args.Message);
            }
    
            // handle any errors when receiving messages
            static Task ErrorHandler(ProcessErrorEventArgs args)
            {
                Console.WriteLine(args.Exception.ToString());
                return Task.CompletedTask;
            }
        }
    }
    
    
  12. Para salvar as alterações, selecione Ctrl+S e depois Ctrl+Q para fechar o editor.

Receber uma mensagem da fila

  1. Para executar o componente que recebe uma mensagem sobre uma venda, execute este comando no Cloud Shell:

    dotnet run --project privatemessagereceiver
    
  2. Verifique as notificações no Cloud Shell. No portal do Azure, vá para o namespace do Barramento de Serviço e verifique o gráfico de Mensagens:

    Received: $10,000 order for bicycle parts from retailer Adventure Works.
    
  3. Quando as mensagens forem recebidas no Cloud Shell, pressione Enter para interromper o aplicativo.

Verifique a contagem de mensagens

Execute o código a seguir para confirmar que todas as mensagens foram removidas da fila, lembrando de substituir <namespace-name> pelo namespace do Barramento de Serviço.

az servicebus queue show \
    --resource-group <rgn>[sandbox resource group name]</rgn> \
    --name salesmessages \
    --query messageCount \
    --namespace-name <namespace-name>

A saída será 0 se todas as mensagens tiverem sido removidas.

Você escreveu um código que envia uma mensagem sobre vendas individuais para uma fila do Barramento de Serviço. No aplicativo distribuído da força de vendas, você deve escrever esse código no aplicativo móvel que a equipe de vendas usa nos dispositivos.

Você também escreveu um código que recebe uma mensagem da fila do Barramento de Serviço. No aplicativo distribuído da força de vendas, você deverá gravar esse código no serviço Web que é executado no Azure e processar as mensagens recebidas.