Partilhar 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 componentes de aplicativos. Ao projetar aplicativos para escala, os componentes do aplicativo geralmente são dissociados para que possam ser dimensionados de forma independente. O Armazenamento em Fila fornece mensagens assíncronas entre componentes de aplicativos, estejam eles em execução na nuvem, na área de trabalho, em um servidor local ou em um dispositivo móvel. O armazenamento em fila também oferece suporte ao gerenciamento de tarefas assíncronas e à criação de fluxos de trabalho do processo.

Acerca deste tutorial

Este tutorial mostra como escrever código .NET para alguns cenários comuns usando o Armazenamento de Filas do Azure. Os cenários abordados incluem a criação e exclusão de filas e a adição, leitura e exclusão de mensagens de 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 armazenar 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 é frequentemente usado para criar uma lista de pendências de trabalho para processar de forma assíncrona.

Conceitos do Serviço de Fila

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

Componentes do serviço de fila do Azure

  • Conta de armazenamento: Todo o acesso ao Armazenamento do Azure é feito através de uma conta de armazenamento. Para obter mais informações sobre contas de armazenamento, consulte Visão geral da conta de armazenamento.

  • Fila: Uma fila contém um conjunto de mensagens. Todas as mensagens têm de estar numa fila. Tenha em atenção que o nome da fila tem de estar todo em minúsculas. Para obter informações sobre como nomear filas, consulte Nomeando filas e metadados.

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

  • Formato URL: As filas podem ser endereçadas usando o seguinte formato de URL: http://<storage account>.queue.core.windows.net/<queue>

    A seguinte URL aponta para uma 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 preferir não criar uma conta de armazenamento no Azure neste momento, você 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 o desenvolvimento local do Armazenamento do Azure.

Configurar seu ambiente de desenvolvimento

Em seguida, configure seu ambiente de desenvolvimento no Visual Studio para que você esteja pronto para experimentar os exemplos de código neste guia.

Criar um projeto de aplicativo de console do Windows

No Visual Studio, crie uma nova aplicação de consola do Windows. As etapas a seguir mostram como criar um aplicativo de console no Visual Studio 2019. Os passos são semelhantes aos de outras versões do Visual Studio.

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

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

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

Utilizar 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 o NuGet para obter esses pacotes. Siga estes passos:

  1. Clique com o botão direito do mouse em seu projeto no Gerenciador de Soluções e escolha Gerenciar Pacotes NuGet.
  2. Selecione Procurar
  3. Pesquise online Azure.Storage.Queues, e selecione Instalar para instalar a biblioteca de cliente do Armazenamento do Azure e as 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.ConfigurationManagere selecione Instalar para instalar o Configuration Manager.

Determine seu ambiente de destino

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

  • Você pode executar seu código em uma conta de Armazenamento do Azure na nuvem.
  • Você pode executar seu código no emulador de armazenamento Azurite. 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 seu 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 do Armazenamento do Azure local.

Observação

Você pode direcionar o emulador de armazenamento para evitar incorrer em quaisquer custos associados ao Armazenamento do Azure. No entanto, se você optar por direcionar uma conta de Armazenamento do Azure na nuvem, os custos para executar este tutorial serão insignificantes.

Obter sua cadeia de conexão de armazenamento

As bibliotecas de cliente do Armazenamento do Azure para .NET suportam o uso de uma cadeia de ligação de armazenamento para configurar pontos de extremidade e credenciais para aceder a serviços de armazenamento. Para obter mais informações, consulte Gerenciar chaves de acesso da conta de armazenamento.

Copiar as credenciais do Portal do Azure

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

  1. Navegue até o portal do Azure.

  2. Localize a sua conta de armazenamento.

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

  4. Localize 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 da cadeia de conexão a 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 informações sobre cadeias de conexão, consulte Configurar uma cadeia de conexão para o Armazenamento do Azure.

Observação

A chave da conta de armazenamento é semelhante à palavra-passe de raiz da conta de armazenamento. Tenha sempre cuidado para proteger a chave da sua conta de armazenamento. Evite distribuí-lo a outros usuários, codificá-lo ou salvá-lo em um arquivo de texto simples acessível a outras pessoas. Regenere sua chave usando o portal do Azure se você acredita 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 sua 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 da 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 sua definição de 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, pode-se usar um atalho que faz a correspondência com o nome e a chave da conta conhecidos. Nesse caso, a configuração da cadeia de conexão é:

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

Adicionar diretivas de utilização

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

Criar o cliente de armazenamento em fila

A classe QueueClient permite recuperar filas armazenadas no Armazenamento de Filas. Aqui está 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);
}

Sugestão

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 não compatíveis.

Agora você está pronto para escrever 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 numa fila

Para inserir uma mensagem em uma fila existente, chame o método SendMessage. Uma mensagem pode ser uma cadeia de caracteres (no formato UTF-8) ou uma matriz de bytes. O código a seguir cria uma fila (se ela 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}");
}

Espreite a próxima mensagem

Você pode espiar as mensagens na fila sem removê-las da fila chamando o método PeekMessages. Se você não passar um valor para o parâmetro maxMessages, o padrão é espiar 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 em fila

Você pode alterar o conteúdo de uma mensagem diretamente 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 de fila com novos conteúdos e define o tempo limite de visibilidade para estender mais 60 segundos. Isso salva o estado de trabalho associado à mensagem e dá ao cliente mais um minuto para continuar trabalhando na mensagem. Você pode usar essa técnica para rastrear fluxos de trabalho de várias etapas em mensagens de fila, sem ter que começar de novo desde o início se uma etapa de processamento falhar devido a uma falha de hardware ou software. Normalmente, você também manteria uma contagem de tentativas e, se a mensagem for repetida mais de n vezes, você a excluirá. Isso protege contra uma mensagem que dispara um erro de aplicativo cada vez que ele é processado.

//-------------------------------------------------
// 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
            );
    }
}

Retirar a próxima mensagem da fila

Remova uma mensagem da fila em duas etapas. Quando você liga para ReceiveMessages, você recebe a próxima mensagem em uma fila. Uma mensagem retornada do ReceiveMessages torna-se invisível para qualquer outro código que lê mensagens dessa fila. Por padrão, essa mensagem permanece invisível por 30 segundos. Para concluir a remoção da mensagem da fila, você também deve chamar DeleteMessage. Esse processo de duas etapas de remoção de uma mensagem garante que, se o código falhar ao processar uma mensagem devido a uma falha de hardware ou software, outra instância do código poderá receber a mesma mensagem e tentar novamente. O seu código chama DeleteMessage imediatamente após a mensagem ter 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);
    }
}

Usar o padrão Async-Await com APIs comuns de armazenamento em fila

Este exemplo mostra como usar o padrão Async-Await com APIs comuns de armazenamento em fila. O exemplo invoca a versão assíncrona de cada um dos métodos fornecidos, conforme indicado pelo sufixo Async 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, o que ajuda a evitar gargalos de desempenho e melhora a capacidade de resposta geral do seu aplicativo. Para obter mais detalhes sobre como usar o padrão Async-Await no .NET, consulte Async and 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}'");
}

Usar opções adicionais para enfileirar mensagens

Há duas maneiras de personalizar a recuperação de mensagens de uma fila. Primeiro, você pode receber um lote de mensagens (até 32). Em segundo lugar, você pode definir um tempo limite de invisibilidade maior ou menor, permitindo que seu código tenha mais ou menos tempo para processar completamente cada mensagem.

O exemplo de código a seguir usa o método ReceiveMessages para obter 20 mensagens em uma chamada. Em seguida, ele processa cada mensagem usando um loop de foreach. Também define o tempo limite de invisibilidade para cinco minutos para cada mensagem. Observe que os cinco minutos começam para todas as mensagens ao mesmo tempo, portanto, após cinco minutos desde a chamada para ReceiveMessages, todas as mensagens que não foram 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 comprimento 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 propriedade ApproximateMessagesCount 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 contidas nela, chame o método Delete no objeto queue.

//-------------------------------------------------
// 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óximos passos

Agora que você aprendeu as noções básicas do armazenamento em fila, siga estes links para saber mais sobre tarefas de armazenamento mais complexas.

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