Compartilhar 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. Ao projetar aplicativos para escala, os componentes do aplicativo geralmente são dissociados para que possam ser dimensionados de forma independente. O Armazenamento de Filas fornece mensagens assíncronas entre os componentes do aplicativo, sejam eles em execução na nuvem, na área de trabalho, 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 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 é o armazenamento de filas?

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 total de capacidade de uma conta de armazenamento. O armazenamento de filas geralmente é usado para criar um acúmulo de trabalho para processar de forma assíncrona.

Conceitos de serviço de fila

O serviço 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 por meio de uma conta de armazenamento. Para obter mais informações sobre contas de armazenamento, consulte a 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 obter informações sobre filas de nomenclatura, consulte Filas de Nomenclatura 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, 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 podem ser endereçáveis usando o seguinte formato de URL: http://<storage account>.queue.core.windows.net/<queue>

    A URL a seguir aborda uma fila no diagrama:

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

Crie 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, confira 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 no momento, também poderá usar o emulador de armazenamento do Azurite para executar e testar seu código em um ambiente local. Para obter mais informações, consulte Usar o emulador do 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 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. Selecionar Arquivo>Novo>Projeto
  2. Selecionar Plataforma>Windows
  3. Selecionar Aplicativo de Console (.NET Framework)
  4. Selecionar 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 clientes do Armazenamento do Azure em qualquer tipo de aplicativo .NET, incluindo um serviço de nuvem do Azure ou um aplicativo Web e aplicativos móveis e desktop. 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 o NuGet para obter esses pacotes. Siga estas etapas:

  1. Clique com o botão direito do mouse no projeto no Gerenciador de Soluções e escolha Gerenciar Pacotes NuGet.
  2. Selecione Navegar
  3. Pesquise na internet por Azure.Storage.Queues e selecione Instalar a fim de instalar a biblioteca do 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 System.Configuration.ConfigurationManagere selecione Instalar para instalar o Configuration Manager.

Determinar 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 do 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 uma chave conhecidas. Para obter mais informações, consulte Usar o emulador do Azurite para desenvolvimento e teste do Armazenamento do Azure local.

Observação

Você pode direcionar o emulador de armazenamento para evitar incorrer em 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.

Obtenha sua cadeia de conexão de armazenamento

As bibliotecas de cliente do Armazenamento do Azure para .NET suportam o uso de uma string de conexão de armazenamento para configurar endereços de endpoint e credenciais para acessar serviços de armazenamento. Para obter mais informações, consulte 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, você fornece ao aplicativo suas credenciais de conta de armazenamento na forma de uma cadeia de conexão. Para exibir suas credenciais de conta de armazenamento:

  1. Navegue até o portal do Azure.

  2. Localize sua conta de armazenamento.

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

  4. Localize o valor da cadeia de conexão na tecla 1 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

Sua chave de conta de armazenamento é semelhante à senha raiz da sua conta de armazenamento. Sempre tenha cuidado para proteger a chave da conta de armazenamento. Evite distribuí-lo para outros usuários, codificar ou salvá-lo em um arquivo de texto sem formatação acessível para 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 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, sua 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 e chave de conta conhecidos. Nesse caso, a configuração da cadeia de conexão é:

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

Adicionar diretivas using

Adicione as seguintes diretivas de 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 de Filas

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

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

Agora você está pronto para escrever um código que lê dados 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 (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}");
}

Espie 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 na fila

Você pode alterar diretamente o conteúdo de uma mensagem 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 novos conteúdos 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 rastrear fluxos de trabalho de várias etapas em mensagens de fila, sem precisar recomeçar 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 repetições e, se a mensagem for repetida mais de n vezes, você a excluiria. Isso protege contra uma mensagem que dispara um erro de aplicativo sempre que é 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
            );
    }
}

Desativar a próxima mensagem

Remova uma mensagem de uma fila em duas etapas. Ao chamar ReceiveMessages, você receberá a próxima mensagem em uma fila. Uma mensagem retornada de ReceiveMessages torna-se invisível para qualquer outro código que leia 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 não processar uma mensagem devido a uma falha de hardware ou software, outra instância do seu código poderá receber a mesma mensagem e tentar novamente. Seu código chama DeleteMessage imediatamente após o processamento da mensagem.

//-------------------------------------------------
// 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 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 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 aplicativo. Para obter mais detalhes sobre como usar o padrão Async-Await no .NET, consulte 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}'");
}

Usar opções adicionais para desativar mensagens

Há duas maneiras de personalizar a recuperação de mensagens de uma fila. Primeiro, você pode obter um lote de mensagens (até 32). Em segundo lugar, você pode definir um tempo limite de invisibilidade mais longo ou menor, permitindo que seu código tenha mais ou menos tempo para processar totalmente 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. Ele também define o tempo limite de invisibilidade como cinco minutos para cada mensagem. Observe que os cinco minutos começam para todas as mensagens ao mesmo tempo, portanto, após cinco minutos passados desde que a chamada para ReceiveMessages, todas as mensagens que não foram excluídas ficarã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 de 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 as noções básicas 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 do .NET versão 11.x preteridos, consulte exemplos de código usando o .NET versão 11.x.