GenesisDB.Client 1.0.0

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

.NET SDK

This is the official .NET SDK for GenesisDB, an awesome and production ready event sourcing database system for building event-driven apps.

GenesisDB Advantages

  • Incredibly fast when reading, fast when writing 🚀
  • Easy backup creation and recovery
  • CloudEvents compatible
  • GDPR-ready
  • Easily accessible via the HTTP interface
  • Auditable. Guarantee database consistency
  • Logging and metrics for Prometheus
  • SQL like query language called GenesisDB Query Language (GDBQL)
  • ...

Installation

NuGet Package

dotnet add package GenesisDB.Client

Package Manager

Install-Package GenesisDB.Client

Configuration

Environment Variables

The following environment variables are required when no explicit configuration is provided:

GENESISDB_AUTH_TOKEN=<secret>
GENESISDB_API_URL=http://localhost:8080
GENESISDB_API_VERSION=v1

Basic Setup

using GenesisDB.Client;

// Initialize from environment variables
using var client = new GenesisDbClient();

// Or initialize with explicit configuration
using var client = new GenesisDbClient(new ClientConfig
{
    ApiUrl = "http://localhost:8080",
    ApiVersion = "v1",
    AuthToken = "secret"
});

Custom HttpClient (for DI / testing)

using var client = new GenesisDbClient(
    new ClientConfig
    {
        ApiUrl = "http://localhost:8080",
        ApiVersion = "v1",
        AuthToken = "secret"
    },
    httpClient  // your own HttpClient instance
);

Streaming Events

Basic Event Streaming

// Stream all events for a subject
var events = await client.StreamEventsAsync("/customer");

foreach (var e in events)
{
    Console.WriteLine($"{e.Id}: {e.Type} — {e.GetDataValue<string>("firstName")}");
}

Stream Events from Lower Bound

var events = await client.StreamEventsAsync("/", new StreamOptions
{
    LowerBound = "2d6d4141-6107-4fb2-905f-445730f4f2a9",
    IncludeLowerBoundEvent = true
});

Stream Events with Upper Bound

var events = await client.StreamEventsAsync("/", new StreamOptions
{
    UpperBound = "9f3e4141-7208-4fb2-905f-445730f4f3b1",
    IncludeUpperBoundEvent = false
});

Stream Events with Both Lower and Upper Bounds

var events = await client.StreamEventsAsync("/", new StreamOptions
{
    LowerBound = "2d6d4141-6107-4fb2-905f-445730f4f2a9",
    IncludeLowerBoundEvent = true,
    UpperBound = "9f3e4141-7208-4fb2-905f-445730f4f3b1",
    IncludeUpperBoundEvent = false
});

Stream Latest Events by Event Type

var events = await client.StreamEventsAsync("/", new StreamOptions
{
    LatestByEventType = "io.genesisdb.app.customer-updated"
});

This feature allows you to stream only the latest event of a specific type for each subject. Useful for getting the current state of entities.

Committing Events

Basic Event Committing

await client.CommitEventsAsync(new[]
{
    new CommitEvent
    {
        Source = "io.genesisdb.app",
        Subject = "/customer",
        Type = "io.genesisdb.app.customer-added",
        Data = new
        {
            firstName = "Bruce",
            lastName = "Wayne",
            emailAddress = "bruce.wayne@enterprise.wayne"
        }
    },
    new CommitEvent
    {
        Source = "io.genesisdb.app",
        Subject = "/customer",
        Type = "io.genesisdb.app.customer-added",
        Data = new
        {
            firstName = "Alfred",
            lastName = "Pennyworth",
            emailAddress = "alfred.pennyworth@enterprise.wayne"
        }
    },
    new CommitEvent
    {
        Source = "io.genesisdb.store",
        Subject = "/article",
        Type = "io.genesisdb.store.article-added",
        Data = new
        {
            name = "Tumbler",
            color = "black",
            price = 2990000.00
        }
    },
    new CommitEvent
    {
        Source = "io.genesisdb.app",
        Subject = "/customer/fed2902d-0135-460d-8605-263a06308448",
        Type = "io.genesisdb.app.customer-personaldata-changed",
        Data = new
        {
            firstName = "Angus",
            lastName = "MacGyver",
            emailAddress = "angus.macgyer@phoenix.foundation"
        }
    }
});

Preconditions

Preconditions allow you to enforce certain checks on the server before committing events. GenesisDB supports multiple precondition types:

isSubjectNew

Ensures that a subject is new (has no existing events):

await client.CommitEventsAsync(
    new[]
    {
        new CommitEvent
        {
            Source = "io.genesisdb.app",
            Subject = "/user/456",
            Type = "io.genesisdb.app.user-created",
            Data = new
            {
                firstName = "John",
                lastName = "Doe",
                email = "john.doe@example.com"
            }
        }
    },
    new[] { Preconditions.IsSubjectNew("/user/456") }
);

isSubjectExisting

Ensures that events exist for the specified subject:

await client.CommitEventsAsync(
    new[]
    {
        new CommitEvent
        {
            Source = "io.genesisdb.app",
            Subject = "/user/456",
            Type = "io.genesisdb.app.user-updated",
            Data = new
            {
                firstName = "John",
                lastName = "Doe",
                email = "john.doe@example.com"
            }
        }
    },
    new[] { Preconditions.IsSubjectExisting("/user/456") }
);

isQueryResultTrue

Evaluates a query and ensures the result is truthy. Supports the full GDBQL feature set including complex WHERE clauses, aggregations, and calculated fields.

Basic uniqueness check:

await client.CommitEventsAsync(
    new[]
    {
        new CommitEvent
        {
            Source = "io.genesisdb.app",
            Subject = "/user/456",
            Type = "io.genesisdb.app.user-created",
            Data = new
            {
                firstName = "John",
                lastName = "Doe",
                email = "john.doe@example.com"
            }
        }
    },
    new[] { Preconditions.IsQueryResultTrue(
        "STREAM e FROM events WHERE e.data.email == 'john.doe@example.com' MAP COUNT() == 0"
    ) }
);

Business rule enforcement (transaction limits):

await client.CommitEventsAsync(
    new[]
    {
        new CommitEvent
        {
            Source = "io.genesisdb.banking",
            Subject = "/user/123/transactions",
            Type = "io.genesisdb.banking.transaction-processed",
            Data = new { amount = 500.00, currency = "EUR" }
        }
    },
    new[] { Preconditions.IsQueryResultTrue(
        "STREAM e FROM events WHERE e.subject UNDER '/user/123' AND e.type == 'transaction-processed' AND e.time >= '2024-01-01T00:00:00Z' MAP SUM(e.data.amount) + 500 <= 10000"
    ) }
);

Complex validation with aggregations:

await client.CommitEventsAsync(
    new[]
    {
        new CommitEvent
        {
            Source = "io.genesisdb.events",
            Subject = "/conference/2024/registrations",
            Type = "io.genesisdb.events.registration-created",
            Data = new { attendeeId = "att-789", ticketType = "premium" }
        }
    },
    new[] { Preconditions.IsQueryResultTrue(
        "STREAM e FROM events WHERE e.subject UNDER '/conference/2024/registrations' AND e.type == 'registration-created' GROUP BY e.data.ticketType HAVING e.data.ticketType == 'premium' MAP COUNT() < 50"
    ) }
);

Generic Preconditions

For forward compatibility with future precondition types, you can use the generic Precondition class directly:

await client.CommitEventsAsync(
    events,
    new[]
    {
        new Precondition
        {
            Type = "someCustomFuturePrecondition",
            Payload = new { foo = "bar", baz = 123 }
        }
    }
);

Supported GDBQL Features in Preconditions:

  • WHERE conditions with AND/OR/IN/BETWEEN operators
  • Hierarchical subject queries (UNDER, DESCENDANTS)
  • Aggregation functions (COUNT, SUM, AVG, MIN, MAX)
  • GROUP BY with HAVING clauses
  • ORDER BY and LIMIT clauses
  • Calculated fields and expressions
  • Nested field access (e.data.address.city)
  • String concatenation and arithmetic operations

If a precondition fails, the commit throws a GenesisDbException with HTTP 412 (Precondition Failed).

GDPR Compliance

Store Data as Reference

await client.CommitEventsAsync(new[]
{
    new CommitEvent
    {
        Source = "io.genesisdb.app",
        Subject = "/user/456",
        Type = "io.genesisdb.app.user-created",
        Data = new
        {
            firstName = "John",
            lastName = "Doe",
            email = "john.doe@example.com"
        },
        Options = new CommitEventOptions { StoreDataAsReference = true }
    }
});

Delete Referenced Data

await client.EraseDataAsync("/user/456");

Observing Events

The ObserveEventsAsync method returns an IAsyncEnumerable<CloudEvent>, which keeps the connection open and yields events as they arrive in real time.

Basic Event Observation

await foreach (var e in client.ObserveEventsAsync("/customer"))
{
    Console.WriteLine($"Received: {e.Id} — {e.Type}");
}

Observe Events from Lower Bound (Message Queue)

await foreach (var e in client.ObserveEventsAsync("/customer", new StreamOptions
{
    LowerBound = "2d6d4141-6107-4fb2-905f-445730f4f2a9",
    IncludeLowerBoundEvent = true
}))
{
    Console.WriteLine($"Received: {e.Id}");
}

Observe Events with Upper Bound (Message Queue)

await foreach (var e in client.ObserveEventsAsync("/customer", new StreamOptions
{
    UpperBound = "9f3e4141-7208-4fb2-905f-445730f4f3b1",
    IncludeUpperBoundEvent = false
}))
{
    Console.WriteLine($"Received: {e.Id}");
}

Observe Events with Both Bounds (Message Queue)

await foreach (var e in client.ObserveEventsAsync("/customer", new StreamOptions
{
    LowerBound = "2d6d4141-6107-4fb2-905f-445730f4f2a9",
    IncludeLowerBoundEvent = true,
    UpperBound = "9f3e4141-7208-4fb2-905f-445730f4f3b1",
    IncludeUpperBoundEvent = false
}))
{
    Console.WriteLine($"Received: {e.Id}");
}

Observe Latest Events by Event Type (Message Queue)

await foreach (var e in client.ObserveEventsAsync("/customer", new StreamOptions
{
    LatestByEventType = "io.genesisdb.app.customer-updated"
}))
{
    Console.WriteLine($"Received latest: {e.Id}");
}

Cancellation Support

Use a CancellationToken to gracefully stop observing:

using var cts = new CancellationTokenSource(TimeSpan.FromMinutes(5));

await foreach (var e in client.ObserveEventsAsync("/customer", cancellationToken: cts.Token))
{
    Console.WriteLine($"Received: {e.Id}");

    if (someCondition)
    {
        cts.Cancel(); // stop observing
    }
}

Querying Events

var results = await client.QueryEventsAsync(
    "STREAM e FROM events WHERE e.type == 'io.genesisdb.app.customer-added' ORDER BY e.time DESC LIMIT 20 MAP { subject: e.subject, firstName: e.data.firstName }"
);

foreach (var result in results)
{
    Console.WriteLine($"{result.GetProperty("subject")} — {result.GetProperty("firstName")}");
}

Query results are returned as List<JsonElement>, giving you full flexibility to access any shape of data:

var results = await client.QueryAsync(
    "STREAM e FROM events WHERE e.subject == '/customer/123' MAP e.data"
);

foreach (var row in results)
{
    var firstName = row.GetProperty("firstName").GetString();
    var age = row.GetProperty("age").GetInt32();
}

Working with CloudEvent Data

The CloudEvent class provides helper methods for accessing event data:

var events = await client.StreamEventsAsync("/customer");

foreach (var e in events)
{
    // Access individual properties
    var firstName = e.GetDataValue<string>("firstName");
    var age = e.GetDataValue<int>("age");

    // Or deserialize the entire data payload to a typed object
    var customer = e.GetData<CustomerData>();
}

Error Handling

API errors throw a GenesisDbException with the HTTP status code and reason:

try
{
    await client.CommitEventsAsync(events, preconditions);
}
catch (GenesisDbException ex) when (ex.StatusCode == System.Net.HttpStatusCode.PreconditionFailed)
{
    Console.WriteLine("Precondition failed — commit rejected");
}
catch (GenesisDbException ex)
{
    Console.WriteLine($"API error: {ex.StatusCode} — {ex.ReasonPhrase}");
}

Health Checks

// Check API status
var pingResponse = await client.PingAsync();
Console.WriteLine($"Ping: {pingResponse}");

// Run audit to check event consistency
var auditResponse = await client.AuditAsync();
Console.WriteLine($"Audit: {auditResponse}");

API Reference

Method Description
PingAsync() Pings the server, returns a string response
AuditAsync() Runs an audit check, returns audit information
CommitEventsAsync(events, preconditions?) Commits one or more events with optional preconditions
StreamEventsAsync(subject, options?) Streams events for a subject, returns List<CloudEvent>
EraseDataAsync(subject) Erases referenced data for GDPR compliance
QueryAsync(query) Executes a GDBQL query, returns List<JsonElement>
QueryEventsAsync(query) Alias for QueryAsync
ObserveEventsAsync(subject, options?, cancellationToken) Observes events in real time via IAsyncEnumerable<CloudEvent>

Running Tests

# Unit tests (no server required)
dotnet test --filter "Category!=Integration"

# Integration tests (requires GenesisDB on localhost:8080)
dotnet test --filter "Category=Integration"

# All tests
dotnet test

Requirements

  • .NET 8.0 or later

License

MIT

Author

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 was computed.  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.
  • net8.0

    • No dependencies.

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
1.0.0 123 4/2/2026