Share via


Introdução ao Armazenamento de Filas do Azure usando o .NET

Visão geral

O armazenamento de Filas do Azure fornece mensagens na nuvem entre os componentes do aplicativo. Na criação de aplicativos para escala, os componentes do aplicativo geralmente são desassociados para que possam ser dimensionados independentemente. O armazenamento de filas fornece mensagens assíncronas para a comunicação entre os componentes do aplicativo, estando eles em execução na nuvem, no computador, em um servidor local ou em um dispositivo móvel. O armazenamento de Filas também dá suporte ao gerenciamento de tarefas assíncronas e à criação de fluxos de trabalho do processo.

Sobre este tutorial

Este tutorial mostra como gravar código .NET para alguns cenários comuns usando o armazenamento de Filas do Azure. Os cenários abordados incluem a criação e a exclusão de filas e a adição, a leitura e a exclusão de mensagens da fila.

Tempo estimado para conclusão: 45 minutos

Pré-requisitos

O que é armazenamento em fila?

O armazenamento de filas do Azure é um serviço para armazenamento de um grande número de mensagens que podem ser acessadas de qualquer lugar do mundo por meio de chamadas autenticadas usando HTTP ou HTTPS. Uma única mensagem de fila pode ter até 64 KB de tamanho e uma fila pode conter milhões de mensagens, até o limite de capacidade total de uma conta de armazenamento. O armazenamento em fila é usado com frequência para criar uma lista de pendências de trabalho a ser processada de forma assíncrona.

Conceitos do serviço Fila

O serviço Fila do Azure contém os seguintes componentes:

Componentes do serviço Fila do Azure

  • Conta de Armazenamento: todo o acesso ao Armazenamento do Azure é feito através de uma conta de armazenamento. Para saber mais sobre as contas de armazenamento, confira Visão geral da conta de armazenamento.

  • Fila: uma fila contém um conjunto de mensagens. Todas as mensagens devem estar em uma fila. Observe que o nome da fila deve estar em letras minúsculas. Para saber mais sobre filas de nomenclatura, confira Nomenclatura de filas e metadados.

  • Mensagem: uma mensagem, em qualquer formato, de até 64 KB. O tempo máximo que uma mensagem pode ficar na fila é de sete dias. Para a versão 2017-07-29 ou posterior, a vida útil máxima pode ser qualquer número positivo ou -1, indicando que a mensagem não expira. Se esse parâmetro for omitido, a vida útil padrão será de sete dias.

  • Formato de URL: as filas são endereçáveis usando o seguinte formato: http://<storage account>.queue.core.windows.net/<queue>

    A URL a seguir endereça um fila no diagrama:

    http://myaccount.queue.core.windows.net/incoming-orders

Criar uma conta de armazenamento do Azure

A maneira mais fácil de criar sua primeira conta de armazenamento do Azure é usando o portal do Azure. Para saber mais, consulte Criar uma conta de armazenamento.

Você também pode criar uma conta de armazenamento do Azure usando o Azure PowerShell, a CLI do Azure ou o Provedor de Recursos de Armazenamento do Azure para .NET.

Se você preferir não criar uma conta de armazenamento no Azure neste momento, também pode usar o emulador de armazenamento Azurite para executar e testar seu código em um ambiente local. Para obter mais informações, consulte Usar o emulador Azurite para desenvolvimento local do armazenamento do Azure.

Configurar seu ambiente de desenvolvimento

Em seguida, configure seu ambiente de desenvolvimento no Visual Studio para poder ficar pronto para experimentar os exemplos de código neste guia.

Criar um projeto de aplicativo de console do Windows.

No Visual Studio, crie um novo aplicativo de console do Windows. As etapas a seguir mostram como criar um aplicativo de console no Visual Studio 2019. As etapas são semelhantes em outras versões do Visual Studio.

  1. Selecione Arquivo>Novo>Projeto
  2. Selecione Plataforma>Windows
  3. Selecione Aplicativo do Console (.NET Framework)
  4. Selecione Avançar
  5. No campo Nome do projeto, insira um nome para seu aplicativo.
  6. Escolha Criar

Todos os exemplos de código neste tutorial podem ser adicionados ao método Main() no arquivoProgram.cs do aplicativo de console.

Você pode usar as bibliotecas clientes do Armazenamento do Azure em qualquer tipo de aplicativo .NET, incluindo um serviço de nuvem do Azure ou aplicativo Web e aplicativos da área de trabalho ou móveis. Neste guia, usamos um aplicativo de console para simplificar.

Use o NuGet para instalar os pacotes necessários

Você precisa fazer referência aos quatro pacotes a seguir em seu projeto para concluir este tutorial:

Você pode usar NuGet para obter os dois pacotes. Siga estas etapas:

  1. Clique com o botão direito do mouse no seu projeto no Gerenciador de Soluções e escolha Gerenciar Pacotes NuGet.
  2. Selecione Procurar
  3. Pesquise online por Azure.Storage.Queues e selecione Instalar para instalar a biblioteca cliente de armazenamento do Azure e suas dependências. Isso também instalará as bibliotecas Azure.Storage.Common e Azure.Core,que são dependências da biblioteca de filas.
  4. Pesquise online por System.Configuration.ConfigurationManager e selecione Instalar para instalar o Configuration Manager.

Determinar o ambiente de destino

Você tem duas opções de ambiente para executar os exemplos neste guia:

  • Você pode executar o código em uma conta de Armazenamento do Azure na nuvem.
  • Você pode executar o código em um emulador de armazenamento do Azure. O Azurite é um ambiente local que emula uma conta de armazenamento do Azure na nuvem. O Azurite é uma opção gratuita para testar e depurar seu código enquanto o aplicativo está em desenvolvimento. O emulador usa uma conta e chave bem conhecidas. Para obter mais informações, consulte Usar o emulador Azurite para desenvolvimento e teste local do armazenamento do Azure.

Observação

Você pode utilizar o emulador de armazenamento como destino para evitar quaisquer custos associados ao Armazenamento do Azure. Todavia, se você escolher utilizar como destino uma conta de armazenamento do Azure na nuvem, os custos para realização das operações neste tutorial serão insignificantes.

Obter cadeia de conexão de armazenamento

As bibliotecas cliente de armazenamento do Azure para .NET dão suporte ao uso de cadeia de conexão de armazenamento para configurar pontos de extremidade e credenciais para acesso a serviços de armazenamento. Para obter mais informações, confira Gerenciar chaves de acesso da conta de armazenamento.

Copiar suas credenciais no Portal do Azure

O código de exemplo precisa autorizar o acesso à sua conta de armazenamento. Para autorizar, forneça suas credenciais de conta de armazenamento ao aplicativo na forma de uma cadeia de conexão. Para verificar as credenciais da conta de armazenamento:

  1. Navegue até o Portal do Azure.

  2. Localize sua cadeia de conexão.

  3. Na seção Configurações da visão geral da conta de armazenamento, selecione Chaves de acesso. Suas chaves de acesso da conta são exibidas, bem como a cadeia de conexão completa para cada chave.

  4. Encontre o valor da Cadeia de conexão em key1 e clique no botão Copiar para copiar a cadeia de conexão. Você adicionará o valor de cadeia de conexão para uma variável de ambiente na próxima etapa.

    Captura de tela mostrando como copiar uma cadeia de conexão do portal do Azure

Para obter mais detalhes sobre as sequências de conexão, veja Configurar uma cadeia de conexão para o Armazenamento do Azure.

Observação

Sua chave de conta de armazenamento é semelhante para a senha raiz da sua conta de armazenamento. Sempre tenha cuidado para proteger a chave de sua conta de armazenamento. Evite distribuí-la a outros usuários, embuti-la no código ou salvá-lo em um arquivo de texto sem formatação que esteja acessível a outras pessoas. Regenere a chave usando o portal do Azure se você achar que ela pode ter sido comprometida.

A melhor maneira de manter a cadeia de conexão de armazenamento é em um arquivo de configuração. Para configurar a cadeia de conexão, abra o arquivo app.config do Gerenciador de Soluções no Visual Studio. Adicione o conteúdo do elemento <appSettings> mostrado aqui. Substitua connection-string pelo valor copiado de sua conta de armazenamento no portal:

<configuration>
    <startup>
        <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.7.2" />
    </startup>
    <appSettings>
        <add key="StorageConnectionString" value="connection-string" />
    </appSettings>
</configuration>

Por exemplo, a configuração é semelhante a:

<add key="StorageConnectionString" value="DefaultEndpointsProtocol=https;AccountName=storagesample;AccountKey=GMuzNHjlB3S9itqZJHHCnRkrokLkcSyW7yK9BRbGp0ENePunLPwBgpxV1Z/pVo9zpem/2xSHXkMqTHHLcx8XRA==EndpointSuffix=core.windows.net" />

Para direcionar o emulador de armazenamento Azurite, você pode usar um atalho que mapeia para o nome de conta e chave bem conhecidos. Nesse caso, a configuração da cadeia de conexão é:

<add key="StorageConnectionString" value="UseDevelopmentStorage=true" />

Adicionar diretivas using

Adicione as seguintes diretivas using à parte superior do arquivo Program.cs:

using System; // Namespace for Console output
using System.Configuration; // Namespace for ConfigurationManager
using System.Threading.Tasks; // Namespace for Task
using Azure.Identity;
using Azure.Storage.Queues; // Namespace for Queue storage types
using Azure.Storage.Queues.Models; // Namespace for PeekedMessage

Crie o cliente de armazenamento de Filas

A classe QueueClient permite recuperar filas armazenadas no armazenamento de Filas. Veja uma maneira de criar o cliente de serviço:

//-------------------------------------------------
// Create the queue service client
//-------------------------------------------------
public void CreateQueueClient(string queueName)
{
    // Get the connection string from app settings
    string connectionString = ConfigurationManager.AppSettings["StorageConnectionString"];

    // Instantiate a QueueClient which will be used to create and manipulate the queue
    QueueClient queueClient = new QueueClient(connectionString, queueName);
}

Dica

As mensagens enviadas usando a classe QueueClient devem estar em um formato que possa ser incluído em uma solicitação XML com codificação UTF-8. Opcionalmente, você pode definir a opção MessageEncoding como Base64 para lidar com mensagens que não estejam em conformidade.

Agora você está pronto para escrever um código que lê e grava dados no armazenamento de Filas.

Criar uma fila

Este exemplo mostra como criar uma fila:

//-------------------------------------------------
// Create a message queue
//-------------------------------------------------
public bool CreateQueue(string queueName)
{
    try
    {
        // Get the connection string from app settings
        string connectionString = ConfigurationManager.AppSettings["StorageConnectionString"];

        // Instantiate a QueueClient which will be used to create and manipulate the queue
        QueueClient queueClient = new QueueClient(connectionString, queueName);

        // Create the queue
        queueClient.CreateIfNotExists();

        if (queueClient.Exists())
        {
            Console.WriteLine($"Queue created: '{queueClient.Name}'");
            return true;
        }
        else
        {
            Console.WriteLine($"Make sure the Azurite storage emulator running and try again.");
            return false;
        }
    }
    catch (Exception ex)
    {
        Console.WriteLine($"Exception: {ex.Message}\n\n");
        Console.WriteLine($"Make sure the Azurite storage emulator running and try again.");
        return false;
    }
}

Inserir uma mensagem em uma fila

Para inserir uma mensagem em uma fila existente, chame o método SendMessage. Uma mensagem pode ser uma cadeia de caracteres (em formato UTF-8) ou uma matriz de bytes. O código a seguir cria uma fila (se não existir) e insere uma mensagem:

//-------------------------------------------------
// Insert a message into a queue
//-------------------------------------------------
public void InsertMessage(string queueName, string message)
{
    // Get the connection string from app settings
    string connectionString = ConfigurationManager.AppSettings["StorageConnectionString"];

    // Instantiate a QueueClient which will be used to create and manipulate the queue
    QueueClient queueClient = new QueueClient(connectionString, queueName);

    // Create the queue if it doesn't already exist
    queueClient.CreateIfNotExists();

    if (queueClient.Exists())
    {
        // Send a message to the queue
        queueClient.SendMessage(message);
    }

    Console.WriteLine($"Inserted: {message}");
}

Espiar a próxima mensagem

Você pode inspecionar as mensagens na fila sem removê-las da fila chamando o método PeekMessages. Se você não passar um valor para o maxMessages parâmetro, o padrão será inspecionar uma mensagem.

//-------------------------------------------------
// Peek at a message in the queue
//-------------------------------------------------
public void PeekMessage(string queueName)
{
    // Get the connection string from app settings
    string connectionString = ConfigurationManager.AppSettings["StorageConnectionString"];

    // Instantiate a QueueClient which will be used to manipulate the queue
    QueueClient queueClient = new QueueClient(connectionString, queueName);

    if (queueClient.Exists())
    { 
        // Peek at the next message
        PeekedMessage[] peekedMessage = queueClient.PeekMessages();

        // Display the message
        Console.WriteLine($"Peeked message: '{peekedMessage[0].Body}'");
    }
}

Alterar o conteúdo de uma mensagem na fila

Você pode alterar o conteúdo de uma mensagem in-loco na fila. Se a mensagem representar uma tarefa de trabalho, você poderá usar esse recurso para atualizar o status da tarefa de trabalho. O código a seguir atualiza a mensagem da fila com novo conteúdo e define o tempo limite de visibilidade para estender mais 60 segundos. Isso salva o estado do trabalho associado à mensagem e dá ao cliente mais um minuto para continuar trabalhando na mensagem. Você pode usar essa técnica para acompanhar fluxos de trabalho de várias etapas em mensagens em fila, sem a necessidade de começar desde o início, caso uma etapa de processamento falhe devido a uma falha de hardware ou de software. Normalmente, você mantém uma contagem de repetições e, se a mensagem for repetida mais de n vezes, você a exclui. Isso protege contra uma mensagem que dispara um erro do aplicativo sempre que for processada.

//-------------------------------------------------
// Update an existing message in the queue
//-------------------------------------------------
public void UpdateMessage(string queueName)
{
    // Get the connection string from app settings
    string connectionString = ConfigurationManager.AppSettings["StorageConnectionString"];

    // Instantiate a QueueClient which will be used to manipulate the queue
    QueueClient queueClient = new QueueClient(connectionString, queueName);

    if (queueClient.Exists())
    {
        // Get the message from the queue
        QueueMessage[] message = queueClient.ReceiveMessages();

        // Update the message contents
        queueClient.UpdateMessage(message[0].MessageId, 
                message[0].PopReceipt, 
                "Updated contents",
                TimeSpan.FromSeconds(60.0)  // Make it invisible for another 60 seconds
            );
    }
}

Remover a próxima mensagem da fila

Remova uma mensagem da fila em duas etapas. Ao chamar ReceiveMessages, você recebe a próxima mensagem em uma fila. Uma mensagem retornada de ReceiveMessages torna-se invisível para todas as outras mensagens de leitura de código da fila. Por padrão, essa mensagem permanece invisível por 30 segundos. Para terminar de remover a mensagem da fila, você também deve chamar DeleteMessage. Este processo de duas etapas de remover uma mensagem garante que quando o código não processa uma mensagem devido à falhas de hardware ou de software, outra instância do seu código pode receber a mesma mensagem e tentar novamente. O código chamará DeleteMessage logo depois que a mensagem tiver sido processada:

//-------------------------------------------------
// Process and remove a message from the queue
//-------------------------------------------------
public void DequeueMessage(string queueName)
{
    // Get the connection string from app settings
    string connectionString = ConfigurationManager.AppSettings["StorageConnectionString"];

    // Instantiate a QueueClient which will be used to manipulate the queue
    QueueClient queueClient = new QueueClient(connectionString, queueName);

    if (queueClient.Exists())
    {
        // Get the next message
        QueueMessage[] retrievedMessage = queueClient.ReceiveMessages();

        // Process (i.e. print) the message in less than 30 seconds
        Console.WriteLine($"Dequeued message: '{retrievedMessage[0].Body}'");

        // Delete the message
        queueClient.DeleteMessage(retrievedMessage[0].MessageId, retrievedMessage[0].PopReceipt);
    }
}

Use o padrão Async-Await com APIs comuns de armazenamento de Filas

Este exemplo mostra como usar o padrão Async-Await com APIs comuns de armazenamento de Filas. O exemplo chama a versão assíncrona de cada um dos métodos determinados, conforme indicado pelo Async sufixo de cada método. Quando um método assíncrono é usado, o padrão Async-Await suspende a execução local até que a chamada seja concluída. Esse comportamento permite que o thread atual faça outro trabalho que ajude a evitar gargalos de desempenho e melhora a capacidade de resposta geral do aplicativo. Para obter mais detalhes sobre como usar o padrão Async-Await no .NET, confira Async e Await (C# e Visual Basic)

//-------------------------------------------------
// Perform queue operations asynchronously
//-------------------------------------------------
public async Task QueueAsync(string queueName)
{
    // Get the connection string from app settings
    string connectionString = ConfigurationManager.AppSettings["StorageConnectionString"];

    // Instantiate a QueueClient which will be used to manipulate the queue
    QueueClient queueClient = new QueueClient(connectionString, queueName);

    // Create the queue if it doesn't already exist
    await queueClient.CreateIfNotExistsAsync();

    if (await queueClient.ExistsAsync())
    {
        Console.WriteLine($"Queue '{queueClient.Name}' created");
    }
    else
    {
        Console.WriteLine($"Queue '{queueClient.Name}' exists");
    }

    // Async enqueue the message
    await queueClient.SendMessageAsync("Hello, World");
    Console.WriteLine($"Message added");

    // Async receive the message
    QueueMessage[] retrievedMessage = await queueClient.ReceiveMessagesAsync();
    Console.WriteLine($"Retrieved message with content '{retrievedMessage[0].Body}'");

    // Async delete the message
    await queueClient.DeleteMessageAsync(retrievedMessage[0].MessageId, retrievedMessage[0].PopReceipt);
    Console.WriteLine($"Deleted message: '{retrievedMessage[0].Body}'");

    // Async delete the queue
    await queueClient.DeleteAsync();
    Console.WriteLine($"Deleted queue: '{queueClient.Name}'");
}

Use opções adicionais para remover mensagens da fila

Há duas maneiras de personalizar a recuperação da mensagem de uma fila. Primeiro, você pode obter um lote de mensagens (até 32). Segundo, você pode definir um tempo limite de invisibilidade mais longo ou mais curto, permitindo mais ou menos tempo para seu código processar totalmente cada mensagem.

O exemplo de código a seguir usa o método ReceiveMessages para receber 20 mensagens em uma chamada. Em seguida, ele processa cada mensagem usando um loop foreach. Ele também define o tempo limite de invisibilidade de cinco minutos para cada mensagem. Observe que os 5 minutos começam para todas as mensagens ao mesmo tempo; portanto, depois de 5 minutos desde a chamada para ReceiveMessages, todas as mensagens que não tenham sido excluídas se tornarão visíveis novamente.

//-----------------------------------------------------
// Process and remove multiple messages from the queue
//-----------------------------------------------------
public void DequeueMessages(string queueName)
{
    // Get the connection string from app settings
    string connectionString = ConfigurationManager.AppSettings["StorageConnectionString"];

    // Instantiate a QueueClient which will be used to manipulate the queue
    QueueClient queueClient = new QueueClient(connectionString, queueName);

    if (queueClient.Exists())
    {
        // Receive and process 20 messages
        QueueMessage[] receivedMessages = queueClient.ReceiveMessages(20, TimeSpan.FromMinutes(5));

        foreach (QueueMessage message in receivedMessages)
        {
            // Process (i.e. print) the messages in less than 5 minutes
            Console.WriteLine($"De-queued message: '{message.Body}'");

            // Delete the message
            queueClient.DeleteMessage(message.MessageId, message.PopReceipt);
        }
    }
}

Obter o tamanho da fila

Você pode obter uma estimativa do número de mensagens em uma fila. O método GetProperties retorna propriedades de fila, incluindo a contagem de mensagens. A ApproximateMessagesCount propriedade contém o número aproximado de mensagens na fila. Esse número não é menor do que o número real de mensagens na fila, mas pode ser maior.

//-----------------------------------------------------
// Get the approximate number of messages in the queue
//-----------------------------------------------------
public void GetQueueLength(string queueName)
{
    // Get the connection string from app settings
    string connectionString = ConfigurationManager.AppSettings["StorageConnectionString"];

    // Instantiate a QueueClient which will be used to manipulate the queue
    QueueClient queueClient = new QueueClient(connectionString, queueName);

    if (queueClient.Exists())
    {
        QueueProperties properties = queueClient.GetProperties();

        // Retrieve the cached approximate message count.
        int cachedMessagesCount = properties.ApproximateMessagesCount;

        // Display number of messages.
        Console.WriteLine($"Number of messages in queue: {cachedMessagesCount}");
    }
}

Excluir uma fila

Para excluir uma fila e todas as mensagens que ela contém, chame o Delete método no objeto da fila.

//-------------------------------------------------
// Delete the queue
//-------------------------------------------------
public void DeleteQueue(string queueName)
{
    // Get the connection string from app settings
    string connectionString = ConfigurationManager.AppSettings["StorageConnectionString"];

    // Instantiate a QueueClient which will be used to manipulate the queue
    QueueClient queueClient = new QueueClient(connectionString, queueName);

    if (queueClient.Exists())
    {
        // Delete the queue
        queueClient.Delete();
    }

    Console.WriteLine($"Queue deleted: '{queueClient.Name}'");
}

Próximas etapas

Agora que você aprendeu os conceitos básicos do armazenamento de Filas, siga estes links para saber mais sobre tarefas de armazenamento mais complexas.

Para obter exemplos de código relacionados usando SDKs preteridos do .NET versão 11.x, confira os Exemplos de código usando o .NET versão 11.x.