|
| 1 | +# SourceFlow.Cloud.Azure |
| 2 | + |
| 3 | +**Azure cloud integration for distributed command and event processing** |
| 4 | + |
| 5 | +[](https://www.nuget.org/packages/SourceFlow.Cloud.Azure/) |
| 6 | +[](LICENSE) |
| 7 | + |
| 8 | +## Overview |
| 9 | + |
| 10 | +SourceFlow.Cloud.Azure extends the SourceFlow.Net framework with Azure cloud services integration, enabling distributed command and event processing using Azure Service Bus and Azure Key Vault. This package provides production-ready dispatchers, listeners, and configuration for building scalable, cloud-native event-sourced applications. The fluent bus API is identical to the AWS provider — only the backing services change. |
| 11 | + |
| 12 | +**Key Features:** |
| 13 | +- 🚀 Azure Service Bus command dispatching with session-based ordering |
| 14 | +- 📢 Azure Service Bus topic/subscription event publishing with fan-out |
| 15 | +- 🔐 Azure Key Vault envelope encryption for sensitive data |
| 16 | +- ⚙️ Fluent bus configuration API |
| 17 | +- 🔄 Automatic resource provisioning (queues, topics, subscriptions) |
| 18 | +- 📊 Built-in observability and health checks |
| 19 | +- 🧪 Service Bus emulator integration for local development |
| 20 | + |
| 21 | +--- |
| 22 | + |
| 23 | +## Table of Contents |
| 24 | + |
| 25 | +1. [Installation](#installation) |
| 26 | +2. [Quick Start](#quick-start) |
| 27 | +3. [Configuration](#configuration) |
| 28 | +4. [Azure Services](#azure-services) |
| 29 | +5. [Bus Configuration System](#bus-configuration-system) |
| 30 | +6. [Message Encryption](#message-encryption) |
| 31 | +7. [Idempotency](#idempotency) |
| 32 | +8. [Local Development](#local-development) |
| 33 | +9. [Monitoring](#monitoring) |
| 34 | +10. [Best Practices](#best-practices) |
| 35 | + |
| 36 | +--- |
| 37 | + |
| 38 | +## Installation |
| 39 | + |
| 40 | +### NuGet Package |
| 41 | + |
| 42 | +```bash |
| 43 | +dotnet add package SourceFlow.Cloud.Azure |
| 44 | +``` |
| 45 | + |
| 46 | +### Prerequisites |
| 47 | + |
| 48 | +- SourceFlow >= 2.0.0 |
| 49 | +- Azure SDK for .NET (Service Bus, Identity, Key Vault) |
| 50 | +- .NET 8.0, .NET 9.0, or .NET 10.0 |
| 51 | + |
| 52 | +--- |
| 53 | + |
| 54 | +## Quick Start |
| 55 | + |
| 56 | +```csharp |
| 57 | +using SourceFlow.Cloud.Azure; |
| 58 | + |
| 59 | +// Register SourceFlow core |
| 60 | +services.UseSourceFlow(typeof(Program).Assembly); |
| 61 | + |
| 62 | +// Configure Azure cloud messaging |
| 63 | +services.UseSourceFlowAzure( |
| 64 | + options => |
| 65 | + { |
| 66 | + options.ServiceBusConnectionString = configuration["Azure:ServiceBus:ConnectionString"]; |
| 67 | + }, |
| 68 | + bus => bus |
| 69 | + .Send |
| 70 | + .Command<CreateOrderCommand>(q => q.Queue("orders")) |
| 71 | + .Command<ProcessPaymentCommand>(q => q.Queue("payments")) |
| 72 | + .Raise |
| 73 | + .Event<OrderCreatedEvent>(t => t.Topic("order-events")) |
| 74 | + .Event<PaymentProcessedEvent>(t => t.Topic("payment-events")) |
| 75 | + .Listen.To |
| 76 | + .CommandQueue("orders") |
| 77 | + .CommandQueue("payments") |
| 78 | + .Subscribe.To |
| 79 | + .Topic("order-events") |
| 80 | + .Topic("payment-events")); |
| 81 | +``` |
| 82 | + |
| 83 | +This registers Azure dispatchers, configures routing, starts Service Bus listeners, and automatically provisions queues/topics/subscriptions at startup. |
| 84 | + |
| 85 | +### Passwordless authentication |
| 86 | + |
| 87 | +Instead of a connection string, set `SourceFlow:Azure:ServiceBus:FullyQualifiedNamespace` |
| 88 | +(e.g. `myns.servicebus.windows.net`) to authenticate with `DefaultAzureCredential` |
| 89 | +(Managed Identity, Azure CLI, Visual Studio, etc.). |
| 90 | + |
| 91 | +--- |
| 92 | + |
| 93 | +## Configuration |
| 94 | + |
| 95 | +Connection settings are read from configuration when not supplied via options: |
| 96 | + |
| 97 | +| Key | Description | |
| 98 | +| --- | --- | |
| 99 | +| `SourceFlow:Azure:ServiceBus:ConnectionString` | Service Bus connection string | |
| 100 | +| `SourceFlow:Azure:ServiceBus:FullyQualifiedNamespace` | Namespace for Managed Identity auth | |
| 101 | + |
| 102 | +| Option | Type | Default | Description | |
| 103 | +| --- | --- | --- | --- | |
| 104 | +| `ServiceBusConnectionString` | string | null | Service Bus connection string | |
| 105 | +| `EnableCommandRouting` | bool | true | Enable command dispatching to queues | |
| 106 | +| `EnableEventRouting` | bool | true | Enable event publishing to topics | |
| 107 | +| `EnableCommandListener` | bool | true | Enable queue command processors | |
| 108 | +| `EnableEventListener` | bool | true | Enable topic subscription processors | |
| 109 | + |
| 110 | +--- |
| 111 | + |
| 112 | +## Azure Services |
| 113 | + |
| 114 | +- **Azure Service Bus queues** — command dispatching with `SessionId` (entity id) for |
| 115 | + strict FIFO ordering per entity, optional duplicate detection, and dead-letter queues. |
| 116 | +- **Azure Service Bus topics/subscriptions** — event publishing with fan-out to multiple |
| 117 | + subscriptions; subscriptions forward to the listening command queue. |
| 118 | +- **Azure Key Vault** — envelope encryption keys for message payload protection. |
| 119 | + |
| 120 | +--- |
| 121 | + |
| 122 | +## Bus Configuration System |
| 123 | + |
| 124 | +The fluent `BusConfigurationBuilder` is shared with the rest of SourceFlow.Net: |
| 125 | + |
| 126 | +```csharp |
| 127 | +bus => bus |
| 128 | + .Send.Command<CreateOrderCommand>(q => q.Queue("orders")) |
| 129 | + .Raise.Event<OrderCreatedEvent>(t => t.Topic("order-events")) |
| 130 | + .Listen.To.CommandQueue("orders") |
| 131 | + .Subscribe.To.Topic("order-events"); |
| 132 | +``` |
| 133 | + |
| 134 | +--- |
| 135 | + |
| 136 | +## Message Encryption |
| 137 | + |
| 138 | +Enable envelope encryption for sensitive message payloads backed by Azure Key Vault: |
| 139 | + |
| 140 | +```csharp |
| 141 | +services.AddSingleton<IMessageEncryption>(sp => |
| 142 | + new AzureKeyVaultMessageEncryption( |
| 143 | + keyVaultUrl: "https://my-vault.vault.azure.net/", |
| 144 | + keyName: "sourceflow-key", |
| 145 | + credential: new DefaultAzureCredential())); |
| 146 | + |
| 147 | +services.UseSourceFlowAzure(options => ..., bus => ...); |
| 148 | +``` |
| 149 | + |
| 150 | +**Encryption flow:** Generate data key → Encrypt message with AES-GCM (data key) → |
| 151 | +Wrap data key with the Key Vault master key → Store in the Service Bus message. |
| 152 | + |
| 153 | +--- |
| 154 | + |
| 155 | +## Idempotency |
| 156 | + |
| 157 | +- **In-memory (single instance)** — registered by default as a singleton with a background |
| 158 | + cleanup service. Suitable for single-instance deployments. |
| 159 | +- **SQL-based (multi-instance / production)** — install `SourceFlow.Stores.EntityFramework` |
| 160 | + and call `services.AddSourceFlowIdempotency(connectionString, cleanupIntervalMinutes)` |
| 161 | + before `UseSourceFlowAzure(...)`. |
| 162 | + |
| 163 | +> ⚠️ Always use SQL-based idempotency for multi-instance deployments — the in-memory store |
| 164 | +> lives in a single process and is insufficient for distributed systems. |
| 165 | +
|
| 166 | +--- |
| 167 | + |
| 168 | +## Local Development |
| 169 | + |
| 170 | +Azurite emulates Blob/Queue/Table storage but **not** Service Bus. For local development and |
| 171 | +CI, use the official Azure Service Bus emulator (backed by SQL Edge), declaring your entities |
| 172 | +up front in its `Config.json`: |
| 173 | + |
| 174 | +```bash |
| 175 | +docker compose -f .github/azure-emulator/docker-compose.yml up -d |
| 176 | + |
| 177 | +export AZURE_SERVICEBUS_CONNECTION_STRING="Endpoint=sb://localhost;\ |
| 178 | +SharedAccessKeyName=RootManageSharedAccessKey;\ |
| 179 | +SharedAccessKey=SAS_KEY_VALUE;UseDevelopmentEmulator=true" |
| 180 | +``` |
| 181 | + |
| 182 | +The emulator serves only entities declared in `Config.json` (no runtime creation) and caps |
| 183 | +total queues + topics at 50. |
| 184 | + |
| 185 | +--- |
| 186 | + |
| 187 | +## Monitoring |
| 188 | + |
| 189 | +- **Activity Source:** `SourceFlow.Cloud.Azure` |
| 190 | +- **Health check:** registered automatically as `azure-servicebus` (tags: `azure`, |
| 191 | + `servicebus`, `messaging`), covering namespace connectivity, queue/topic existence, and |
| 192 | + Key Vault access when encryption is enabled. |
| 193 | +- Trace context is propagated via the Service Bus message `ApplicationProperties` |
| 194 | + (`traceparent`) for end-to-end distributed tracing. |
| 195 | + |
| 196 | +--- |
| 197 | + |
| 198 | +## Best Practices |
| 199 | + |
| 200 | +- Use sessions for ordered operations (the dispatcher sets `SessionId` = entity id). |
| 201 | +- Enable duplicate detection on queues fed by at-least-once producers. |
| 202 | +- Group related commands to the same queue (`CreateOrder`, `UpdateOrder`, `CancelOrder` → `orders`). |
| 203 | +- Enable SQL-based idempotency in production. |
| 204 | +- Prefer Managed Identity (`FullyQualifiedNamespace` + RBAC) over connection strings. |
| 205 | +- Enable Key Vault encryption for PII, financial, or health data. |
| 206 | +- Use IaC (Bicep/Terraform) for production resources; the bootstrapper is for dev convenience. |
| 207 | +- Monitor health checks and dead-letter queue depth. |
| 208 | + |
| 209 | +--- |
| 210 | + |
| 211 | +## License |
| 212 | + |
| 213 | +MIT — see [LICENSE](LICENSE). |
0 commit comments