ResQ.BuildingBlocks.Adapters.Persistence 0.2.0

dotnet add package ResQ.BuildingBlocks.Adapters.Persistence --version 0.2.0
                    
NuGet\Install-Package ResQ.BuildingBlocks.Adapters.Persistence -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="ResQ.BuildingBlocks.Adapters.Persistence" Version="0.2.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="ResQ.BuildingBlocks.Adapters.Persistence" Version="0.2.0" />
                    
Directory.Packages.props
<PackageReference Include="ResQ.BuildingBlocks.Adapters.Persistence" />
                    
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 ResQ.BuildingBlocks.Adapters.Persistence --version 0.2.0
                    
#r "nuget: ResQ.BuildingBlocks.Adapters.Persistence, 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 ResQ.BuildingBlocks.Adapters.Persistence@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=ResQ.BuildingBlocks.Adapters.Persistence&version=0.2.0
                    
Install as a Cake Addin
#tool nuget:?package=ResQ.BuildingBlocks.Adapters.Persistence&version=0.2.0
                    
Install as a Cake Tool

ResQ.BuildingBlocks.Adapters.Persistence

The EF Core 9 persistence adapter (driven ring). Provider-agnostic — it references only EF Core and its Relational package, so the consumer picks the provider (Npgsql, SQLite, …) in the configure callback. Depends only on ResQ.BuildingBlocks.Application + ResQ.BuildingBlocks.Domain — never on the messaging adapter (the outbox/inbox use the messaging ports that live in the application core).

The keystone: EfUnitOfWork

EfUnitOfWork is the scoped IUnitOfWork. Its SaveChangesAsync dispatches domain events before the underlying DbContext.SaveChanges, in a drain loop over ChangeTracker.Entries<IHasDomainEvents>():

  1. Collect tracked aggregates with pending events, snapshot and clear them.
  2. await IDomainEventDispatcher.DispatchAsync(events) — a handler may enqueue an outbox row or raise more events.
  3. Repeat until no aggregate has pending events, then call the underlying SaveChangesAsync.

Because dispatch happens inside the same save, outbox rows a handler enqueues commit atomically with the aggregate write. There is deliberately no domain-event-dispatch interceptor: EF's internal service provider does not contain application services. Contract: commits must flow through IUnitOfWork.SaveChangesAsync for domain events to dispatch.

What's in the box

  • Repository<TAggregate,TId> / ReadRepository<TAggregate,TId> — specification-driven aggregate repositories; the read side forces AsNoTracking.
  • SpecificationEvaluator — bridges the EF-free ISpecification<T> (criteria, includes, ordering, paging, tracking, split-query, ignore-filters) onto an IQueryable<T>.
  • TransactionBehavior<TRequest,TResponse> — wraps commands (detected through the CQRS marker interfaces, so ICommand<T> is caught too) in a transaction via EF's execution strategy. Queries pass through.
  • AuditInterceptor + IAuditable — a singleton save-changes interceptor that stamps created/modified timestamps from IClock.
  • Transactional outbox — OutboxMessage (bytes payload), OutboxMessageConfiguration, IOutbox / EfOutbox (enqueue in the same transaction), OutboxRelay (at-least-once background publisher), OutboxOptions.
  • Inbox idempotency — InboxMessage, InboxMessageConfiguration, EfIdempotencyStore (dedupe by (messageId, handler)).
  • ModelBuilderExtensions — ApplyResqInfrastructure() maps the outbox/inbox tables; ApplyConfigurationsFrom(assembly) applies your own configs.

Wiring

services.AddResqPersistence<AppDbContext>(
    (sp, options) => options.UseNpgsql(connectionString),
    setup =>
    {
        setup.UseOutbox = true;             // register EfOutbox + OutboxRelay
        setup.UseTransactionBehavior = true; // register TransactionBehavior last (innermost)
        setup.EnableAudit = true;            // attach AuditInterceptor
    });

services.AddResqRepositories(typeof(AppDbContext).Assembly);

AddResqPersistence pools the context (AddDbContextPool), relays a scoped DbContext, and registers EfUnitOfWork/EfIdempotencyStore scoped and AuditInterceptor singleton. In OnModelCreating, call modelBuilder.ApplyResqInfrastructure().ApplyConfigurationsFrom(GetType().Assembly).

Apache-2.0 · part of resq-software/dotnet.

Product Compatible and additional computed target framework versions.
.NET net8.0 is compatible.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 is compatible.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 was computed.  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 325 8/16/2026