Introdução ao Armazenamento de Filas do Azure através do .NET
Descrição Geral
O Armazenamento de Filas do Azure fornece mensagens na cloud entre componentes da aplicação. Na conceção de aplicações para dimensionamento, os componentes da aplicação são muitas vezes desacoplados para que possam ser dimensionados de forma independente. O Armazenamento de Filas fornece mensagens assíncronas entre componentes da aplicação, quer estejam em execução na cloud, no ambiente de trabalho, num servidor no local ou num dispositivo móvel. O Armazenamento de Filas também suporta a gestão de tarefas assíncronas e a criação de fluxos de trabalho de processos.
Acerca deste tutorial
Este tutorial mostra como escrever código .NET para alguns cenários comuns com o Armazenamento de Filas do Azure. Os cenários abrangidos incluem criar e eliminar filas e adicionar, ler e eliminar mensagens de filas.
Tempo estimado para concluir: 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 acedidas a partir de qualquer local no mundo através de chamadas autenticadas com HTTP ou HTTPS. Uma mensagem de fila única pode ter até 64 KB e uma fila pode conter milhões de mensagens, até ao limite da capacidade total de uma conta de armazenamento. O armazenamento de filas é frequentemente utilizado para criar um registo de tarefas pendentes de trabalho para processar de forma assíncrona.
Conceitos do serviço fila
O serviço Fila do Azure contém os seguintes componentes:
Conta de Armazenamento: todos os acessos ao Storage do Azure são efetuados através de uma conta de armazenamento. Para obter mais informações sobre contas de armazenamento, veja Descriçã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 a nomenclatura de filas, veja Nomenclatura de Filas e Metadados.
Mensagem: uma mensagem, em qualquer formato, até 64 KB. O tempo máximo que uma mensagem pode permanecer na fila de espera é 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 que indique que a mensagem não expira. Se este parâmetro for omitido, o time-to-live predefinido é de sete dias.
Formato de URL: As filas são endereçáveis com o seguinte formato de URL: http://
<storage account>
.queue.core.windows.net/<queue>
O seguinte URL endereça uma fila no diagrama:
http://myaccount.queue.core.windows.net/incoming-orders
Criar uma conta de armazenamento do Azure
A forma mais fácil de criar a primeira conta de armazenamento do Azure é com o portal do Azure. Para saber mais, veja Criar uma conta de armazenamento.
Também pode utilizar o Azure PowerShell, a CLI do Azure ou o Fornecedor de Recursos do Armazenamento do Azure para .NET.
Se preferir não criar uma conta de armazenamento no Azure neste momento, também pode utilizar o emulador de armazenamento do Azurite para executar e testar o código num ambiente local. Para obter mais informações, veja Utilizar o emulador do Azurite para o desenvolvimento local do Armazenamento do Azure.
Configurar o ambiente de desenvolvimento
Em seguida, configure o ambiente de desenvolvimento no Visual Studio, para estar pronto para experimentar os exemplos de código deste guia.
Criar um projeto de aplicação de consola do Windows
No Visual Studio, crie uma nova aplicação de consola do Windows. Os passos seguintes mostram-lhe como criar uma aplicação de consola no Visual Studio 2019. Os passos são semelhantes aos de outras versões do Visual Studio.
- Selecionar Ficheiro>Novo>Projeto
- Selecione Plataforma>Windows
- Selecione Aplicação de Consola (.NET Framework)
- Selecione Seguinte
- No campo Nome do projeto , introduza um nome para a sua aplicação
- Selecione Criar
Todos os exemplos de código deste tutorial podem ser adicionados ao método Main()
do ficheiro Program.cs
da aplicação da consola.
Pode utilizar as bibliotecas de cliente do Armazenamento do Microsoft Azure em qualquer tipo de aplicação .NET, incluindo um serviço cloud do Azure ou uma aplicação Web e aplicações móveis e de ambiente de trabalho. Neste guia, utilizamos uma aplicação de consola pela simplicidade.
Utilizar o NuGet para instalar os pacotes necessários
Tem de referenciar os quatro pacotes seguintes no seu projeto para concluir este tutorial:
- Biblioteca Azure.Core para .NET: este pacote fornece primitivos partilhados, abstrações e auxiliares para bibliotecas de cliente modernas do SDK do Azure .NET.
- Biblioteca de cliente Azure.Storage.Common para .NET: este pacote fornece uma infraestrutura partilhada pelas outras bibliotecas de cliente do Armazenamento do Microsoft Azure.
- Biblioteca de cliente Azure.Storage.Queues para .NET: este pacote permite trabalhar com o Armazenamento de Filas do Azure para armazenar mensagens que podem ser acedidas por um cliente.
- Biblioteca System.Configuration.ConfigurationManager para .NET: este pacote fornece acesso a ficheiros de configuração para aplicações cliente.
Pode utilizar o NuGet para obter estes pacotes. Siga estes passos:
- Clique com o botão direito do rato no Explorador de Soluções e selecione Gerir Pacotes NuGet.
- Selecione Procurar
- Procure online
Azure.Storage.Queues
e selecione Instalar para instalar a biblioteca de cliente do Armazenamento do Azure e as respetivas dependências. Esta ação também irá instalar as bibliotecas Azure.Storage.Common e Azure.Core, que são dependências da biblioteca de filas. - Procure online e
System.Configuration.ConfigurationManager
selecione Instalar para instalar o Configuration Manager.
Determinar o ambiente de destino
Tem duas opções de ambiente para executar os exemplos neste guia:
- Pode executar o código numa conta de armazenamento do Azure na nuvem.
- Pode executar o código no emulador de armazenamento do Azurite. O Azurite é um ambiente local que emula uma conta de Armazenamento do Azure na cloud. O Azurite é uma opção gratuita para testar e depurar o código enquanto a sua aplicação está em desenvolvimento. O emulador utiliza uma conta e chave bem conhecidas. Para obter mais informações, veja Utilizar o emulador do Azurite para desenvolvimento e teste do Armazenamento do Azure local.
Nota
Pode filtrar o emulador de armazenamento para evitar incorrer em custos associados ao Storage do Azure. No entanto, se optar por direcionar uma conta de Armazenamento do Azure na cloud, os custos para executar este tutorial serão insignificantes.
Obter a cadeia de ligação de armazenamento
As bibliotecas de cliente do Armazenamento do Microsoft Azure para o suporte .NET utilizam uma cadeia de ligação de armazenamento para configurar pontos finais e credenciais para aceder aos serviços de armazenamento. Para obter mais informações, veja Gerir chaves de acesso da conta de armazenamento.
Copiar as credenciais do Portal do Azure
O código de exemplo tem de autorizar o acesso à sua conta de armazenamento. Para autorizar, forneça à aplicação as credenciais da conta de armazenamento sob a forma de uma cadeia de ligação. Para ver as credenciais da conta de armazenamento:
Navegue para o portal do Azure.
Localize a sua conta de armazenamento.
Na secção Definições da descriçã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.
Encontre o valor da Cadeia de ligação em key1e clique no botão Copiar para copiar a cadeia de ligação. Irá adicionar o valor da cadeia de ligação para uma variável de ambiente no próximo passo.
Para obter mais informações sobre cadeias de ligação, veja Configurar uma cadeia de ligação para o Armazenamento do Azure.
Nota
A chave da conta de armazenamento é semelhante à palavra-passe de raiz da conta de armazenamento. Tenha sempre o cuidado de proteger a chave da conta de armazenamento. Evite distribui-la a outros utilizadores, pré-programá-la ou guardá-la num ficheiro de texto simples que seja acessível a outras pessoas. Regenere a sua chave através do portal do Azure se considerar que poderá ter sido comprometida.
A melhor forma para manter a cadeia de ligação de armazenamento é num ficheiro de configuração. Para configurar a cadeia de ligação, abra o ficheiro app.config
a partir do Explorador de Soluções no Visual Studio. Adicione o conteúdo do <appSettings>
elemento apresentado aqui. Substitua connection-string
pelo valor que copiou 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 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 do Azurite, pode utilizar um atalho que mapeia para o conhecido nome e chave da conta. Nesse caso, a definição da cadeia de ligação é:
<add key="StorageConnectionString" value="UseDevelopmentStorage=true" />
Adicionar com diretivas
Adicione as seguintes diretivas using
à parte superior do ficheiro 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 QueueClient
classe permite-lhe obter filas armazenadas no Armazenamento de Filas. Eis uma forma de criar o cliente do 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 que enviar com a QueueClient
classe têm de estar num formato que possa ser incluído num pedido XML com codificação UTF-8. Opcionalmente, pode definir a opção MessageEncoding como Base64 para processar mensagens não conformes.
Agora, está pronto para escrever código que lê dados de e escreve 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;
}
}
Introduzir uma mensagem numa fila
Para inserir uma mensagem numa fila existente, chame o SendMessage
método . Uma mensagem pode ser uma cadeia (no formato UTF-8) ou uma matriz de bytes. O código seguinte 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}");
}
Pré-visualização da mensagem seguinte
Pode pré-visualizar as mensagens na fila sem as remover da fila ao chamar o PeekMessages
método. Se não transmitir um valor para o maxMessages
parâmetro, a predefinição é pré-visualizar 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 os conteúdos de uma mensagem em fila
Pode alterar os conteúdos de uma mensagem no local na fila de espera. Se a mensagem representa uma tarefa de trabalho, pode utilizar esta funcionalidade para atualizar o estado da tarefa de trabalho. O seguinte código atualiza a mensagem de filas com novos conteúdos e expande o tempo limite de visibilidade em 60 segundos. Isto guarda o estado do trabalho associado à mensagem e atribui ao cliente outro minuto para continuar a trabalhar na mensagem. Pode utilizar esta técnica para controlar fluxos de trabalho de vários passos em mensagens de fila, sem ter de recomeçar desde o início se um passo de processamento falhar devido a uma falha de hardware ou software. Normalmente, também manteria uma contagem de tentativas e se a mensagem for repetida mais do que n vezes, deveria eliminá-la. Esta ação protege contra uma mensagem que aciona um erro da aplicação sempre que é 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
);
}
}
Desconsultar a mensagem seguinte
Descodule uma mensagem de uma fila em dois passos. Quando liga ReceiveMessages
para , recebe a mensagem seguinte numa fila. Uma mensagem devolvida ReceiveMessages
torna-se invisível para qualquer outra mensagem de leitura de código desta fila. Por predefinição, esta mensagem permanece invisível durante 30 segundos. Para concluir a remoção da mensagem da fila, também tem de chamar DeleteMessage
. Este processo de dois passos da remoção de uma mensagem garante que se o código não conseguir processar uma mensagem devido a uma falha de hardware ou software, outra instância do seu código poderá obter a mesma mensagem e tentar novamente. O código chama DeleteMessage
logo 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);
}
}
Utilizar o padrão de Async-Await com APIs comuns de Armazenamento de Filas
Este exemplo mostra como utilizar o padrão de Async-Await com APIs de Armazenamento de Filas comuns. O exemplo chama a versão assíncrona de cada um dos métodos especificados, conforme indicado pelo Async
sufixo de cada método. Quando é utilizado um método assíncrono, o padrão de Async-Await suspende a execução local até a chamada ser concluída. Este comportamento permite que o thread atual efetue outro trabalho, o que ajuda a evitar congestionamentos de desempenho e melhora a capacidade de resposta global da sua aplicação. Para obter mais detalhes sobre como utilizar o padrão de Async-Await no .NET, veja 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}'");
}
Utilizar opções adicionais para desativar mensagens
Existem duas formas através das quais pode personalizar a obtenção de mensagens a partir de uma fila. Em primeiro lugar, pode obter um lote de mensagens (até 32). Em segundo lugar, pode definir um tempo limite de invisibilidade superior ou inferior, dando mais ou menos tempo ao código para processar totalmente cada mensagem.
O seguinte exemplo de código utiliza o ReceiveMessages
método para obter 20 mensagens numa chamada. Em seguida, processa cada mensagem com um foreach
ciclo. Define também o tempo limite de invisibilidade para cinco minutos para cada mensagem. Tenha em atenção que os cinco minutos são iniciados para todas as mensagens ao mesmo tempo, pelo que após cinco minutos passaram desde a chamada para ReceiveMessages
o , quaisquer mensagens que não tenham sido eliminadas voltarão a ficar visíveis.
//-----------------------------------------------------
// 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
Pode obter uma estimativa do número de mensagens numa fila. O GetProperties
método devolve as propriedades da fila, incluindo a contagem de mensagens. A ApproximateMessagesCount
propriedade contém o número aproximado de mensagens na fila. Este número não é inferior ao número real de mensagens na fila, mas pode ser superior.
//-----------------------------------------------------
// 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}");
}
}
Eliminar uma fila
Para eliminar uma fila e todas as mensagens contidas na mesma, chame o Delete
método 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}'");
}
Passos seguintes
Agora que aprendeu as noções básicas do Armazenamento de Filas, siga estas ligações para saber mais sobre tarefas de armazenamento mais complexas.
- Veja a documentação de referência do Armazenamento de Filas para obter detalhes completos sobre as APIs disponíveis:
- Ver mais guias de funcionalidades para saber mais sobre as opções adicionais para armazenar dados no Azure.
- Introdução ao Armazenamento de Tabelas do Azure com o .NET para armazenar dados estruturados.
- Introdução ao Armazenamento de Blobs do Azure utilizar o .NET para armazenar dados não estruturados.
- Ligar à Base de Dados SQL com o .NET (C#) para armazenar dados relacionais.
- Saiba como simplificar o código que escreve para trabalhar com o Armazenamento do Azure com o SDK de WebJobs do Azure.
Para exemplos de código relacionados com SDKs .NET preteridos versão 11.x, veja Exemplos de código com a versão 11.x do .NET.