Overview
Savvyio.Extensions.QueueStorage adds Azure-backed transport implementations to Savvyio's messaging model. AzureCommandQueue maps command delivery to Azure Queue Storage, and AzureEventBus combines Azure Event Grid publishing with Azure Queue Storage subscription for integration events.
The package focuses on transport behavior and Azure-specific configuration. You supply an IMarshaller for message serialization, and companion packages can add serializer implementations and Microsoft.Extensions.DependencyInjection registration.
Key APIs
AzureQueue<TRequest> is the abstract base for Azure-backed transports. Its protected constructors either build QueueServiceClient and QueueClient from AzureQueueOptions or accept testable Azure clients directly, and derived types use SendMessageAsync and ReceiveMessagesAsync while queue deletion is tied to message acknowledgement.
AzureQueueOptions configures queue naming, authentication, QueueClientOptions, and the send and receive contexts used by AzureQueue<TRequest>. PostConfigureClient(Action<QueueClient>) lets you run final client setup after the queue client has been created, and ValidateOptions() enforces connection-string queue naming, the presence of some Azure credential path, and rejects the case where both the storage account name and queue name are missing.
AzureQueueReceiveOptions controls batch receive behavior for Azure Queue Storage. It defaults to 10 messages and a 30 second visibility timeout, clamps the batch size to 1..32, and clamps visibility timeout to the Azure-supported 1 second..7 days range.
AzureQueueSendOptions controls outbound queue timing. It defaults to a 7 day time-to-live and immediate visibility, while clamping visibility timeout to the Azure-supported 0..7 days range.
AzureCommandQueue implements IPointToPointChannel<ICommand> on Azure Queue Storage. SendAsync(...) serializes and enqueues command messages, ReceiveAsync(...) returns them as IAsyncEnumerable<IMessage<ICommand>>, and GetHealthCheckTarget() exposes the underlying QueueServiceClient for health probing.
AzureEventBus implements IPublishSubscribeChannel<IIntegrationEvent> across Azure Event Grid and Azure Queue Storage. PublishAsync(...) converts a message to a CloudEvent, carries over the signature when the message implements ISignedMessage<IIntegrationEvent>, adds the typeext extension attribute, and sends the event through EventGridPublisherClient, while SubscribeAsync(...) keeps draining queue batches until none remain and passes each message to the supplied asynchronous handler.
AzureEventBusOptions configures the Event Grid topic endpoint, credential choice, and EventGridPublisherClientOptions. Setting TokenCredential, AzureKeyCredential, or AzureSasCredential clears the other authentication choices, and ValidateOptions() requires both a topic endpoint and at least one credential type.
Basic usage
using System;
using System.IO;
using Codebelt.Extensions.Xunit;
using Savvyio;
using Savvyio.Extensions.QueueStorage;
using Savvyio.Extensions.QueueStorage.Commands;
using Xunit;
namespace MyProject.Tests;
public class AzureCommandQueueFacts : Test
{
public AzureCommandQueueFacts(ITestOutputHelper output) : base(output)
{
}
[Fact]
public void Constructor_PostConfigureClient_RunsCallback()
{
var clientConfigured = false;
var options = new AzureQueueOptions
{
StorageAccountName = "contoso",
QueueName = "members"
}.PostConfigureClient(_ => clientConfigured = true);
var sut = new AzureCommandQueue(new StubMarshaller(), options);
TestOutput.WriteLine($"Client configured: {clientConfigured}");
Assert.True(clientConfigured);
Assert.NotNull(sut.GetHealthCheckTarget());
}
private sealed class StubMarshaller : IMarshaller
{
public Stream Serialize<TValue>(TValue value) => throw new NotSupportedException();
public Stream Serialize(object value, Type inputType) => throw new NotSupportedException();
public TValue Deserialize<TValue>(Stream data) => throw new NotSupportedException();
public object Deserialize(Stream data, Type returnType) => throw new NotSupportedException();
}
}
Use this pattern when you want to validate queue transport construction or run queue-client setup logic before the transport is added to a host. It matters because PostConfigureClient(...) is the package hook for last-mile queue client initialization, and AzureCommandQueue fails fast when its Azure options are not valid.
Installation
dotnet add package Savvyio.Extensions.QueueStorage
Usage guidance
Adopt this package when your Savvyio application needs Azure Queue Storage for point-to-point commands or Azure Event Grid plus Azure Queue Storage for integration-event delivery, and you want those transports behind IPointToPointChannel<ICommand> or IPublishSubscribeChannel<IIntegrationEvent>. If you only need raw Azure SDK clients or Microsoft.Extensions.DependencyInjection registration, use the Azure SDK directly or pair this package with Savvyio.Extensions.DependencyInjection.QueueStorage and a companion marshaller package instead.
Family packages
- 🏭Savvyio.App
- 📦Savvyio.Commands
- 📦Savvyio.Commands.Messaging
- 📦Savvyio.Core
- 📦Savvyio.Domain
- 📦Savvyio.Domain.EventSourcing
- 📦Savvyio.EventDriven
- 📦Savvyio.EventDriven.Messaging
- 📦Savvyio.Extensions.Dapper
- 📦Savvyio.Extensions.DapperExtensions
- 📦Savvyio.Extensions.DependencyInjection
- 📦Savvyio.Extensions.DependencyInjection.Dapper
- 📦Savvyio.Extensions.DependencyInjection.DapperExtensions
- 📦Savvyio.Extensions.DependencyInjection.Domain
- 📦Savvyio.Extensions.DependencyInjection.EFCore
- 📦Savvyio.Extensions.DependencyInjection.EFCore.Domain
- 📦Savvyio.Extensions.DependencyInjection.EFCore.Domain.EventSourcing
- 📦Savvyio.Extensions.DependencyInjection.NATS
- 📝Savvyio.Extensions.DependencyInjection.Newtonsoft.Json
- 📦Savvyio.Extensions.DependencyInjection.QueueStorage
- 📦Savvyio.Extensions.DependencyInjection.RabbitMQ
- 📦Savvyio.Extensions.DependencyInjection.SimpleQueueService
- 📝Savvyio.Extensions.DependencyInjection.Text.Json
- 📦Savvyio.Extensions.Dispatchers
- 📦Savvyio.Extensions.EFCore
- 📦Savvyio.Extensions.EFCore.Domain
- 📦Savvyio.Extensions.EFCore.Domain.EventSourcing
- 📦Savvyio.Extensions.NATS
- 📝Savvyio.Extensions.Newtonsoft.Json
- 📦Savvyio.Extensions.RabbitMQ
- 📦Savvyio.Extensions.SimpleQueueService
- 📝Savvyio.Extensions.Text.Json
- 📦Savvyio.Messaging
- 📦Savvyio.Queries