Overview
Savvyio.Extensions.DependencyInjection.QueueStorage registers Savvyio messaging channels for Azure Queue Storage and Azure Event Grid in IServiceCollection. Its two entry points add a command queue and an integration event bus, and each has a marker-based variant so multiple Azure-backed channels can coexist in the same container.
The package builds on Savvyio.Extensions.DependencyInjection for Microsoft Dependency Injection registration and on Savvyio.Extensions.QueueStorage for the transport implementations themselves. The package-owned types mainly add DI marker interfaces and marker-specific option types so the lower-level Azure queue and event bus implementations can be resolved in a strongly typed way.
Key APIs
AddAzureCommandQueue registers Savvyio.Extensions.QueueStorage.Commands.AzureCommandQueue as the unmarked command queue implementation. Source and tests show it forwards the registration to IPointToPointChannel<ICommand>, ISender<ICommand>, and IReceiver<ICommand>, applies the supplied Action<AzureQueueOptions>, and defaults the service lifetime to singleton unless serviceSetup overrides it.
AddAzureCommandQueue<TMarker> registers the marker-specific AzureCommandQueue<TMarker> wrapper for applications that need more than one command queue registration. Tests verify that the marked queue resolves through IPointToPointChannel<ICommand, TMarker>, ISender<ICommand, TMarker>, and IReceiver<ICommand, TMarker> and that the supplied Action<AzureQueueOptions<TMarker>> is preserved in DI.
AddAzureEventBus registers Savvyio.Extensions.QueueStorage.EventDriven.AzureEventBus as the unmarked publish-subscribe channel for IIntegrationEvent. Tests show that it forwards to IPublishSubscribeChannel<IIntegrationEvent>, IPublisher<IIntegrationEvent>, and ISubscriber<IIntegrationEvent> while storing both the queue setup and the event bus setup in DI.
AddAzureEventBus<TMarker> registers the marker-specific AzureEventBus<TMarker> wrapper when you want an Azure Event Grid plus Azure Queue Storage bus isolated behind a marker type. Like the unmarked overload, it defaults to singleton lifetime and captures both Action<AzureQueueOptions<TMarker>> and Action<AzureEventBusOptions<TMarker>> as configured options.
AzureQueueOptions<TMarker> is the marker-bearing subclass of Savvyio.Extensions.QueueStorage.AzureQueueOptions. Use it when queue settings such as StorageAccountName, QueueName, credentials, and send or receive contexts need to be scoped to a specific DI marker instead of shared across all registrations.
AzureEventBusOptions<TMarker> is the marker-bearing subclass of Savvyio.Extensions.QueueStorage.EventDriven.AzureEventBusOptions. It carries the Event Grid specific configuration, including TopicEndpoint, credentials, and publisher client settings, for a single marked bus registration.
AzureCommandQueue<TMarker> is the concrete DI-optimized queue type behind the marked command registration. Its constructor takes an IMarshaller and AzureQueueOptions<TMarker> and surfaces the lower-level Azure Storage Queue implementation through the marker-specific point-to-point abstractions.
AzureEventBus<TMarker> is the concrete DI-optimized bus type behind the marked event registration. Its constructor takes an IMarshaller, AzureQueueOptions<TMarker>, and AzureEventBusOptions<TMarker> and exposes the lower-level Azure Event Grid plus Azure Queue Storage implementation through IPublishSubscribeChannel<IIntegrationEvent, TMarker>.
Basic usage
using System;
using System.IO;
using Codebelt.Extensions.Xunit;
using Microsoft.Extensions.DependencyInjection;
using Savvyio;
using Savvyio.EventDriven;
using Savvyio.Extensions.DependencyInjection.Messaging;
using Savvyio.Extensions.DependencyInjection.QueueStorage;
using Savvyio.Extensions.DependencyInjection.QueueStorage.EventDriven;
using Xunit;
namespace MyProject.Tests;
public sealed class PaymentsBusRegistrationTest : Test
{
public PaymentsBusRegistrationTest(ITestOutputHelper output) : base(output) { }
[Fact]
public void AddAzureEventBus_WithMarker_ResolvesMarkedBusAndConfiguredOptions()
{
var services = new ServiceCollection();
services.AddSingleton<IMarshaller, StubMarshaller>();
services.AddAzureEventBus<PaymentsBus>(
queue => { queue.StorageAccountName = "acmestorage"; queue.QueueName = "payments"; },
bus => bus.TopicEndpoint = new Uri("https://events.example.com"));
using var provider = services.BuildServiceProvider();
var channel = provider.GetRequiredService<IPublishSubscribeChannel<IIntegrationEvent, PaymentsBus>>();
var queueOptions = provider.GetRequiredService<AzureQueueOptions<PaymentsBus>>();
var busOptions = provider.GetRequiredService<AzureEventBusOptions<PaymentsBus>>();
TestOutput.WriteLine($"Resolved {channel.GetType().Name} for queue '{queueOptions.QueueName}' and topic '{busOptions.TopicEndpoint}'.");
Assert.IsType<AzureEventBus<PaymentsBus>>(channel);
Assert.Equal("payments", queueOptions.QueueName);
Assert.Equal(new Uri("https://events.example.com"), busOptions.TopicEndpoint);
}
private readonly struct PaymentsBus { }
private sealed class StubMarshaller : IMarshaller
{
public Stream Serialize<TValue>(TValue value) => new MemoryStream();
public Stream Serialize(object value, Type inputType) => new MemoryStream();
public TValue Deserialize<TValue>(Stream data) => throw new NotSupportedException();
public object Deserialize(Stream data, Type returnType) => throw new NotSupportedException();
}
}
Use this pattern when your application resolves Azure-backed event buses through Microsoft Dependency Injection and you need marker-based separation between channel registrations. It matters because the package turns the lower-level Queue Storage and Event Grid transport into a strongly typed DI registration with validated queue and topic options.
Installation
dotnet add package Savvyio.Extensions.DependencyInjection.QueueStorage
Usage guidance
Adopt this package when you already use Savvyio with Microsoft Dependency Injection and want command or integration event channels backed by Azure Queue Storage and Azure Event Grid, especially when marker types help keep multiple registrations distinct. If you only need the transport implementation itself, or you prefer to work directly with Azure SDK clients and your own container wiring, Savvyio.Extensions.QueueStorage or the Azure SDK is the better fit.
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.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.QueueStorage
- 📦Savvyio.Extensions.RabbitMQ
- 📦Savvyio.Extensions.SimpleQueueService
- 📝Savvyio.Extensions.Text.Json
- 📦Savvyio.Messaging
- 📦Savvyio.Queries