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:
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.
- Selecione Arquivo>Novo>Projeto
- Selecione Plataforma>Windows
- Selecione Aplicativo do Console (.NET Framework)
- Selecione Avançar
- No campo Nome do projeto, insira um nome para seu aplicativo.
- 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:
- Biblioteca do Azure. Core para .NET: este pacote fornece primitivos compartilhados, abstrações e auxiliares para bibliotecas de cliente modernos SDK do .NET Azure.
- Biblioteca cliente do Azure.Storage.Common para .NET: este pacote fornece infraestrutura compartilhada por outras bibliotecas clientes de armazenamento do Azure.
- Biblioteca cliente do Azure.Storage.Queues para .NET: este pacote permite trabalhar com o armazenamento de Filas do Azure para armazenar mensagens que podem ser acessadas por um cliente.
- Biblioteca System.ConfigurationManager para .NET: este pacote fornece acesso aos arquivos de configuração para aplicativos clientes.
Você pode usar NuGet para obter os dois pacotes. Siga estas etapas:
- Clique com o botão direito do mouse no seu projeto no Gerenciador de Soluções e escolha Gerenciar Pacotes NuGet.
- Selecione Procurar
- 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. - 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:
Navegue até o Portal do Azure.
Localize sua cadeia de conexão.
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.
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.
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.
- Consulte a documentação de referência do armazenamento de Filas para obter detalhes completos sobre as APIs disponíveis:
- Consulte outros guias de recursos para obter informações sobre opções adicionais para armazenar dados no Azure.
- Introdução ao armazenamento de Tabelas do Azure usando o .NET para armazenar dados estruturados.
- Introdução ao armazenamento de Blobs do Azure usando o .NET para armazenar dados não estruturados.
- Conectar-se ao Banco de Dados SQL usando .NET (C#) para armazenar dados relacionais.
- Saiba como simplificar o código que você escreve para trabalhar com o Armazenamento do Azure usando o SDK do Azure WebJobs.
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.