aalmuqahwi.BuildingBlocks.Infrastructure 0.2.0

dotnet add package aalmuqahwi.BuildingBlocks.Infrastructure --version 0.2.0
                    
NuGet\Install-Package aalmuqahwi.BuildingBlocks.Infrastructure -Version 0.2.0
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="aalmuqahwi.BuildingBlocks.Infrastructure" Version="0.2.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="aalmuqahwi.BuildingBlocks.Infrastructure" Version="0.2.0" />
                    
Directory.Packages.props
<PackageReference Include="aalmuqahwi.BuildingBlocks.Infrastructure" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add aalmuqahwi.BuildingBlocks.Infrastructure --version 0.2.0
                    
#r "nuget: aalmuqahwi.BuildingBlocks.Infrastructure, 0.2.0"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package aalmuqahwi.BuildingBlocks.Infrastructure@0.2.0
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=aalmuqahwi.BuildingBlocks.Infrastructure&version=0.2.0
                    
Install as a Cake Addin
#tool nuget:?package=aalmuqahwi.BuildingBlocks.Infrastructure&version=0.2.0
                    
Install as a Cake Tool

BuildingBlocks

Reusable Domain/Application/Infrastructure building blocks — DDD, Clean Architecture, CQRS, and Modular Monolith patterns — for .NET.

Status

🚧 Actively developed. Built to learn NuGet packaging and reduce copy-paste across my own projects — APIs may still change between versions.

Installation

dotnet add package aalmuqahwi.BuildingBlocks.Domain
dotnet add package aalmuqahwi.BuildingBlocks.Application
dotnet add package aalmuqahwi.BuildingBlocks.Infrastructure

Packages

BuildingBlocks.Domain

Core DDD primitives. No external dependencies.

  • Result / Error — success/failure without exceptions
  • Entity<TId> / AggregateRoot<TId> — equality by ID, domain event tracking
  • DomainEvent / IDomainEvent — immutable facts raised by aggregates
  • ValueObject — base for immutable, structurally-equal types

BuildingBlocks.Application

CQRS and cross-cutting contracts. Depends only on BuildingBlocks.Domain.

  • ICommand / IQuery<TResult> — request markers
  • ICommandHandler<,> / IQueryHandler<,> — handler contracts
  • IDispatcher — routes commands/queries to their handlers
  • IPipelineBehavior<,> — cross-cutting middleware around handler execution (logging, validation, etc.)
  • IUnitOfWork — persistence flush abstraction, technology-agnostic
  • IDomainEventHandler<> / IDomainEventDispatcher — domain event handling contracts
  • IIntegrationEvent / IIntegrationEventHandler<> / IIntegrationEventDispatcher — cross-boundary event contracts (module-to-module or service-to-service)
  • IOutboxWriter — in-memory buffer for integration events raised during a unit of work
  • OutboxMessage — persisted outbox record (Type, Payload, ProcessedOnUtc, Error, RetryCount)
  • IOutboxMessageStore / IOutboxProcessor — outbox persistence and processing contracts, technology-agnostic

BuildingBlocks.Infrastructure

Concrete DI-based implementations. Depends on BuildingBlocks.Application.

  • Dispatcher — resolves and invokes command/query handlers via keyed DI, runs pipeline behaviors
  • DomainEventDispatcher — resolves and invokes all registered handlers for a given domain event
  • IntegrationEventDispatcher — resolves and invokes all registered handlers for a given integration event
  • OutboxWriter — in-memory IOutboxWriter implementation
  • OutboxProcessor — reads pending outbox messages, dispatches them, and marks each processed or failed independently (one bad message never blocks the rest of the batch)
  • AddBuildingBlocksInfrastructure(...) — one-line registration for dispatching (or call AddDispatcher(...) / AddDomainEventDispatcher(...) / AddOutboxProcessor() individually)

Usage

// Program.cs
builder.Services.AddBuildingBlocksInfrastructure(typeof(Program).Assembly);

// Somewhere in your app
public record CreateOrderCommand(string ProductId) : ICommand<Result<Guid>>;

public class CreateOrderHandler : ICommandHandler<CreateOrderCommand, Result<Guid>>
{
    public Task<Result<Guid>> Handle(CreateOrderCommand command, CancellationToken ct)
        => Task.FromResult(Result.Success(Guid.NewGuid()));
}

// Dispatching
var result = await dispatcher.SendAsync(new CreateOrderCommand("prod-123"));

Outbox / integration events — raise an event during a unit of work, flush it to storage when saving, then process it independently.

Raise and persist:

// Somewhere handling a command
_outboxWriter.Add(new OrderShipped(orderId));

// Inside your DbContext's SaveChangesAsync override (or equivalent)
foreach (var integrationEvent in _outboxWriter.Flush())
{
    OutboxMessages.Add(new OutboxMessage
    {
        Id = Guid.NewGuid(),
        Type = integrationEvent.GetType().AssemblyQualifiedName!,
        Payload = JsonSerializer.Serialize(integrationEvent, integrationEvent.GetType()),
        OccurredOnUtc = DateTime.UtcNow
    });
}

Register and process, triggered by whatever scheduler you prefer:

// Program.cs
builder.Services.AddOutboxProcessor();
builder.Services.AddScoped<IIntegrationEventHandler<OrderShipped>, SendShippingEmail>();
builder.Services.AddScoped<IOutboxMessageStore, EfOutboxMessageStore>(); // your own implementation

// Triggered by your own BackgroundService, Hangfire, Quartz, etc.
await outboxProcessor.ProcessPendingAsync(ct);

Design notes

  • Domain has zero dependencies by design — safe to reference from anywhere
  • IUnitOfWork and persistence are intentionally technology-agnostic — bring your own EF Core/Dapper/etc. implementation, including IOutboxMessageStore
  • Each package only depends on what it strictly needs — Application and Infrastructure don't force unrelated dependencies onto consumers who only want a subset
  • Integration event handlers are registered manually, not auto-scanned like command/domain event handlers — unlike those, integration events may cross service boundaries, so implicit assembly scanning could pick up a handler that was never meant to run in a given service. Forgetting to register a handler causes it to silently never run — no error, no warning.
  • Outbox delivery is at-least-once, not exactly-once. If the process crashes between dispatching and marking a message processed, it will be redelivered on the next run. Integration event handlers should be idempotent.
  • OutboxProcessor reports failures and computes the next retry count, but your IOutboxMessageStore owns retry policy. MarkFailedAsync is called with the handler's actual error message and an incremented RetryCount — it's up to your store implementation to decide when a message has retried too many times and stop returning it from GetPendingAsync (or move it to a dead-letter state). Without this, a permanently unresolvable message will be retried forever.
  • No built-in scheduler for IOutboxProcessor. ProcessPendingAsync() is a plain, injectable method — call it from a BackgroundService, a Hangfire recurring job, a Quartz job, or anything else. Trigger it from exactly one place; running two triggers concurrently against the same store can cause duplicate or racing delivery.
Product 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. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
0.2.0 111 8/7/2026
0.1.0 112 7/24/2026