A simplified, modern .NET client library for Azure Queue Storage with comprehensive message operations and intuitive APIs. This library provides an easy-to-use wrapper around Azure.Storage.Queues SDK with support for sending, receiving, peeking, updating, and deleting messages. Features include text and binary message support, configurable visibility timeouts, message TTL management, batch operations, and reliable message processing patterns. Perfect for building asynchronous, decoupled applications with background job processing, task queuing, and inter-service communication. Includes built-in error handling, poison message detection, and dequeue count tracking. Compatible with .NET Standard 2.0+, .NET 7, 8, and 9. Ideal for microservices architectures, distributed systems, and cloud-native applications requiring reliable message queuing.
$ dotnet add package AzureStorage.Standard.QueuesA simplified, modern .NET client library for Azure Queue Storage with built-in error handling and intuitive APIs for managing queues and messages.
Simplified API - Easy-to-use wrapper around Azure.Storage.Queues SDK Queue Management - Create, delete, and list queues Message Operations - Send, receive, peek, update, and delete messages Binary Support - Send/receive both text and binary messages Batch Operations - Send multiple messages efficiently Visibility Timeout - Control message processing windows Message TTL - Configure message expiration Pop Receipts - Update and delete messages safely Comprehensive Error Handling - Detailed exception information Extensive Documentation - Full XML documentation for IntelliSense
dotnet add package AzureStorage.Standard.Queues
Or via Package Manager Console:
Install-Package AzureStorage.Standard.Queues
using AzureStorage.Standard.Queues;
using AzureStorage.Standard.Core;
var options = new StorageOptions
{
ConnectionString = "DefaultEndpointsProtocol=https;AccountName=..."
};
var queueClient = new QueueClient(options);
await queueClient.CreateQueueIfNotExistsAsync("orders");
// Send a text message
await queueClient.SendMessageAsync(
queueName: "orders",
message: "Process order #12345"
);
// Send with visibility timeout (delay processing)
await queueClient.SendMessageAsync(
queueName: "orders",
message: "Delayed order",
visibilityTimeout: TimeSpan.FromMinutes(5)
);
// Send with time-to-live
await queueClient.SendMessageAsync(
queueName: "orders",
message: "Expiring order",
timeToLive: TimeSpan.FromHours(1)
);
// Receive a single message
var messages = await queueClient.ReceiveMessagesAsync(
queueName: "orders",
maxMessages: 1
);
foreach (var message in messages)
{
Console.WriteLine($"Message: {message.MessageText}");
// Process the message...
// Delete after processing
await queueClient.DeleteMessageAsync(
queueName: "orders",
messageId: message.MessageId,
popReceipt: message.PopReceipt
);
}
// Preview messages without removing them
var peekedMessages = await queueClient.PeekMessagesAsync(
queueName: "orders",
maxMessages: 10
);
foreach (var message in peekedMessages)
{
Console.WriteLine($"Peeked: {message.MessageText}");
}
// Send binary data
byte[] imageData = File.ReadAllBytes("image.jpg");
await queueClient.SendMessageAsync("images", imageData);
// Receive binary data
var messages = await queueClient.ReceiveMessagesAsync("images");
foreach (var message in messages)
{
byte[] data = message.MessageBytes;
// Process binary data...
}
var messages = new List<string>
{
"Order #001",
"Order #002",
"Order #003"
};
await queueClient.SendMessagesAsync("orders", messages);
var messages = await queueClient.ReceiveMessagesAsync("orders", maxMessages: 1);
var message = messages.First();
// Need more time to process? Update the visibility timeout
var updatedMessage = await queueClient.UpdateMessageAsync(
queueName: "orders",
messageId: message.MessageId,
popReceipt: message.PopReceipt,
message: message.MessageText, // Can also update content
visibilityTimeout: TimeSpan.FromMinutes(5) // Extend processing time
);
// Use the new pop receipt for subsequent operations
await queueClient.DeleteMessageAsync(
queueName: "orders",
messageId: updatedMessage.MessageId,
popReceipt: updatedMessage.PopReceipt
);
// Receive up to 32 messages at once
var messages = await queueClient.ReceiveMessagesAsync(
queueName: "orders",
maxMessages: 32,
visibilityTimeout: TimeSpan.FromMinutes(2)
);
int messageCount = await queueClient.GetMessageCountAsync("orders");
Console.WriteLine($"Approximate message count: {messageCount}");
// Warning: Permanently deletes all messages!
await queueClient.ClearMessagesAsync("orders");
// List all queues
var queues = await queueClient.ListQueuesAsync();
foreach (var queue in queues)
{
Console.WriteLine($"Queue: {queue}");
}
// Check if queue exists
bool exists = await queueClient.QueueExistsAsync("orders");
// Delete queue
await queueClient.DeleteQueueAsync("orders");
var options = new StorageOptions
{
ConnectionString = "DefaultEndpointsProtocol=https;AccountName=myaccount;AccountKey=..."
};
var options = new StorageOptions
{
AccountName = "myaccount",
AccountKey = "your-account-key"
};
var options = new StorageOptions
{
ServiceUri = new Uri("https://myaccount.queue.core.windows.net")
};
// Reliable message processing pattern
while (true)
{
var messages = await queueClient.ReceiveMessagesAsync(
queueName: "orders",
maxMessages: 10,
visibilityTimeout: TimeSpan.FromMinutes(2)
);
if (!messages.Any())
{
await Task.Delay(TimeSpan.FromSeconds(5));
continue;
}
foreach (var message in messages)
{
try
{
// Process message
await ProcessOrderAsync(message.MessageText);
// Delete if successful
await queueClient.DeleteMessageAsync(
"orders",
message.MessageId,
message.PopReceipt
);
}
catch (Exception ex)
{
Console.WriteLine($"Failed to process message: {ex.Message}");
// Message will become visible again after visibility timeout
}
}
}
Messages can be up to 64 KB in size:
// For larger data, store in Blob Storage and send URL
var blobUrl = await UploadToBlobAsync(largeData);
await queueClient.SendMessageAsync("orders", blobUrl);
Set appropriate timeouts based on processing time:
// Short-lived tasks
visibilityTimeout: TimeSpan.FromSeconds(30)
// Long-running tasks
visibilityTimeout: TimeSpan.FromMinutes(10)
Track processed messages to avoid duplicates:
if (message.DequeueCount > 1)
{
// Message has been processed before - check if already handled
if (await IsAlreadyProcessedAsync(message.MessageId))
{
await queueClient.DeleteMessageAsync("orders", message.MessageId, message.PopReceipt);
continue;
}
}
Handle messages that fail repeatedly:
if (message.DequeueCount > 5)
{
// Move to dead-letter queue or log for investigation
await queueClient.SendMessageAsync("orders-poison", message.MessageText);
await queueClient.DeleteMessageAsync("orders", message.MessageId, message.PopReceipt);
}
// Valid names
"orders"
"order-processing-queue"
"queue123"
// Invalid names
"Orders" // uppercase not allowed
"or" // too short
"order--queue" // consecutive hyphens
try
{
await queueClient.SendMessageAsync("orders", "New order");
}
catch (AzureStorageException ex)
{
Console.WriteLine($"Error: {ex.Message}");
Console.WriteLine($"Error Code: {ex.ErrorCode}");
Console.WriteLine($"Status Code: {ex.StatusCode}");
}
For complete documentation, visit the GitHub repository.
This project is licensed under the MIT License - see the LICENSE file for details.
Contributions are welcome! Please feel free to submit a Pull Request.
For issues, questions, or suggestions, please open an issue on GitHub.