Akaule.NimBus.MessageStore.SqlServer
3.0.0
dotnet add package Akaule.NimBus.MessageStore.SqlServer --version 3.0.0
NuGet\Install-Package Akaule.NimBus.MessageStore.SqlServer -Version 3.0.0
<PackageReference Include="Akaule.NimBus.MessageStore.SqlServer" Version="3.0.0" />
<PackageVersion Include="Akaule.NimBus.MessageStore.SqlServer" Version="3.0.0" />
<PackageReference Include="Akaule.NimBus.MessageStore.SqlServer" />
paket add Akaule.NimBus.MessageStore.SqlServer --version 3.0.0
#r "nuget: Akaule.NimBus.MessageStore.SqlServer, 3.0.0"
#:package Akaule.NimBus.MessageStore.SqlServer@3.0.0
#addin nuget:?package=Akaule.NimBus.MessageStore.SqlServer&version=3.0.0
#tool nuget:?package=Akaule.NimBus.MessageStore.SqlServer&version=3.0.0
NimBus
A nimbus for your Azure cloud — ordered, audited, and always accounted for.
NimBus is an Azure Service Bus based integration platform with a shared SDK, management web app, and message tracking and storage.
Repository Layout
src/NimBus.slnbuilds the full platform, including the web app, resolver, app host, and shared libraries.
Key projects:
src/NimBus.Abstractions: core interfaces (IMessage,ISender,IEventHandler, message context).src/NimBus.Core: shared endpoint, event, message, and pipeline abstractions.src/NimBus: platform configuration and built-in endpoint definitions.src/NimBus.CommandLine:nbCLI for Azure infrastructure, topology provisioning, and deployment.src/NimBus.SDK: publisher/subscriber SDK surface.src/NimBus.ServiceBus: Service Bus integration layer.src/NimBus.MessageStore.Abstractions: provider-neutral storage contracts (IMessageTrackingStore,ISubscriptionStore,IEndpointMetadataStore,IMetricsStore).src/NimBus.MessageStore.CosmosDb: Cosmos DB storage provider.src/NimBus.MessageStore.SqlServer: SQL Server storage provider (DbUp-managed schema).src/NimBus.Manager/src/NimBus.Management.ServiceBus: management client abstractions and Service Bus management operations used by the web app.src/NimBus.WebApp: ASP.NET Core management UI plus the React/Vite client app.src/NimBus.Resolver: tracks message outcomes and updates resolver state.src/NimBus.AppHost/src/NimBus.ServiceDefaults: Aspire host and shared defaults for local orchestration.src/NimBus.Testing: in-memory transport plus the storage conformance suite that all message-store providers run against.src/NimBus.Outbox.SqlServer: SQL Server transactional outbox implementation.src/NimBus.Inbox.SqlServer: SQL Server consumer inbox implementation.
Samples live under samples/:
samples/AspirePubSub/: minimal publisher, subscriber (with middleware + DeferredProcessor), provisioner, and resolver worker.samples/CrmErpDemo/: two-system CRM ↔ ERP integration demo — see the CRM/ERP sample section below.
Message Store
The audit trail, resolver state, blocked sessions, and metrics live behind the contracts in NimBus.MessageStore.Abstractions and are pluggable across providers. Pick the one that fits your environment; both pass the same NimBus.Testing conformance suite.
| Provider | Project | Registration | Notes |
|---|---|---|---|
| SQL Server | NimBus.MessageStore.SqlServer |
services.AddSqlServerMessageStore(...) |
Schema is owned and migrated by DbUp on first run. Ships the nimbus.Messages, UnresolvedEvents, MessageAudits, EndpointSubscriptions, EndpointMetadata, Heartbeats, BlockedMessages, InvalidMessages tables plus metrics views. |
| Cosmos DB | NimBus.MessageStore.CosmosDb |
services.AddCosmosDbMessageStore(...) |
Per-endpoint containers (see ADR-008). |
The Aspire AppHost and the CRM/ERP demo both default to SQL Server and accept --StorageProvider cosmos to switch. The transactional outbox (NimBus.Outbox.SqlServer) is independent of the message-store choice.
Transport
Azure Service Bus is NimBus's transport. The platform leans on Service Bus's native primitives (sessions, deferred messages, scheduled enqueue, forwarding subscriptions, dead-letter queues) rather than abstracting them away.
| Provider | Project | Registration | Notes |
|---|---|---|---|
| Azure Service Bus | NimBus.ServiceBus |
services.AddNimBus(b => b.AddServiceBusTransport(...)) |
Native sessions, deferred messages, scheduled enqueue, forwarding subscriptions, dead-letter queue. |
Extensions
NimBus uses an extension framework to separate core messaging from optional features. Extensions are registered through the AddNimBus() builder and can hook into the message pipeline and lifecycle events.
src/NimBus.Extensions.Notifications: sends notifications on message failures and dead-letters.
See docs/extensions.md for the full guide on using and creating extensions.
Building an Adapter
A NimBus adapter is a worker process that sits between an external system and the event bus — it subscribes to events from other systems, publishes events when its own backing system changes, or both. Most consumers of NimBus are writing adapters.
Four questions decide how the wiring looks:
- Subscribe, publish, or both? Subscribers register handlers via
AddNimBusSubscriber+AddNimBusReceiver. Publishers registerAddNimBusPublisher. - Long-running Worker or Azure Functions? Worker = simple, in-process, easy to debug (
samples/CrmErpDemo/Crm.Adapter). Functions = serverless, native session triggers (samples/CrmErpDemo/Erp.Adapter.Functions). - Direct publish or SQL Server outbox? Direct = stateless. Outbox = atomic with local DB writes via
AddNimBusSqlServerOutbox. - Aspire or manual
ServiceBusClient?builder.AddAzureServiceBusClient("servicebus")for Aspire; manualAddSingleton<ServiceBusClient>for Functions and other hosts.
The minimum viable subscriber is small — IDeferredMessageProcessor is auto-registered by AddNimBusSubscriber, so the floor really is this:
var builder = Host.CreateApplicationBuilder(args);
builder.AddServiceDefaults();
builder.AddAzureServiceBusClient("servicebus");
builder.Services.AddNimBusSubscriber("BillingEndpoint", sub =>
{
sub.AddHandlersFromAssemblyContaining<OrderPlacedHandler>();
});
builder.Services.AddNimBusReceiver(opts =>
{
opts.TopicName = "BillingEndpoint";
opts.SubscriptionName = "BillingEndpoint";
});
builder.Build().Run();
Add builder.Services.AddNimBus(n => n.AddPipelineBehavior<LoggingMiddleware>()) when you want middleware in the pipeline.
Use sub.AddHandler<OrderPlaced, OrderPlacedHandler>() when you want to register or override a handler explicitly.
Next steps:
- Building Adapters — full guide: publisher, subscriber, middleware (built-in + custom), retry policies, outbox, hosting choice
- Getting Started — end-to-end tutorial including Aspire local dev
- SDK API Reference —
IPublisherClient,IEventHandler<T>,RetryPolicy,IOutbox, request/response
NuGet Packages
| Package | Description |
|---|---|
NimBus.Abstractions |
Core abstractions and interfaces |
NimBus.Core |
Endpoint management, retry policies, logging |
NimBus.ServiceBus |
Azure Service Bus integration |
NimBus.SDK |
Publisher/subscriber SDK |
NimBus.CommandLine |
nb CLI tool |
Install
Packages publish under the Akaule.NimBus.* prefix (the bare NimBus.* prefix is
reserved on nuget.org); assemblies and namespaces stay NimBus.*:
dotnet add package Akaule.NimBus.SDK
dotnet tool install -g Akaule.NimBus.CommandLine
Publishing
Push a version tag to trigger the NuGet publish workflow:
git tag v1.0.0
git push origin v1.0.0
Pre-release versions are supported (e.g. v1.0.0-preview.1).
Prerequisites
- .NET 10 SDK preview, matching the project target frameworks.
- Node.js 22+ (LTS), required by
src/NimBus.WebApp/ClientAppand thesamples/CrmErpDemo/Crm.Web/Erp.WebSPAs during build. Vite 8 and Vitest 4 are the minimum supported toolchain; older Node versions will fail atnpm install. - Access to NuGet package sources used by the solution.
Build
From the repository root:
dotnet build .\src\NimBus.CommandLine\NimBus.CommandLine.csproj
dotnet build .\src\NimBus.sln
Notes:
src/NimBus.WebApprunsnpm installandnpm run buildas part of the .NET build.NSwag.MSBuildis used directly from NuGet; no localdotnet-tools.jsonmanifest is required.
CLI
The repository includes a dotnet tool named nb in src/NimBus.CommandLine.
It handles Azure infrastructure provisioning, Service Bus topology setup, and application deployment.
Prerequisites
- Azure CLI (
az) ≥ 2.60.0 installed and onPATH(required for Flex Consumption deploys; see docs/deployment.md) az logincompleted for the target subscription- Permissions to create and deploy resources in the target resource group
Running the tool
Run via dotnet run from the repository root:
dotnet run --project .\src\NimBus.CommandLine -- <command> [options]
Alternatively, install it as a local dotnet tool:
dotnet pack .\src\NimBus.CommandLine
dotnet tool install --global --add-source .\src\NimBus.CommandLine\nupkg Akaule.NimBus.CommandLine
nb <command> [options]
Use --help on any command to see all available options:
dotnet run --project .\src\NimBus.CommandLine -- --help
dotnet run --project .\src\NimBus.CommandLine -- infra apply --help
Quick start: full deployment
To provision infrastructure, set up the Service Bus topology, and deploy the applications in one step:
dotnet run --project .\src\NimBus.CommandLine -- setup `
--solution-id nimbus `
--environment dev `
--resource-group rg-nimbus-dev
This runs infra apply, topology apply, and deploy apps in sequence.
Or npx-style from a fresh clone, without building anything first (dnx ships with the .NET 10 SDK):
git clone https://github.com/akakaule/NimBus; cd NimBus
dnx Akaule.NimBus.CommandLine -- setup --solution-id nimbus --environment dev --resource-group rg-nimbus-dev
New deployments default to the cheapest sensible hosting: the resolver runs on a Flex Consumption
plan (FC1, scales to zero) and the management WebApp plan is B1 for dev/development
(S1 for other environments). Existing deployments keep their current plans on re-runs; see
--resolver-plan and --management-plan-sku in docs/cli.md.
Commands
infra apply
Deploys Azure infrastructure (Service Bus namespace, Cosmos DB, Application Insights, Function App, Web App) using the bicep templates in deploy/bicep/.
dotnet run --project .\src\NimBus.CommandLine -- infra apply `
--solution-id nimbus `
--environment dev `
--resource-group rg-nimbus-dev
| Option | Required | Description |
|---|---|---|
--solution-id <ID> |
Yes | Identifier used in Azure resource names |
--environment <NAME> |
Yes | Environment name (e.g. dev, test, prod) |
--resource-group <NAME> |
Yes | Azure resource group to deploy into |
--repo-root <PATH> |
No | Repository root; auto-detected if omitted |
--location <AZURE-REGION> |
No | Azure region override for the bicep templates |
--webapp-version <VALUE> |
No | Version string stored in the web app settings |
topology export
Exports the current PlatformConfiguration (endpoints, event types, routing) to a JSON file for inspection.
dotnet run --project .\src\NimBus.CommandLine -- topology export
dotnet run --project .\src\NimBus.CommandLine -- topology export -o .\my-config.json
| Option | Required | Description |
|---|---|---|
-o, --output <PATH> |
No | Output path; defaults to platform-config.json in the current directory |
topology apply
Provisions Service Bus topics, subscriptions, and routing rules based on PlatformConfiguration. This creates the messaging topology that the platform endpoints use to communicate.
dotnet run --project .\src\NimBus.CommandLine -- topology apply `
--solution-id nimbus `
--environment dev `
--resource-group rg-nimbus-dev
| Option | Required | Description |
|---|---|---|
--solution-id <ID> |
Yes | Solution identifier |
--environment <NAME> |
Yes | Environment name |
--resource-group <NAME> |
Yes | Resource group containing the Service Bus namespace |
deploy apps
Builds, packages, and deploys the Resolver (Azure Function App) and Web App to Azure.
dotnet run --project .\src\NimBus.CommandLine -- deploy apps `
--solution-id nimbus `
--environment dev `
--resource-group rg-nimbus-dev
| Option | Required | Description |
|---|---|---|
--solution-id <ID> |
Yes | Solution identifier |
--environment <NAME> |
Yes | Environment name |
--resource-group <NAME> |
Yes | Resource group containing the target apps |
--repo-root <PATH> |
No | Repository root; auto-detected if omitted |
--configuration <NAME> |
No | Build configuration passed to dotnet publish; defaults to Release |
setup
Runs the full provisioning and deployment pipeline in sequence: infra apply → topology apply → deploy apps. Accepts all options from those individual commands.
Resource naming
The --solution-id and --environment values are normalized (lowercased, non-alphanumeric characters removed) and combined to produce Azure resource names:
| Resource | Naming pattern | Example |
|---|---|---|
| Service Bus namespace | sb-{solutionId}-{environment} |
sb-nimbus-dev |
| Application Insights | ai-{solutionId}-{environment}-global-tracelog |
ai-nimbus-dev-global-tracelog |
| Cosmos DB account | cosmos-{solutionId}-{environment} |
cosmos-nimbus-dev |
| Resolver Function App | func-{solutionId}-{environment}-resolver |
func-nimbus-dev-resolver |
| Management Web App | webapp-{solutionId}-{environment}-management |
webapp-nimbus-dev-management |
Local Development (Aspire)
The Aspire AppHost orchestrates the full platform locally. A built-in Provisioner creates the Service Bus topics/subscriptions before starting the Resolver and WebApp.
1. Set connection strings
dotnet user-secrets set "ConnectionStrings:servicebus" "<your-servicebus-connection-string>" `
--project .\src\NimBus.AppHost
dotnet user-secrets set "ConnectionStrings:cosmos" "<your-cosmos-connection-string>" `
--project .\src\NimBus.AppHost
2. Run
dotnet run --project .\src\NimBus.AppHost
The Aspire dashboard opens automatically. You'll see:
- provisioner — provisions Service Bus topology, then exits
- resolver — starts after provisioner completes
- webapp — starts after provisioner completes (external HTTP endpoint)
- publisher — sample HTTP API (
POST /publish/order,POST /publish/order-failed) - subscriber — sample event handler with middleware pipeline and separated DeferredProcessor
CRM/ERP integration sample
samples/CrmErpDemo/ is a larger, two-system reference scenario: a CRM and an ERP, each with its own SPA, REST API, SQL database, and adapter, exchanging domain events over Azure Service Bus.
What it demonstrates:
- Transactional outbox — entity insert and
nimbus.OutboxMessagesrow commit on the sameSqlConnection/SqlTransaction(no MSDTC), forwarded to Service Bus by an outbox dispatcher. - Two hosting models, identical handlers — CRM adapter runs as a .NET Worker (
BackgroundService), ERP adapter runs as Azure Functions isolated worker; the sameIEventHandler<T>works in both. - Cross-topic forwarding without loops — origin-prefixed event names (
CrmAccountCreated,ErpCustomerCreated, …) plusFrom IS NULLfilters on forwarding subscriptions make round-trip loops structurally impossible. - Session-based ordering —
[SessionKey(nameof(AccountId))]keeps theCrmAccountCreated → ErpCustomerCreated → link-erpround-trip ordered per account. - Operator surface — reuses
nimbus-ops(theNimBus.WebApp+ Resolver) for full audit trail and resubmit/skip on dead-lettered sessions. - Pluggable message store — runs against SQL Server by default (in a
nimbusdatabase on the same Aspire-managed SQL container as the CRM and ERP DBs); pass--StorageProvider cosmosto switch the audit/resolver/metrics store to Cosmos DB.
Run it
# 1. One-time secret (real Azure Service Bus namespace; no local emulator path)
dotnet user-secrets --project samples/CrmErpDemo/CrmErpDemo.AppHost set ConnectionStrings:servicebus "Endpoint=sb://..."
# 2. SPA dependencies (first run only)
cd samples/CrmErpDemo/Crm.Web; npm install; cd ../../..
cd samples/CrmErpDemo/Erp.Web; npm install; cd ../../..
# 3. Launch the demo (SQL Server storage by default)
dotnet run --project samples/CrmErpDemo/CrmErpDemo.AppHost
Wait for provisioner to complete in the Aspire dashboard, then create an account in crm-web and watch it round-trip through crm-adapter → Service Bus → erp-adapter Function → erp-api → back to crm-api to populate the ERP customer id. Stop erp-api mid-flow to see the failure / blocked-session / resubmit path in nimbus-ops.
Full architecture diagrams, message flows, topology details, and a v2 domains backlog are in samples/CrmErpDemo/README.md.
CI/CD
Ready-to-use deployment pipelines ship with the repository — both run infra apply → topology apply → deploy apps and accept optional resolver-plan / management-plan-sku / location inputs:
- GitHub Actions:
deploy.yml, manually triggered, authenticates with OIDC (no stored secrets) - Azure DevOps:
azure-pipelines-deploy.yml, manually triggered, uses a workload-identity service connection
Teams that provision infrastructure with their own tooling can drive the Bicep templates directly using the sample parameter files in deploy/bicep/parameters/.
The Deployment Guide covers the full setup for every path: the Entra app + federated credentials for GitHub OIDC, the Azure DevOps service connection, the RBAC the deploying identity needs (the Bicep creates role assignments — plain Contributor is not enough), and the raw-Bicep walkthrough.
Documentation
| Guide | Description |
|---|---|
| Getting Started | Step-by-step tutorial: create a publisher, subscriber, and run with Aspire |
| Deployment Guide | All deployment paths: one-command, GitHub Actions (OIDC), Azure DevOps, raw Bicep + required RBAC |
| Azure Infrastructure Requirements | Reference for governance review: resource inventory, provider registrations, RBAC matrix for pipeline identity, apps, and operators |
| Building Adapters | Detailed guide for adapter authors — publisher, subscriber, middleware, hosting choice |
| Azure Functions Hosting | Production hosting with Service Bus session triggers and DeferredProcessor |
| Message Flows | All 12 message flow patterns with mermaid diagrams |
| Error Handling | Adapter error-handling reference (transient, retry, dead-letter, classification) |
| Deferred Messages | Session blocking and deferral mechanics with Mermaid diagrams |
| Pipeline Middleware | Built-in middleware, custom behaviors, and lifecycle observers |
| Consumer Inbox | Opt-in redelivery deduplication, providers, retention, and remaining idempotency windows |
| Testing Guide | Test layers, conformance suites, OpenTelemetry coverage, and diagrams |
| CLI Reference | All nb commands: infra, topology, deploy, endpoint, container, catalog |
| SDK API Reference | Interfaces: IPublisherClient, IEventHandler, RetryPolicy, IOutbox |
| WebApp REST API | The HTTP control plane: route map, auth, calling from outside the SPA, code generation, current external-grade gaps |
| Extensions | Extension framework guide |
| Architecture | System design and component overview |
Acknowledgments
NimBus owes a clear intellectual debt to two open-source projects in the .NET messaging space. The design of the SDK, the pipeline of behaviors, the recoverability story (retries, dead-letter, audit, operator-driven resubmit/skip), and the framing of session-based ordering as a first-class concern are all heavily influenced by prior art from these communities.
- NServiceBus by Particular Software — the primary source of inspiration. NimBus's approach to message handlers, the pipeline-of-behaviors pattern, the transactional outbox, the centralized audit/recovery surface (in the spirit of ServiceControl + ServicePulse), and the emphasis on operator workflows over silent dead-letter all trace back to NServiceBus's ecosystem.
NimBus is an independent implementation targeted specifically at Azure Service Bus and is not a port, fork, or derivative of either project. Any awkward design choices here are NimBus's own.
License
This project and its solutions are licensed under the MIT License.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net10.0
- Akaule.NimBus.Core (>= 3.0.0)
- Akaule.NimBus.MessageStore.Abstractions (>= 3.0.0)
- Akaule.NimBus.OpenTelemetry (>= 3.0.0)
- Dapper (>= 2.1.66)
- dbup-core (>= 6.1.1)
- dbup-sqlserver (>= 7.1.0)
- Microsoft.Data.SqlClient (>= 6.1.4)
- Microsoft.Extensions.Configuration.Abstractions (>= 10.0.0)
- Microsoft.Extensions.Configuration.Binder (>= 10.0.0)
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 10.0.0)
- Microsoft.Extensions.Diagnostics.HealthChecks (>= 10.0.0)
- Microsoft.Extensions.Hosting.Abstractions (>= 10.0.0)
- Microsoft.Extensions.Logging.Abstractions (>= 10.0.0)
- Microsoft.Extensions.Options (>= 10.0.0)
- Newtonsoft.Json (>= 13.0.4)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.