Azure Service Bus biblioteca de cliente para .NET – versão 7.13.1

Azure Service Bus permite-lhe criar aplicações que tiram partido de padrões de mensagens assíncronas através de um serviço altamente fiável para mediar mensagens entre produtores e consumidores. Azure Service Bus fornece mensagens flexíveis e mediadas entre o cliente e o servidor, juntamente com mensagens FIFO (first in, first-out) estruturadas e funcionalidades de publicação/subscrição com encaminhamento complexo. Se quiser saber mais sobre Azure Service Bus, poderá querer rever: O que é Azure Service Bus?

Utilize a biblioteca de cliente para Azure Service Bus para:

  • Transferir dados empresariais: tire partido das mensagens para uma troca duradoura de informações, como encomendas de vendas ou compras, diários ou movimentos de inventário.

  • Desassociar aplicações: melhore a fiabilidade e escalabilidade de aplicações e serviços, aliviando os remetentes e recetores da necessidade de estarem online ao mesmo tempo.

  • Controlar a forma como as mensagens são processadas: suporte os consumidores concorrentes tradicionais para mensagens que utilizam filas ou permita a cada consumidor a sua própria instância de uma mensagem através de tópicos e subscrições.

  • Implementar fluxos de trabalho complexos: as sessões de mensagens suportam cenários que requerem ordenação de mensagens ou diferimento de mensagens.

Código fonte | Pacote (NuGet) | Documentação | de referência da APIDocumentação do | produto Guia | de migraçãoGuia de resolução de problemas

Introdução

Pré-requisitos

  • Subscrição do Microsoft Azure: Para utilizar os serviços do Azure, incluindo Azure Service Bus, precisará de uma subscrição. Se não tiver uma conta do Azure existente, pode inscrever-se numa avaliação gratuita ou utilizar os benefícios de subscritor do MSDN quando criar uma conta.

  • Espaço de nomes do Service Bus: Para interagir com Azure Service Bus, também terá de ter um espaço de nomes disponível. Se não estiver familiarizado com a criação de recursos do Azure, poderá querer seguir o guia passo a passo para criar um espaço de nomes do Service Bus com o portal do Azure. Aqui, também pode encontrar instruções detalhadas para utilizar a CLI do Azure, Azure PowerShell ou modelos do Azure Resource Manager (ARM) para criar uma entidade do Service Bus.

  • C# 8.0: A biblioteca de cliente Azure Service Bus utiliza as novas funcionalidades que foram introduzidas no C# 8.0. Para tirar partido da sintaxe C# 8.0, recomenda-se que compile com o SDK .NET Core 3.0 ou superior com uma versão de linguagem do latest.

    Os utilizadores do Visual Studio que pretendam tirar o máximo partido da sintaxe C# 8.0 terão de utilizar o Visual Studio 2019 ou posterior. O Visual Studio 2019, incluindo a edição Community gratuita, pode ser transferido aqui. Os utilizadores do Visual Studio 2017 podem tirar partido da sintaxe C# 8 ao utilizar o pacote NuGet Microsoft.Net.Compilers e ao definir a versão do idioma, embora a experiência de edição possa não ser a ideal.

    Ainda pode utilizar a biblioteca com versões de linguagem C# anteriores, mas terá de gerir manualmente membros descartáveis assíncronos e enumerados assíncronos em vez de beneficiar da nova sintaxe. Ainda pode visar qualquer versão de arquitetura suportada pelo seu SDK .NET Core, incluindo versões anteriores do .NET Core ou do .NET Framework. Para obter mais informações, veja: como especificar arquiteturas de destino.

    Nota Importante: Para criar ou executar os exemplos e os exemplos sem modificação, a utilização do C# 8.0 é obrigatória. Ainda pode executar os exemplos se decidir alterá-los para outras versões de idioma.

Para criar rapidamente os recursos necessários do Service Bus no Azure e para receber uma cadeia de ligação para os mesmos, pode implementar o nosso modelo de exemplo ao clicar em:

Implementar no Azure

Instalar o pacote

Instale a biblioteca de cliente Azure Service Bus para .NET com NuGet:

dotnet add package Azure.Messaging.ServiceBus

Autenticar o cliente

Para que a biblioteca de cliente do Service Bus interaja com uma fila ou tópico, terá de compreender como ligar e autorizar com a mesma. A forma mais fácil de o fazer é utilizar uma cadeia de ligação, que é criada automaticamente ao criar um espaço de nomes do Service Bus. Se não estiver familiarizado com as políticas de acesso partilhado no Azure, poderá seguir o guia passo a passo para obter uma cadeia de ligação do Service Bus.

Assim que tiver uma cadeia de ligação, pode autenticar o cliente com a mesma.

// Create a ServiceBusClient that will authenticate using a connection string
string connectionString = "<connection_string>";
await using var client = new ServiceBusClient(connectionString);

Para ver como autenticar com o Azure.Identity, veja este exemplo.

Para ver como iniciar a ligação com um ponto final personalizado, veja este exemplo.

ASP.NET Core

Para injetar ServiceBusClient como dependência numa aplicação ASP.NET Core, instale a integração da biblioteca de cliente do Azure para ASP.NET Core pacote.

dotnet add package Microsoft.Extensions.Azure

Em seguida, registe o cliente no Startup.ConfigureServices método :

public void ConfigureServices(IServiceCollection services)
{
    services.AddAzureClients(builder =>
    {
        builder.AddServiceBusClient(Configuration.GetConnectionString("ServiceBus"));
    });
  
    services.AddControllers();
}

Para utilizar o código anterior, adicione-o à sua configuração:

{
  "ConnectionStrings": {
    "ServiceBus": "<connection_string>"
  }
}

Para obter mais detalhes, veja Injeção de dependências com o SDK do Azure para .NET.

Conceitos-chave

Depois de inicializar um ServiceBusClient, pode interagir com os principais tipos de recursos num Espaço de Nomes do Service Bus, dos quais podem existir múltiplos e em que a transmissão real de mensagens ocorre, o espaço de nomes funciona frequentemente como um contentor de aplicações:

  • Fila: permite o envio e a receção de mensagens. Frequentemente utilizado para comunicação ponto a ponto.

  • Tópico: Ao contrário das Filas, os Tópicos são mais adequados para publicar/subscrever cenários. Um tópico pode ser enviado para, mas requer uma subscrição, da qual pode haver vários em paralelo, para consumir.

  • Subscrição: o mecanismo a consumir a partir de um Tópico. Cada subscrição é independente e recebe uma cópia de cada mensagem enviada para o tópico. As regras e filtros podem ser utilizados para personalizar as mensagens recebidas por uma subscrição específica.

Para obter mais informações sobre estes recursos, consulte O que é Azure Service Bus?.

Para interagir com estes recursos, deve estar familiarizado com os seguintes conceitos do SDK:

  • Um cliente do Service Bus é a interface principal para programadores que interagem com a biblioteca de cliente do Service Bus. Funciona como o gateway a partir do qual ocorrerá toda a interação com a biblioteca.

  • Um remetente do Service Bus tem o âmbito de uma fila ou tópico específico e é criado com o cliente do Service Bus. O remetente permite-lhe enviar mensagens para uma fila ou tópico. Também permite que as mensagens de agendamento estejam disponíveis para entrega numa data especificada.

  • Um recetor do Service Bus está no âmbito de uma determinada fila ou subscrição e é criado com o cliente do Service Bus. O recetor permite-lhe receber mensagens de uma fila ou subscrição. Também permite que as mensagens sejam resolvidas depois de as receberem. Existem quatro formas de resolver as mensagens:

    • Concluído – faz com que a mensagem seja eliminada da fila ou tópico.
    • Abandon - liberta o bloqueio do recetor na mensagem, permitindo que a mensagem seja recebida por outros recetores.
    • Diferir – impede que a mensagem seja recebida por meios normais. Para receber mensagens diferidas, o número de sequência da mensagem tem de ser mantido.
    • DeadLetter - move a mensagem para a fila Dead Letter. Isto impedirá que a mensagem seja recebida novamente. Para receber mensagens da fila Carta Não Entregue, é necessário um recetor com o âmbito da fila Carta Não Entregue.
  • Um recetor de sessão do Service Bus está no âmbito de uma determinada fila ou subscrição ativada para sessão e é criado com o cliente do Service Bus. O recetor de sessão é quase idêntico ao recetor padrão, sendo que a diferença é que as operações de gestão de sessões são expostas, que se aplicam apenas a entidades com sessão ativada. Estas operações incluem obter e definir o estado da sessão, bem como renovar os bloqueios de sessão.

  • Um processador do Service Bus está no âmbito de uma determinada fila ou subscrição e é criado com o cliente do Service Bus. O ServiceBusProcessor pode ser considerado como uma abstração em torno de um conjunto de recetores. Utiliza um modelo de chamada de retorno para permitir que o código seja especificado quando uma mensagem é recebida e quando ocorre uma exceção. Oferece a conclusão automática de mensagens processadas, renovação automática de bloqueio de mensagens e execução simultânea de processadores de eventos especificados pelo utilizador. Devido ao conjunto de funcionalidades, deve ser a ferramenta ir para a escrita de aplicações que recebem de entidades do Service Bus. O ServiceBusReceiver é recomendado para cenários mais complexos em que o processador não é capaz de fornecer o controlo detalhado que se pode esperar ao utilizar o ServiceBusReceiver diretamente.

  • Um processador de sessão do Service Bus está no âmbito de uma determinada fila ou subscrição ativada para sessão e é criado com o cliente do Service Bus. O processador de sessão é quase idêntico ao processador padrão, sendo que a diferença é que as operações de gestão de sessões são expostas, que se aplicam apenas a entidades com sessão ativada.

Para obter mais conceitos e debates mais aprofundados, veja: Funcionalidades Avançadas do Service Bus.

Duração do cliente

Os ServiceBusClientremetentes, recetores e processadores são seguros para colocar em cache e utilizar como singleton durante a duração da aplicação, que é a melhor prática quando as mensagens são enviadas ou recebidas regularmente. São responsáveis pela gestão eficiente da utilização de rede, CPU e memória, trabalhando para manter a utilização baixa durante períodos de inatividade.

Estes tipos são descartáveis e chamam DisposeAsync ou CloseAsync são necessários para garantir que os recursos de rede e outros objetos não geridos são devidamente limpos. É importante ter em atenção que, quando uma ServiceBusClient instância é eliminada, fecha e limpa automaticamente todos os remetentes, recetores e processadores que foram criados com a mesma.

Segurança de threads

Garantimos que todos os métodos de instância de cliente são seguros para threads e independentes uns dos outros (orientação). Isto garante que a recomendação de reutilização de instâncias de cliente é sempre segura, mesmo entre threads.

Conceitos adicionais

Opções de | cliente Diagnósticos | A gozar

Exemplos

Enviar e receber uma mensagem

O envio de mensagens é efetuado com o ServiceBusSender. A receção é efetuada com o ServiceBusReceiver.

string connectionString = "<connection_string>";
string queueName = "<queue_name>";
// since ServiceBusClient implements IAsyncDisposable we create it with "await using"
await using var client = new ServiceBusClient(connectionString);

// create the sender
ServiceBusSender sender = client.CreateSender(queueName);

// create a message that we can send. UTF-8 encoding is used when providing a string.
ServiceBusMessage message = new ServiceBusMessage("Hello world!");

// send the message
await sender.SendMessageAsync(message);

// create a receiver that we can use to receive the message
ServiceBusReceiver receiver = client.CreateReceiver(queueName);

// the received message is a different type as it contains some service set properties
ServiceBusReceivedMessage receivedMessage = await receiver.ReceiveMessageAsync();

// get the message body as a string
string body = receivedMessage.Body.ToString();
Console.WriteLine(body);

Enviar um lote de mensagens

Existem duas formas de enviar várias mensagens ao mesmo tempo. A primeira forma de o fazer utiliza o batching seguro. Com o lote seguro, pode criar um ServiceBusMessageBatch objeto, o que lhe permitirá tentar adicionar mensagens uma de cada vez ao lote com o TryAdd método . Se a mensagem não conseguir caber no lote, TryAdd irá devolver falso.

// add the messages that we plan to send to a local queue
Queue<ServiceBusMessage> messages = new Queue<ServiceBusMessage>();
messages.Enqueue(new ServiceBusMessage("First message"));
messages.Enqueue(new ServiceBusMessage("Second message"));
messages.Enqueue(new ServiceBusMessage("Third message"));

// create a message batch that we can send
// total number of messages to be sent to the Service Bus queue
int messageCount = messages.Count;

// while all messages are not sent to the Service Bus queue
while (messages.Count > 0)
{
    // start a new batch
    using ServiceBusMessageBatch messageBatch = await sender.CreateMessageBatchAsync();

    // add the first message to the batch
    if (messageBatch.TryAddMessage(messages.Peek()))
    {
        // dequeue the message from the .NET queue once the message is added to the batch
        messages.Dequeue();
    }
    else
    {
        // if the first message can't fit, then it is too large for the batch
        throw new Exception($"Message {messageCount - messages.Count} is too large and cannot be sent.");
    }

    // add as many messages as possible to the current batch
    while (messages.Count > 0 && messageBatch.TryAddMessage(messages.Peek()))
    {
        // dequeue the message from the .NET queue as it has been added to the batch
        messages.Dequeue();
    }

    // now, send the batch
    await sender.SendMessagesAsync(messageBatch);

    // if there are any remaining messages in the .NET queue, the while loop repeats
}

A segunda forma utiliza a SendMessagesAsync sobrecarga que aceita um IEnumerable de ServiceBusMessage. Com este método, tentaremos ajustar todas as mensagens fornecidas num único lote de mensagens que iremos enviar para o serviço. Se as mensagens forem demasiado grandes para caberem num único lote, a operação gerará uma exceção.

IList<ServiceBusMessage> messages = new List<ServiceBusMessage>();
messages.Add(new ServiceBusMessage("First"));
messages.Add(new ServiceBusMessage("Second"));
// send the messages
await sender.SendMessagesAsync(messages);

Receber um lote de mensagens

// create a receiver that we can use to receive the messages
ServiceBusReceiver receiver = client.CreateReceiver(queueName);

// the received message is a different type as it contains some service set properties
// a batch of messages (maximum of 2 in this case) are received
IReadOnlyList<ServiceBusReceivedMessage> receivedMessages = await receiver.ReceiveMessagesAsync(maxMessages: 2);

// go through each of the messages received
foreach (ServiceBusReceivedMessage receivedMessage in receivedMessages)
{
    // get the message body as a string
    string body = receivedMessage.Body.ToString();
}

Concluir uma mensagem

Para remover uma mensagem de uma fila ou subscrição, podemos chamar o CompleteAsync método.

string connectionString = "<connection_string>";
string queueName = "<queue_name>";
// since ServiceBusClient implements IAsyncDisposable we create it with "await using"
await using var client = new ServiceBusClient(connectionString);

// create the sender
ServiceBusSender sender = client.CreateSender(queueName);

// create a message that we can send
ServiceBusMessage message = new ServiceBusMessage("Hello world!");

// send the message
await sender.SendMessageAsync(message);

// create a receiver that we can use to receive and settle the message
ServiceBusReceiver receiver = client.CreateReceiver(queueName);

// the received message is a different type as it contains some service set properties
ServiceBusReceivedMessage receivedMessage = await receiver.ReceiveMessageAsync();

// complete the message, thereby deleting it from the service
await receiver.CompleteMessageAsync(receivedMessage);

Abandonar uma mensagem

Abandonar uma mensagem liberta o bloqueio do nosso recetor, o que permite que a mensagem seja recebida por este ou outros recetores.

ServiceBusReceivedMessage receivedMessage = await receiver.ReceiveMessageAsync();

// abandon the message, thereby releasing the lock and allowing it to be received again by this or other receivers
await receiver.AbandonMessageAsync(receivedMessage);

Adiar uma mensagem

Adiar uma mensagem impedirá que seja recebida novamente através dos ReceiveMessageAsync métodos ou ReceiveMessagesAsync . Em vez disso, existem métodos separados ReceiveDeferredMessageAsync e ReceiveDeferredMessagesAsync para receber mensagens diferidas.

ServiceBusReceivedMessage receivedMessage = await receiver.ReceiveMessageAsync();

// defer the message, thereby preventing the message from being received again without using
// the received deferred message API.
await receiver.DeferMessageAsync(receivedMessage);

// receive the deferred message by specifying the service set sequence number of the original
// received message
ServiceBusReceivedMessage deferredMessage = await receiver.ReceiveDeferredMessageAsync(receivedMessage.SequenceNumber);

Uma mensagem com uma letra não entregue

As letras não entregues a uma mensagem são semelhantes a diferir, sendo que uma das principais diferenças é que as mensagens serão automaticamente incorretas e enviadas pelo serviço depois de terem sido recebidas um determinado número de vezes. As aplicações podem optar por enviar manualmente mensagens com base nos respetivos requisitos. Quando uma mensagem está sem letras, é realmente movida para uma subconjunta da fila original. Tenha em atenção que o ServiceBusReceiver é utilizado para receber mensagens da subconsulta de letra inativa, independentemente de a fila principal estar ou não ativada para sessão.

ServiceBusReceivedMessage receivedMessage = await receiver.ReceiveMessageAsync();

// Dead-letter the message, thereby preventing the message from being received again without receiving from the dead letter queue.
// We can optionally pass a dead letter reason and dead letter description to further describe the reason for dead-lettering the message.
await receiver.DeadLetterMessageAsync(receivedMessage, "sample reason", "sample description");

// receive the dead lettered message with receiver scoped to the dead letter queue.
ServiceBusReceiver dlqReceiver = client.CreateReceiver(queueName, new ServiceBusReceiverOptions
{
    SubQueue = SubQueue.DeadLetter
});
ServiceBusReceivedMessage dlqMessage = await dlqReceiver.ReceiveMessageAsync();

// The reason and the description that we specified when dead-lettering the message will be available in the received dead letter message.
string reason = dlqMessage.DeadLetterReason;
string description = dlqMessage.DeadLetterErrorDescription;

Para obter mais informações, veja a descrição geral das filas de letras não entregues do ServiceBus.

Utilizar o Processador

O ServiceBusProcessor pode ser considerado como uma abstração em torno de um conjunto de receptores. Utiliza um modelo de chamada de retorno para permitir que o código seja especificado quando uma mensagem é recebida e quando ocorre uma exceção. Oferece a conclusão automática de mensagens processadas, renovação automática do bloqueio de mensagens e execução simultânea de processadores de eventos especificados pelo utilizador. Devido ao conjunto de funcionalidades, deve ser a ferramenta ir para a escrita de aplicações que recebem de entidades do Service Bus. O ServiceBusReceiver é recomendado para cenários mais complexos em que o processador não é capaz de fornecer o controlo detalhado que se pode esperar ao utilizar o ServiceBusReceiver diretamente.

string connectionString = "<connection_string>";
string queueName = "<queue_name>";
// since ServiceBusClient implements IAsyncDisposable we create it with "await using"
await using var client = new ServiceBusClient(connectionString);

// create the sender
ServiceBusSender sender = client.CreateSender(queueName);

// create a set of messages that we can send
ServiceBusMessage[] messages = new ServiceBusMessage[]
{
    new ServiceBusMessage("First"),
    new ServiceBusMessage("Second")
};

// send the message batch
await sender.SendMessagesAsync(messages);

// create the options to use for configuring the processor
var options = new ServiceBusProcessorOptions
{
    // By default or when AutoCompleteMessages is set to true, the processor will complete the message after executing the message handler
    // Set AutoCompleteMessages to false to [settle messages](/azure/service-bus-messaging/message-transfers-locks-settlement#peeklock) on your own.
    // In both cases, if the message handler throws an exception without settling the message, the processor will abandon the message.
    AutoCompleteMessages = false,

    // I can also allow for multi-threading
    MaxConcurrentCalls = 2
};

// create a processor that we can use to process the messages
await using ServiceBusProcessor processor = client.CreateProcessor(queueName, options);

// configure the message and error handler to use
processor.ProcessMessageAsync += MessageHandler;
processor.ProcessErrorAsync += ErrorHandler;

async Task MessageHandler(ProcessMessageEventArgs args)
{
    string body = args.Message.Body.ToString();
    Console.WriteLine(body);

    // we can evaluate application logic and use that to determine how to settle the message.
    await args.CompleteMessageAsync(args.Message);
}

Task ErrorHandler(ProcessErrorEventArgs args)
{
    // the error source tells me at what point in the processing an error occurred
    Console.WriteLine(args.ErrorSource);
    // the fully qualified namespace is available
    Console.WriteLine(args.FullyQualifiedNamespace);
    // as well as the entity path
    Console.WriteLine(args.EntityPath);
    Console.WriteLine(args.Exception.ToString());
    return Task.CompletedTask;
}

// start processing
await processor.StartProcessingAsync();

// since the processing happens in the background, we add a Console.ReadKey to allow the processing to continue until a key is pressed.
Console.ReadKey();

Autenticar com o Azure.Identity

A biblioteca de Identidade do Azure fornece suporte fácil do Azure Active Directory para autenticação.

// Create a ServiceBusClient that will authenticate through Active Directory
string fullyQualifiedNamespace = "yournamespace.servicebus.windows.net";
await using var client = new ServiceBusClient(fullyQualifiedNamespace, new DefaultAzureCredential());

Trabalhar com Sessões

As sessões fornecem um mecanismo para agrupar mensagens relacionadas. Para utilizar sessões, tem de trabalhar com uma entidade com capacidade de sessão.

Resolução de problemas

Veja o Guia de Resolução de Problemas do Service Bus.

Passos seguintes

Para além dos cenários introdutórios discutidos, a biblioteca de cliente Azure Service Bus oferece suporte para cenários adicionais para ajudar a tirar partido do conjunto completo de funcionalidades do serviço Azure Service Bus. Para ajudar a explorar alguns destes cenários, a biblioteca de cliente do Service Bus oferece um projeto de exemplos para servir de ilustração para cenários comuns. Veja os exemplos README para obter detalhes.

Contribuir

Agradecemos todas as contribuições e sugestões para este projeto. A maioria das contribuições requerem que celebre um Contrato de Licença de Contribuição (CLA) no qual se declare que tem o direito de conceder e que, na verdade, concede-nos os direitos para utilizar a sua contribuição. Para mais detalhes, visite https://cla.microsoft.com.

Quando submete um pedido Pull, um bot do CLA determina automaticamente se tem de fornecer um CLA e decorar o PR de forma adequada (por exemplo, etiqueta, comentário). Só tem de seguir as instruções fornecidas pelo bot. Apenas terá de fazer isto uma vez em todos os repositórios com o nosso CLA.

Este projeto adotou o Microsoft Open Source Code of Conduct (Código de Conduta do Microsoft Open Source). Para obter mais informações, consulte as FAQ do Código de Conduta ou o contacto opencode@microsoft.com com quaisquer perguntas ou comentários adicionais.

Consulte o nosso guia de contribuição para obter mais informações.

Impressões