Idiomatic .NET client for the ReckonDB event store, accessed over gRPC via the reckon-gateway frontend.
using Reckon;
await using var client = await ReckonClient.ConnectAsync("gateway.example.org:50051");
var overview = await client.Health.OverviewAsync();
Console.WriteLine($"node={overview.Node} status={overview.Status}");reckon-dotnet is the .NET client for the Reckon event-sourcing stack. It
speaks gRPC to a running
reckon-gateway, which fronts
a ReckonDB event store (embedded in the gateway, or federated across remote
Erlang clusters). You get typed, idiomatic .NET over the full gateway surface
without speaking Erlang dist or hand-rolling protobuf.
The package id is Reckon.Client; the root namespace is Reckon (so calls read
ReckonClient.Connect(...)). One ReckonClient wraps one gRPC channel to one
gateway endpoint; per-service sub-clients are bound to a store and share that
connection.
This is a sibling to reckon-go and mirrors its shape 1:1. It does not reimplement the evoq framework layer — .NET teams keep their Wolverine/Marten idioms and back the store with ReckonDB through this client. See the "Reckon and the Critter Stack" appendix in the Reckon Codex.
The packages (Reckon.Client, Reckon.Extensions.Hosting) are not on
nuget.org yet, so dotnet add package Reckon.Client does not find them. Build
them from source and reference the project, or pack them into a local feed:
git clone --recurse-submodules https://github.com/reckon-db-org/reckon-dotnet
cd reckon-dotnet
dotnet pack -c Release --output artifacts
# in your own project:
dotnet nuget add source /path/to/reckon-dotnet/artifacts --name reckon-local
dotnet add package Reckon.Client
dotnet add package Reckon.Extensions.Hosting # optional: DI + hosting glueOr skip the feed and reference the project directly:
dotnet add reference /path/to/reckon-dotnet/src/Reckon.Client/Reckon.Client.csproj.
CI (GitHub Actions) builds and tests every push. Its v* tag job is written
to publish both packages to nuget.org (see
.github/workflows/ci.yml); until that has run,
building from source is the way in.
| Sub-client | Accessor | Purpose | Status |
|---|---|---|---|
health |
client.Health |
gateway / per-store health | ✅ M0 |
streams |
client.Streams(store) |
append + read + watch events on a stream | ✅ M1 |
subscriptions |
client.Subscriptions(store) |
live + persistent subscriptions | ✅ M2 |
snapshots |
client.Snapshots(store) |
per-stream snapshots | ✅ M2 |
dcb |
client.Dcb(store) |
DCB writes/reads and CCC payload reads | ✅ M3 |
schema |
client.Schema(store) |
schema registration + upcasting | ✅ M4 |
temporal |
client.Temporal(store) |
wall-clock / time-travel reads | ✅ M4 |
admin |
client.Admin(store) |
scavenge, links, store stats | ✅ M4 |
stores |
client.Stores |
cluster topology discovery + watch | ✅ M4 |
There is no Ccc sub-client by design: CCC (Command Context Consistency) is the
payload-keyed read variant of the DCB primitive and reuses DCB's single
conditional-append, so it lives on the Dcb sub-client — matching the proto
(DcbService), reckon-gater, and reckon-go.
The Reckon.Extensions.Hosting package wires the client into a generic host and
gives you a subscription-driven projection worker: ReckonDB owns the log and
delivery, your handler owns the read model.
using Reckon.Extensions.Hosting;
builder.Services.AddReckonClient(o => { o.Address = "gateway:50051"; });
// Drive a projection from a persistent subscription. The handler is resolved
// from a fresh DI scope per event and acked automatically on success.
builder.Services.AddReckonSubscription<OrderProjection>(o =>
{
o.Store = "orders";
o.Type = SubscriptionType.EventType;
o.Selector = "order_placed_v1";
o.SubscriptionName = "orders-projection";
});
// Optional gateway health check:
builder.Services.AddHealthChecks().AddCheck<ReckonHealthCheck>("reckon");using Reckon.Extensions.Hosting;
using Reckon.Subscriptions;
public sealed class OrderProjection : IReckonEventHandler
{
public Task HandleAsync(SubscriptionEnvelope envelope, CancellationToken ct)
{
// apply envelope.Event to your read model (Marten doc, EF row, ...)
return Task.CompletedTask;
}
}The gRPC contract is reckon-proto,
vendored here as a git submodule under proto/, pinned to a tag. Stubs are
generated at build time by Grpc.Tools into obj/ (package
reckon.gateway.v1 → C# namespace Reckon.Gateway.V1); nothing generated is
committed.
Clone with submodules:
git clone --recurse-submodules https://github.com/reckon-db-org/reckon-dotnet
# or, after a plain clone:
git submodule update --initdotnet build
dotnet test # live tests are inert without a gatewayNeed a gateway to point at? dev-env/ spins one up locally in one
command (embedded store default_store, gRPC on localhost:50051):
cd dev-env && ./up.sh
RECKON_GATEWAY=localhost:50051 RECKON_INSECURE=1 dotnet testRequires the .NET SDK (repo pins dotnet 10.0.301 via .tool-versions).
Targets net8.0, net9.0 and net10.0.
Run the quickstart sample against that gateway:
RECKON_GATEWAY=localhost:50051 RECKON_INSECURE=1 dotnet run --project examples/QuickStartProduce the NuGet packages (Reckon.Client, Reckon.Extensions.Hosting) with
symbols:
dotnet pack -c Release --output artifactsApache-2.0. See LICENSE.