Purview EventSourcing is a .NET event sourcing framework for building aggregate-based applications with provider-agnostic store facades, source-generated aggregates, transaction coordination, and storage packages for SQL Server, Azure Storage, MongoDB, and Azure Cosmos DB.
- Build aggregates on top of
AggregateBaseand load/save them throughIEventStore. - Add queryable read models with
IQueryableEventStorewhen you need filtering, paging, and list views. - Generate aggregate event types and registration code from partial methods using the source generator support included in
Purview.EventSourcing. - Coordinate multi-aggregate saves through
IEventStoreTransactionFactory. - Swap storage providers without changing your application-facing aggregate APIs.
| Package ID | Purpose | Project README |
|---|---|---|
Purview.EventSourcing |
Core abstractions, aggregate types, facades, transactions, DI extensions, and source generation support | src/src/EventSourcing/README.md |
Purview.EventSourcing.SqlServer |
Azure SQL / SQL Server event stream and queryable snapshot stores | src/src/EventSourcing.SqlServer/README.md |
Purview.EventSourcing.AzureStorage |
Azure Table / Blob event store | src/src/EventSourcing.AzureStorage/README.md |
Purview.EventSourcing.MongoDB |
MongoDB event stream and queryable snapshot stores | src/src/EventSourcing.MongoDB/README.md |
Purview.EventSourcing.CosmosDb |
Azure Cosmos DB queryable snapshot store | src/src/EventSourcing.CosmosDb/README.md |
dotnet add package Purview.EventSourcing
dotnet add package Purview.EventSourcing.SqlServerProvider packages layer on top of the core Purview.EventSourcing package. Add only the providers required for your chosen persistence strategy.
using Purview.EventSourcing.Aggregates;
[GenerateAggregate]
public partial class OrderAggregate : AggregateBase
{
public string CustomerId { get; private set; } = default!;
public decimal Total { get; private set; }
[GenerateAggregateEvent]
public partial void CreateOrder(string customerId);
[GenerateAggregateEvent]
public partial void AddLineItem(string productId, string productName, int quantity, decimal unitPrice);
}[GenerateAggregate] supports three inheritance paths:
- No declared base class: the generated partial type automatically inherits
AggregateBase. - Direct inheritance from
AggregateBase. - Transitive inheritance through one or more intermediate base classes.
builder.Services.AddSqlServerEventStore();
builder.Services.AddSqlServerSnapshotQueryableEventStore();{
"ConnectionStrings": {
"eventstore-sqlserver": "Server=.;Database=MyApp;Trusted_Connection=True;"
}
}public sealed class OrderService(IEventStore store)
{
public async Task PlaceOrderAsync(string orderId, string customerId, CancellationToken cancellationToken)
{
var order = await store.GetAsync<OrderAggregate>(orderId, cancellationToken)
?? await store.CreateAsync<OrderAggregate>(orderId, cancellationToken: cancellationToken);
order.CreateOrder(customerId);
order.AddLineItem("SKU-1", "Demo product", 1, 19.99m);
await store.SaveAsync(order, cancellationToken);
}
}public sealed class OrderQueries(IQueryableEventStore store)
{
public Task<long> CountActiveOrdersAsync(CancellationToken cancellationToken) =>
store.CountAsync<OrderAggregate>(o => !o.Details.IsDeleted, cancellationToken);
}public sealed class CheckoutService(
IEventStoreTransactionFactory transactionFactory,
IQueryableEventStore store)
{
public async Task<bool> CheckoutAsync(
OrderAggregate order,
InventoryAggregate inventory,
CancellationToken cancellationToken)
{
await using var transaction = transactionFactory.Create();
transaction.Enlist(order, store);
transaction.Enlist(inventory, store);
var result = await transaction.CommitAsync(cancellationToken);
return result.Success;
}
}| Provider | Package | Registration API | Notes |
|---|---|---|---|
| Core only | Purview.EventSourcing |
AddNullQueryableEventStore() |
No persistent query store |
| Azure SQL / SQL Server | Purview.EventSourcing.SqlServer |
AddSqlServerEventStore() and AddSqlServerSnapshotQueryableEventStore() |
Separate event and snapshot implementations in one package |
| Azure Table / Blob | Purview.EventSourcing.AzureStorage |
AddAzureTableEventStore() |
Table events plus Blob support for large payloads and snapshots |
| MongoDB | Purview.EventSourcing.MongoDB |
AddMongoDBEventStore() and AddMongoDBSnapshotQueryableEventStore() |
Separate event and snapshot implementations in one package |
| Azure Cosmos DB snapshots | Purview.EventSourcing.CosmosDb |
AddCosmosDbQueryableEventStore() |
Queryable snapshot store |
For SQL Server and Azure SQL schema, permissions, and event-versioning guidance, see docs/wiki/SQL-Server-Guide.md.
The sample solution demonstrates how the framework is intended to be consumed:
EventSourcing.Samples.Webuses the non-genericIEventStoreandIQueryableEventStorefacades.EventSourcing.Samples.QuickStartis a console app that demonstrates related aggregates, multi-aggregate transactions, and rollback-on-failure behavior without external infrastructure.EventSourcing.Samples.AppHostwires up SQL Server, Redis, Azurite, and the web app for Aspire-driven local runs.- Sample services such as
CartCheckoutService,OrderFulfillmentService, andStockTransferServicedemonstrate multi-aggregate workflows.
| Path | Purpose |
|---|---|
src/src |
Packable framework packages and sample applications |
src/tests |
Unit, integration, and source generator test projects |
docs/wiki |
Wiki-style project documentation (Home.md, SQL Server guide, release flow, source-generator behaviors) |
Justfile |
Build, test, format, version, pack, and publish workflow definitions |
dotnet tool restore
dotnet restore src/Purview.EventSourcing.slnx
dotnet build src/Purview.EventSourcing.slnx --configuration Release
dotnet csharpier check src
dotnet test --project src/tests/EventSourcing.UnitTests/EventSourcing.UnitTests.csproj --configuration Release
Additional notes:
justrecipes in theJustfilewrap the same restore, build, test, pack, and version commands for local development.- Integration tests use Testcontainers; local Docker support is recommended.
package.jsonis the release version source of truth for builds and packages.dotnet packorjust packwrites packages toartifacts/packages.
- Update the package version with the repository release process.
- Review the generated
CHANGELOG.mdand package version changes. - Build, test, and pack the repository.
- Let the GitHub Actions CD workflow create the tag, publish the GitHub release, and push NuGet packages.
Do not create release tags manually.