### Run EventStoreDB Locally with Docker Source: https://github.com/kurrent-io/kurrentdb-client-dotnet/blob/master/samples/secure-with-tls/README.md Start an EventStoreDB node locally using Docker Compose. This command assumes certificates have been generated and installed. ```bash docker-compose up -d ``` -------------------------------- ### Install OpenTelemetry Exporters Source: https://github.com/kurrent-io/kurrentdb-client-dotnet/blob/master/docs/api/observability.md Install the required OpenTelemetry exporters for your chosen observability platform using the dotnet CLI. ```bash dotnet add package OpenTelemetry.Exporter.Console # For Jaeger dotnet add package OpenTelemetry.Exporter.Jaeger # For OTLP (OpenTelemetry Protocol) dotnet add package OpenTelemetry.Exporter.OpenTelemetryProtocol # For Seq dotnet add package Seq.Extensions.Logging ``` -------------------------------- ### Handling System Events Source: https://github.com/kurrent-io/kurrentdb-client-dotnet/blob/master/docs/api/reading-events.md Provides an example of how to filter out system events (those starting with '$' or '$$') when reading from the '$all' stream. ```APIDOC ## Reading $all stream and handling system events ### Description Reads events from the '$all' stream and demonstrates how to ignore system events by checking the EventType. ### Method client.ReadAllAsync ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Request Example ```cs var events = client.ReadAllAsync(Direction.Forwards, Position.Start); await foreach (var e in events) { if (e.Event.EventType.StartsWith("$")) continue; Console.WriteLine(Encoding.UTF8.GetString(e.OriginalEvent.Data.ToArray())); } ``` ### Response #### Success Response (200) An asynchronous stream of events, excluding system events. #### Response Example None provided in source. ``` -------------------------------- ### Add KurrentDB.Client Package Source: https://github.com/kurrent-io/kurrentdb-client-dotnet/blob/master/docs/api/getting-started.md Install the KurrentDB.Client package using the .NET CLI. Ensure you specify the desired version. ```bash dotnet add package KurrentDB.Client --version "1.1.*" ``` -------------------------------- ### Sample Trace Output for Stream Append Source: https://github.com/kurrent-io/kurrentdb-client-dotnet/blob/master/docs/api/observability.md This example shows the detailed trace output generated by a stream append operation. It includes information about the activity ID, span ID, trace flags, source, display name, start time, duration, and associated tags. ```bash Activity.TraceId: 8da04787239dbb85c1f9c6fba1b1f0d6 Activity.SpanId: 4352ec4a66a20b95 Activity.TraceFlags: Recorded Activity.ActivitySourceName: kurrentdb Activity.DisplayName: streams.append Activity.Kind: Client Activity.StartTime: 2024-05-29T06:50:41.2519016Z Activity.Duration: 00:00:00.1500707 Activity.Tags: db.kurrentdb.stream: example-stream server.address: localhost server.port: 2113 db.system: kurrentdb db.operation: streams.append event.count: 3 StatusCode: Ok Resource associated with Activity: service.name: my-eventstore-app service.instance.id: 7316ef20-c354-4e64-97da-c1b99c2c28b0 service.version: 1.0.0 deployment.environment: production telemetry.sdk.name: opentelemetry telemetry.sdk.language: dotnet telemetry.sdk.version: 1.9.0 ``` -------------------------------- ### Run Certificate Generation Script - Windows Source: https://github.com/kurrent-io/kurrentdb-client-dotnet/blob/master/samples/secure-with-tls/README.md Execute this PowerShell script to generate and install TLS certificates on a Windows machine. This script automates the certificate setup. ```powershell .\create-certs.ps1 ``` -------------------------------- ### Creating a Subscription Group to $all Source: https://github.com/kurrent-io/kurrentdb-client-dotnet/blob/master/docs/api/persistent-subscriptions.md This example shows how to create a persistent subscription group that subscribes to all events on the `$all` stream, with optional server-side filtering. ```APIDOC ## Create Persistent Subscription Group to $all ### Description Creates a persistent subscription group for the `$all` stream. Supports server-side filtering. ### Method `POST` (Conceptual - actual method is `CreateToAllAsync` in the .NET client) ### Endpoint `/streams/$all/subscription-groups/{groupName}` (Conceptual) ### Parameters #### Path Parameters - **groupName** (string) - Required - The name of the subscription group. #### Query Parameters - **filter** (StreamFilter) - Optional - Server-side filter to apply to the `$all` stream. #### Request Body - **settings** (PersistentSubscriptionSettings) - Optional - Settings for the persistent subscription. ### Request Example ```cs var settings = new PersistentSubscriptionSettings(); await client.CreateToAllAsync("subscription-group", StreamFilter.Prefix("user"), settings); ``` ``` -------------------------------- ### Basic KurrentDB Client Instrumentation Setup Source: https://github.com/kurrent-io/kurrentdb-client-dotnet/blob/master/docs/api/observability.md Configure basic OpenTelemetry instrumentation for the KurrentDB client using `AddKurrentDBClientInstrumentation()` and `AddConsoleExporter()` within a .NET generic host. ```csharp using KurrentDB.Client.Extensions.OpenTelemetry; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using OpenTelemetry.Resources; using OpenTelemetry.Trace; const string serviceName = "my-eventstore-app"; var host = Host.CreateDefaultBuilder() .ConfigureServices((_, services) => { services.AddOpenTelemetry() .ConfigureResource(builder => builder.AddService(serviceName)) .WithTracing(tracerBuilder => tracerBuilder .AddKurrentDBClientInstrumentation() .AddConsoleExporter() ); }) .Build(); await host.RunAsync(); ``` -------------------------------- ### Creating a Subscription Group to a Specific Stream Source: https://github.com/kurrent-io/kurrentdb-client-dotnet/blob/master/docs/api/persistent-subscriptions.md This example demonstrates how to create a persistent subscription group for a specific stream. Admin permissions are required. ```APIDOC ## Create Persistent Subscription Group to Stream ### Description Creates a persistent subscription group for a specific stream. Admin permissions are required. ### Method `POST` (Conceptual - actual method is `CreateToStreamAsync` in the .NET client) ### Endpoint `/streams/{streamName}/subscription-groups/{groupName}` (Conceptual) ### Parameters #### Path Parameters - **streamName** (string) - Required - The name of the stream to subscribe to. - **groupName** (string) - Required - The name of the subscription group. #### Request Body - **settings** (PersistentSubscriptionSettings) - Optional - Settings for the persistent subscription. ### Request Example ```cs var settings = new PersistentSubscriptionSettings(); await client.CreateToStreamAsync("order-123", "subscription-group", settings); ``` ``` -------------------------------- ### Run Certificate Generation Script - Linux/MacOS Source: https://github.com/kurrent-io/kurrentdb-client-dotnet/blob/master/samples/secure-with-tls/README.md Execute this script to generate and install TLS certificates on Linux, MacOS, or WSL. This simplifies the certificate management process. ```bash ./create-certs.sh ``` -------------------------------- ### Reading All Events Forwards Source: https://github.com/kurrent-io/kurrentdb-client-dotnet/blob/master/docs/api/reading-events.md Demonstrates the basic usage of reading all events from the '$all' stream in a forward direction, starting from the beginning. ```APIDOC ## ReadAllAsync $all stream forwards ### Description Reads events from the '$all' stream in a forward direction, starting from a specified position. ### Method client.ReadAllAsync ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Request Example ```cs var events = client.ReadAllAsync(Direction.Forwards, Position.Start); ``` ### Response #### Success Response (200) An asynchronous stream of events. #### Response Example ```cs await foreach (var e in events) Console.WriteLine(Encoding.UTF8.GetString(e.OriginalEvent.Data.ToArray())); ``` ``` -------------------------------- ### Subscribe to a Stream Source: https://github.com/kurrent-io/kurrentdb-client-dotnet/blob/master/docs/api/subscriptions.md Subscribe to a single stream starting from the beginning. The handler is called for each event from the starting point onward. ```csharp await using var subscription = client.SubscribeToStream("order-123", FromStream.Start); await foreach (var message in subscription.Messages.WithCancellation(ct)) { switch (message) { case StreamMessage.Event(var evnt): Console.WriteLine($"Received event {evnt.OriginalEventNumber}@{evnt.OriginalStreamId}"); break; } } ``` -------------------------------- ### Subscribe to All Streams Source: https://github.com/kurrent-io/kurrentdb-client-dotnet/blob/master/docs/api/subscriptions.md Subscribe to all streams in the database, starting from the beginning. The handler is called for each event from the starting point onward. ```csharp await using var subscription = client.SubscribeToAll(FromAll.Start); await foreach (var message in subscription.Messages) { switch (message) { case StreamMessage.Event(var evnt): Console.WriteLine($"Received event {evnt.OriginalEventNumber}@{evnt.OriginalStreamId}"); break; } } ``` -------------------------------- ### Reading All Events Backwards Source: https://github.com/kurrent-io/kurrentdb-client-dotnet/blob/master/docs/api/reading-events.md Shows how to read all events from the '$all' stream in a backward direction, starting from the end. ```APIDOC ## ReadAllAsync $all stream backwards ### Description Reads events from the '$all' stream in a backward direction, starting from the end position. ### Method client.ReadAllAsync ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Request Example ```cs var events = client.ReadAllAsync(Direction.Backwards, Position.End); ``` ### Response #### Success Response (200) An asynchronous stream of events in reverse order. #### Response Example None provided in source. ``` -------------------------------- ### Read All Events Forwards Source: https://github.com/kurrent-io/kurrentdb-client-dotnet/blob/master/docs/api/reading-events.md Reads all events from the '$all' stream starting from the beginning. Use this to iterate through all recorded events. ```csharp var events = client.ReadAllAsync(Direction.Forwards, Position.Start); ``` -------------------------------- ### $all Subscription from Specific Position Source: https://github.com/kurrent-io/kurrentdb-client-dotnet/blob/master/docs/api/subscriptions.md Subscribe to all events starting from a specific position in the event log. This uses the log's prepare and commit positions. ```APIDOC ## $all Subscription from Specific Position ### Description Subscribes to all events from a specific position in the event log. ### Method ```cs client.SubscribeToAll(FromAll.After(result.LogPosition)) ``` ### Parameters - **fromAll** (FromAll): Specifies the starting point for the subscription, using `FromAll.After` with a `LogPosition`. ### Code Example ```cs var result = await client.AppendToStreamAsync( "order-123", StreamState.NoStream, [ new EventData(Uuid.NewUuid(), "-", ReadOnlyMemory.Empty) ] ); await using var subscription = client.SubscribeToAll( FromAll.After(result.LogPosition) ); await foreach (var message in subscription.Messages) { switch (message) { case StreamMessage.Event(var evnt): Console.WriteLine($"Received event {evnt.OriginalEventNumber}@{evnt.OriginalStreamId}"); break; } } ``` ``` -------------------------------- ### Handle System Events When Reading Source: https://github.com/kurrent-io/kurrentdb-client-dotnet/blob/master/docs/api/reading-events.md Reads events forwards from the start and filters out system events, which typically start with '$' or '$$'. Only user-defined events are processed. ```csharp var events = client.ReadAllAsync(Direction.Forwards, Position.Start); await foreach (var e in events) { if (e.Event.EventType.StartsWith("$")) continue; Console.WriteLine(Encoding.UTF8.GetString(e.OriginalEvent.Data.ToArray())); } ``` -------------------------------- ### Handle Projection Creation Conflict Source: https://github.com/kurrent-io/kurrentdb-client-dotnet/blob/master/docs/api/projections.md Attempting to create a projection that already exists will result in an RpcException with StatusCode.AlreadyExists. This example demonstrates catching this specific error. ```csharp var name = "count-events"; await client.CreateContinuousAsync(name, js); try { await client.CreateContinuousAsync(name, js); } catch (RpcException e) when (e.StatusCode is StatusCode.AlreadyExists) { Console.WriteLine(e.Message); } catch (RpcException e) when (e.Message.Contains("Conflict")) { // will be removed in a future release var format = $"{name} already exists"; Console.WriteLine(format); } ``` -------------------------------- ### Read Stream Forwards with Specific Revision Source: https://github.com/kurrent-io/kurrentdb-client-dotnet/blob/master/docs/api/reading-events.md Demonstrates reading a stream forwards starting from a specific revision obtained from a previous read operation. ```APIDOC ## Read Stream Forwards with Specific Revision ### Description Demonstrates reading a stream forwards starting from a specific revision obtained from a previous read operation. ### Method `ReadStreamAsync` ### Parameters #### Path Parameters - **direction** (Direction) - Required - The direction to read the stream (Forwards). - **streamName** (string) - Required - The name of the stream to read from. - **revision** (StreamPosition or long) - Required - The position in the stream to start reading from. Can be `StreamPosition.Start`, `StreamPosition.End`, a specific revision number, or a `StreamPosition` obtained from a previous read. ### Request Example ```cs var orders = client.ReadStreamAsync( Direction.Forwards, "order-123", StreamPosition.Start ); if (orders.FirstStreamPosition is not null) { var customers = client.ReadStreamAsync( Direction.Forwards, "customer-456", orders.FirstStreamPosition ); } ``` ``` -------------------------------- ### Read All Events Backwards Source: https://github.com/kurrent-io/kurrentdb-client-dotnet/blob/master/docs/api/reading-events.md Reads all events from the '$all' stream starting from the end. Use this to iterate through events in reverse chronological order. ```csharp var events = client.ReadAllAsync(Direction.Backwards, Position.End); ``` -------------------------------- ### Read Events Forwards with User Credentials Source: https://github.com/kurrent-io/kurrentdb-client-dotnet/blob/master/docs/api/reading-events.md Reads events forwards from the start using specified user credentials, overriding connection defaults. A cancellation token can be provided to abort the operation. ```csharp var result = client.ReadAllAsync( Direction.Forwards, Position.Start, userCredentials: new UserCredentials("admin", "changeit"), cancellationToken: cancellationToken ); ``` -------------------------------- ### Get Projection Result as Raw JSON Source: https://github.com/kurrent-io/kurrentdb-client-dotnet/blob/master/docs/api/projections.md Fetches the result of a named projection and partition as a raw JSON string. A delay is included to ensure the projection has sufficient time to compute its result. ```cs const string js = @"fromAll() .when({ $init: function() { return { count: 0 }; }, $any: function(s, e) { s.count += 1; } }) .outputState(); "; var name = "count-events"; await client.CreateContinuousAsync(name, js); await Task.Delay(500); //give it some time to have a result. var document = await client.GetResultAsync(name); Console.WriteLine(document.RootElement.GetRawText()) ``` -------------------------------- ### Read Events Forwards with ResolveLinkTos Source: https://github.com/kurrent-io/kurrentdb-client-dotnet/blob/master/docs/api/reading-events.md Reads events forwards from the start, resolving linked events if `resolveLinkTos` is set to true. This is useful when projections create linked events. ```csharp var result = client.ReadAllAsync( Direction.Forwards, Position.Start, resolveLinkTos: true ); ``` -------------------------------- ### Run Samples with Docker Source: https://github.com/kurrent-io/kurrentdb-client-dotnet/blob/master/samples/secure-with-tls/README.md This command launches both the EventStoreDB server and the client application using Docker Compose, with preconfigured TLS settings. ```bash docker-compose -f docker-compose.yml -f docker-compose.app.yml up ``` -------------------------------- ### Create KurrentDB Projection Management Client Source: https://github.com/kurrent-io/kurrentdb-client-dotnet/blob/master/docs/api/projections.md Instantiate the projection management client with connection settings. Ensure the connection string is correctly formatted. ```csharp var client = new KurrentDBProjectionManagementClient( KurrentDBClientSettings.Create("kurrentdb://localhost:2113?tls=false&tlsVerifyCert=false") ); ``` -------------------------------- ### Create and Connect KurrentDB Client Source: https://github.com/kurrent-io/kurrentdb-client-dotnet/blob/master/docs/api/getting-started.md Instantiate the KurrentDB client with connection settings. The client can be used as a singleton and manages its connection internally. ```cs var client = new KurentDBClient(KurentDBClientSettings.Create("kurrentdb://admin:changeit@localhost:2113?tls=false&tlsVerifyCert=false")); ``` -------------------------------- ### Connecting to $all Source: https://github.com/kurrent-io/kurrentdb-client-dotnet/blob/master/docs/api/persistent-subscriptions.md Demonstrates how to subscribe to all events in a stream using a persistent subscription group. ```APIDOC ## SubscribeToAll ### Description Subscribes to all events in a stream for a given subscription group. ### Method `SubscribeToAllAsync` ### Endpoint N/A (SDK method) ### Parameters - **subscriptionGroupName** (string) - Required - The name of the subscription group. - **cancellationToken** (CancellationToken) - Optional - Token to cancel the operation. ### Request Example ```cs await using var subscription = client.SubscribeToAll("subscription-group", cancellationToken: ct); await foreach (var message in subscription.Messages) { switch (message) { case PersistentSubscriptionMessage.SubscriptionConfirmation(var subscriptionId): Console.WriteLine($"Subscription {subscriptionId} to stream started"); break; case PersistentSubscriptionMessage.Event(var resolvedEvent, _): await HandleEvent(resolvedEvent); break; } } ``` ### Response - **PersistentSubscriptionMessage** - An enumeration of messages received from the subscription, including confirmations and events. ``` -------------------------------- ### Get status of a named projection Source: https://github.com/kurrent-io/kurrentdb-client-dotnet/blob/master/docs/api/projections.md Retrieves the status of a projection identified by its name. ```APIDOC ## Get status Gets the status of a named projection. ### Method ```cs var status = await client.GetStatusAsync(name); ``` ### Parameters #### Path Parameters - **name** (string) - Required - The name of the projection. ### Response #### Success Response - **status** (ProjectionStatus) - The status details of the projection. ``` -------------------------------- ### Basic Server-Side Filtering Source: https://github.com/kurrent-io/kurrentdb-client-dotnet/blob/master/docs/api/subscriptions.md Demonstrates how to subscribe to the '$all' stream with basic server-side filtering using stream name prefixes. ```APIDOC ## Subscribe with Basic Stream Filter ### Description Subscribes to the '$all' stream and filters events based on provided stream name prefixes. ### Method ```csharp client.SubscribeToAll ``` ### Parameters #### filterOptions - **StreamFilter.Prefix** (string[]) - Required - One or more prefixes to filter stream names. ### Request Example ```csharp await using var subscription = client.SubscribeToAll( FromAll.Start, filterOptions: new SubscriptionFilterOptions(StreamFilter.Prefix("test-", "other-")) ); ``` ``` -------------------------------- ### Read Stream Backwards Source: https://github.com/kurrent-io/kurrentdb-client-dotnet/blob/master/docs/api/reading-events.md Reads events from a specified stream in the backward direction, starting from the end of the stream. ```APIDOC ## Read Stream Backwards ### Description Reads events from a specified stream in the backward direction, starting from the end of the stream. ### Method `ReadStreamAsync` ### Parameters #### Path Parameters - **direction** (Direction) - Required - The direction to read the stream (Backwards). - **streamName** (string) - Required - The name of the stream to read from. - **revision** (StreamPosition or long) - Required - The position in the stream to start reading from. Typically `StreamPosition.End` for reading backwards. ### Request Example ```cs var events = client.ReadStreamAsync( Direction.Backwards, "order-123", StreamPosition.End ); await foreach (var e in events) Console.WriteLine(Encoding.UTF8.GetString(e.OriginalEvent.Data.ToArray())); ``` ``` -------------------------------- ### Read Stream Backwards (C#) Source: https://github.com/kurrent-io/kurrentdb-client-dotnet/blob/master/docs/api/reading-events.md Reads all events from a specified stream in the backward direction, starting from the end. ```csharp var events = client.ReadStreamAsync( Direction.Backwards, "order-123", StreamPosition.End ); await foreach (var e in events) Console.WriteLine(Encoding.UTF8.GetString(e.OriginalEvent.Data.ToArray())); ``` -------------------------------- ### Run Client Application Locally Source: https://github.com/kurrent-io/kurrentdb-client-dotnet/blob/master/samples/secure-with-tls/README.md Execute the .NET client application locally. This command can be run from your IDE or the console after setting up the project. ```bash dotnet run ./secure-with-tls.csproj ``` -------------------------------- ### Read Stream Forwards (C#) Source: https://github.com/kurrent-io/kurrentdb-client-dotnet/blob/master/docs/api/reading-events.md Reads all events from a specified stream in the forward direction, starting from the beginning. ```csharp var events = client.ReadStreamAsync(Direction.Forwards, "order-123", StreamPosition.Start); ``` -------------------------------- ### Create KurrentDB Persistent Subscriptions Client Source: https://github.com/kurrent-io/kurrentdb-client-dotnet/blob/master/docs/api/persistent-subscriptions.md Instantiate the KurrentDBPersistentSubscriptionsClient to manage persistent subscriptions. Ensure to configure the connection string appropriately. ```cs await using var client = new KurrentDBPersistentSubscriptionsClient( KurrentDBClientSettings.Create("kurrentdb://localhost:2113?tls=false&tlsVerifyCert=false") ); ``` -------------------------------- ### Create Persistent Subscription Group for '$all' Stream with Filtering Source: https://github.com/kurrent-io/kurrentdb-client-dotnet/blob/master/docs/api/persistent-subscriptions.md Create a subscription group for the '$all' stream, optionally applying server-side filtering using StreamFilter.Prefix. Admin permissions are required. ```cs var settings = new PersistentSubscriptionSettings(); await client.CreateToAllAsync("subscription-group", StreamFilter.Prefix("user"), settings); ``` -------------------------------- ### Stream Subscription from Specific Position Source: https://github.com/kurrent-io/kurrentdb-client-dotnet/blob/master/docs/api/subscriptions.md Subscribe to a stream starting from a specific event revision. Events after this position will be processed. ```APIDOC ## Stream Subscription from Specific Position ### Description Subscribes to a stream from a specific stream revision onwards. ### Method ```cs client.SubscribeToStream("order-123", FromStream.After(StreamPosition.FromInt64(20))) ``` ### Parameters - **streamId** (string): The ID of the stream to subscribe to. - **fromStream** (FromStream): Specifies the starting point for the subscription, using `FromStream.After` with a `StreamPosition`. ### Code Example ```cs await using var subscription = client.SubscribeToStream( "order-123", FromStream.After(StreamPosition.FromInt64(20)) ); await foreach (var message in subscription.Messages) { switch (message) { case StreamMessage.Event(var evnt): Console.WriteLine($"Received event {evnt.OriginalEventNumber}@{evnt.OriginalStreamId}"); break; } } ``` ``` -------------------------------- ### Checkpointing with Default Interval Source: https://github.com/kurrent-io/kurrentdb-client-dotnet/blob/master/docs/api/subscriptions.md Demonstrates how to process messages from a subscription and handle checkpoint notifications, which occur by default after every 32 non-system events. ```APIDOC ## Process Subscription Messages with Checkpointing ### Description Processes messages from a subscription, handling regular events and checkpoint notifications. Checkpoints are automatically sent at a default interval. ### Method ```csharp subscription.Messages ``` ### Parameters #### message - **StreamMessage.Event** - Represents a processed event. - **StreamMessage.AllStreamCheckpointReached** - Represents a checkpoint notification, containing the position. ### Request Example ```csharp var filterOptions = new SubscriptionFilterOptions(EventTypeFilter.ExcludeSystemEvents()); await using var subscription = client.SubscribeToAll(FromAll.Start, filterOptions: filterOptions); await foreach (var message in subscription.Messages) { switch (message) { case StreamMessage.Event(var e): Console.WriteLine($"{e.Event.EventType} @ {e.Event.Position.CommitPosition}"); break; case StreamMessage.AllStreamCheckpointReached(var p): // Save commit position to a persistent store as a checkpoint Console.WriteLine($"checkpoint taken at {p.CommitPosition}"); break; } } ``` ``` -------------------------------- ### Get state of a projection Source: https://github.com/kurrent-io/kurrentdb-client-dotnet/blob/master/docs/api/projections.md Retrieves the current state of a projection. The state can be retrieved as a raw JSON document or as a strongly-typed object. ```APIDOC ## Get state Retrieves the state of a projection. ### Method ```cs var document = await client.GetStateAsync(name); ``` ### Parameters #### Path Parameters - **name** (string) - Required - The name of the projection. ### Response #### Success Response - **document** (JsonDocument) - The state of the projection as a JSON document. ### Typed Result ```cs var result = await client.GetStateAsync(name); ``` #### Response (Typed) - **result** (T) - The state of the projection as a typed object. ``` -------------------------------- ### Configuring Checkpoint Interval Source: https://github.com/kurrent-io/kurrentdb-client-dotnet/blob/master/docs/api/subscriptions.md Shows how to configure the interval at which checkpoint notifications are sent, balancing overhead and recovery time. ```APIDOC ## Configure Subscription Checkpoint Interval ### Description Configures the interval at which the client receives checkpoint notifications from the server. This allows for tuning the balance between checkpointing overhead and recovery speed. ### Method ```csharp new SubscriptionFilterOptions ``` ### Parameters #### checkpointInterval - **int** - Required - The multiplier for the base checkpoint interval (32 events). For example, a value of 1000 means notifications are sent every 32,000 events. ### Request Example ```csharp var filterOptions = new SubscriptionFilterOptions( filter: EventTypeFilter.ExcludeSystemEvents(), checkpointInterval: 1000 ); ``` ``` -------------------------------- ### Connect using X.509 Certificate Source: https://github.com/kurrent-io/kurrentdb-client-dotnet/blob/master/docs/api/authentication.md Use this to connect to KurrentDB when client certificate authentication is required. Ensure both the certificate and private key files are provided. ```csharp const string userCertFile = "/path/to/user.crt"; const string userKeyFile = "/path/to/user.key"; var settings = KurentDBClientSettings.Create( $"kurrentdb://localhost:2113/?tls=true&tlsVerifyCert=true&userCertFile={userCertFile}&userKeyFile={userKeyFile}" ); await using var client = new KurentDBClient(settings); ``` -------------------------------- ### Connect to a Specific Stream with Manual Acknowledgements Source: https://github.com/kurrent-io/kurrentdb-client-dotnet/blob/master/docs/api/persistent-subscriptions.md Connect to a specific stream and manage message acknowledgements manually. Use Ack for successful processing and Nack for failures, specifying the action for failed messages. ```csharp await using var subscription = client.SubscribeToStream( "test-stream", "subscription-group", cancellationToken: ct ); await foreach (var message in subscription.Messages) { switch (message) { case PersistentSubscriptionMessage.SubscriptionConfirmation(var subscriptionId): Console.WriteLine($"Subscription {subscriptionId} to stream with manual acks started"); break; case PersistentSubscriptionMessage.Event(var resolvedEvent, _): try { await HandleEvent(resolvedEvent); await subscription.Ack(resolvedEvent); } catch (UnrecoverableException ex) { await subscription.Nack(PersistentSubscriptionNakEventAction.Park, ex.Message, resolvedEvent); } break; } } ``` -------------------------------- ### Provide User Credentials for Subscription Source: https://github.com/kurrent-io/kurrentdb-client-dotnet/blob/master/docs/api/subscriptions.md Explicitly provide user credentials when creating a subscription to override client-level credentials. This is necessary for subscribing to $all or filtered streams if the default client credentials lack the required permissions. ```cs await using var subscription = client.SubscribeToAll( FromAll.Start, userCredentials: new UserCredentials("admin", "changeit") ); ``` -------------------------------- ### Get result of a named projection and partition Source: https://github.com/kurrent-io/kurrentdb-client-dotnet/blob/master/docs/api/projections.md Retrieves the result of a projection for a specific partition. The result can be fetched as a raw JSON document or as a strongly-typed object. ```APIDOC ## Get result Retrieves the result of the named projection and partition. ### Method ```cs var document = await client.GetResultAsync(name); ``` ### Parameters #### Path Parameters - **name** (string) - Required - The name of the projection. ### Response #### Success Response - **document** (JsonDocument) - The result of the projection as a JSON document. ### Typed Result ```cs var result = await client.GetResultAsync(name); ``` #### Response (Typed) - **result** (T) - The result of the projection as a typed object. ``` -------------------------------- ### Connect to KurrentDB Cluster using DNS Source: https://github.com/kurrent-io/kurrentdb-client-dotnet/blob/master/docs/api/getting-started.md Use this format to connect to a KurrentDB cluster when a DNS A record points to all cluster nodes. The `kurrentdb+discover://` schema enables gossip protocol for cluster information retrieval. ```text kurrentdb+discover://admin:changeit@cluster.dns.name:2113 ``` -------------------------------- ### Connect to $all Stream Source: https://github.com/kurrent-io/kurrentdb-client-dotnet/blob/master/docs/api/persistent-subscriptions.md Connect to an existing subscription group for the '$all' stream. Handles subscription confirmations and event messages. ```csharp await using var subscription = client.SubscribeToAll("subscription-group", cancellationToken: ct); await foreach (var message in subscription.Messages) { switch (message) { case PersistentSubscriptionMessage.SubscriptionConfirmation(var subscriptionId): Console.WriteLine($"Subscription {subscriptionId} to stream started"); break; case PersistentSubscriptionMessage.Event(var resolvedEvent, _): await HandleEvent(resolvedEvent); break; } } ``` -------------------------------- ### Configure Multiple Trace Exporters Source: https://github.com/kurrent-io/kurrentdb-client-dotnet/blob/master/docs/api/observability.md Set up the KurrentDB client instrumentation to use multiple trace exporters simultaneously, such as Console, Jaeger, and OTLP, by chaining exporter configurations. ```csharp using OpenTelemetry.Exporter; var host = Host.CreateDefaultBuilder() .ConfigureServices((_, services) => { services.AddOpenTelemetry() .ConfigureResource(builder => builder.AddService("my-eventstore-app")) .WithTracing(tracerBuilder => tracerBuilder .AddKurrentDBClientInstrumentation() .AddConsoleExporter() .AddJaegerExporter(options => { options.Endpoint = new Uri("http://localhost:14268/api/traces"); }) .AddOtlpExporter(options => { options.Endpoint = new Uri("http://localhost:4318/v1/traces"); }) ); }) .Build(); ``` -------------------------------- ### Read Events from Stream Source: https://github.com/kurrent-io/kurrentdb-client-dotnet/blob/master/docs/api/getting-started.md Read events from a stream in a specified direction starting from a given position. The event payload is returned as a byte array and requires deserialization. ```cs var result = client.ReadStreamAsync( Direction.Forwards, "order-123", StreamPosition.Start ); var events = await result.ToListAsync(); ``` -------------------------------- ### Get Projection Result as Typed Result Source: https://github.com/kurrent-io/kurrentdb-client-dotnet/blob/master/docs/api/projections.md Retrieves the result of a projection and deserializes it into a specified C# class, offering a type-safe way to access projection outcomes. ```cs public class Result { public int count { get; set; } public override string ToString() => $"count= {count}"; }; var result = await client.GetResultAsync(name); ``` -------------------------------- ### Basic $all Subscription Source: https://github.com/kurrent-io/kurrentdb-client-dotnet/blob/master/docs/api/subscriptions.md Subscribe to all events across the database. The handler is called for each existing event and then for new events as they arrive. ```APIDOC ## Basic $all Subscription ### Description Subscribes to all events in the database and processes them from the start. ### Method ```cs client.SubscribeToAll(FromAll.Start) ``` ### Parameters - **fromAll** (FromAll): Specifies the starting point for the subscription (e.g., `FromAll.Start`). ### Code Example ```cs await using var subscription = client.SubscribeToAll(FromAll.Start); await foreach (var message in subscription.Messages) { switch (message) { case StreamMessage.Event(var evnt): Console.WriteLine($"Received event {evnt.OriginalEventNumber}@{evnt.OriginalStreamId}"); break; } } ``` ``` -------------------------------- ### Get Projection Status Source: https://github.com/kurrent-io/kurrentdb-client-dotnet/blob/master/docs/api/projections.md Retrieves the current status of a specific named projection. This includes details like its name, status, checkpoint status, mode, and progress. ```cs const string js = @"fromAll() .when({ $init: function() { return { count: 0 }; }, $any: function(state, event) { state.count += 1; } }) .outputState(); "; var name = "count-events"; await client.CreateContinuousAsync(name, js); var status = await client.GetStatusAsync(name); Console.WriteLine( $@"{status?.Name}, {status?.Status}, {status?.CheckpointStatus}, {status?.Mode}, {status?.Progress}" ); ``` -------------------------------- ### Create a Continuous Projection Source: https://github.com/kurrent-io/kurrentdb-client-dotnet/blob/master/docs/api/projections.md Creates a continuous projection that processes events from the beginning of the store and continues with new events. The JavaScript query defines the projection logic. Projections must have unique names. ```csharp const string js = """ fromAll() .when({ $init: function() { return { count: 0 }; }, $any: function(s, e) { s.count += 1; } }) .outputState(); """; await client.CreateContinuousAsync("count-events", js); ``` -------------------------------- ### Handle Enabling Non-existent Projection Source: https://github.com/kurrent-io/kurrentdb-client-dotnet/blob/master/docs/api/projections.md Demonstrates catching the RpcException when attempting to enable a projection that does not exist. The expected status code is NotFound. ```csharp try { await client.EnableAsync("projection that does not exists"); } catch (RpcException e) when (e.StatusCode is StatusCode.NotFound) { Console.WriteLine(e.Message); } catch (RpcException e) when (e.Message.Contains("NotFound")) { // will be removed in a future release Console.WriteLine(e.Message); } ``` -------------------------------- ### Handle Subscription Caught Up Event Source: https://github.com/kurrent-io/kurrentdb-client-dotnet/blob/master/docs/api/subscriptions.md Detect when a subscription transitions from catching up to live mode by listening for the `CaughtUp` message. This is useful for knowing when the subscription is processing real-time events. ```cs await using var subscription = client.SubscribeToStream("order-123", FromStream.Start); await foreach (var message in subscription.Messages) { switch (message) { case StreamMessage.Event(var evnt): Console.WriteLine($"Received event {evnt.OriginalEventNumber}@{evnt.OriginalStreamId}"); break; case StreamMessage.CaughtUp: Console.WriteLine("Caught up to live mode"); break; } } ``` -------------------------------- ### Connect Consumer to a Persistent Subscription on a Stream Source: https://github.com/kurrent-io/kurrentdb-client-dotnet/blob/master/docs/api/persistent-subscriptions.md Connect a client to an existing persistent subscription group on a specific stream. The bufferSize parameter is crucial for managing message flow and preventing timeouts. ```cs await using var subscription = client.SubscribeToStream( "order-123", "subscription-group", cancellationToken: ct ); await foreach (var message in subscription.Messages) { switch (message) { case PersistentSubscriptionMessage.SubscriptionConfirmation(var subscriptionId): Console.WriteLine($"Subscription {subscriptionId} to stream started"); break; case PersistentSubscriptionMessage.Event(var resolvedEvent, _): await HandleEvent(resolvedEvent); await subscription.Ack(resolvedEvent); break; } } ``` -------------------------------- ### Get Projection State as Typed Result Source: https://github.com/kurrent-io/kurrentdb-client-dotnet/blob/master/docs/api/projections.md Retrieves the state of a projection and deserializes it directly into a specified C# class. This simplifies accessing projection data by providing type safety. ```cs public class Result { public int count { get; set; } public override string ToString() => $"count= {count}"; }; var result = await client.GetStateAsync(name); ``` -------------------------------- ### Create Persistent Subscription Group for a Specific Stream Source: https://github.com/kurrent-io/kurrentdb-client-dotnet/blob/master/docs/api/persistent-subscriptions.md Create a subscription group for a persistent subscription on a specific stream. Admin permissions are required, and attempting to create an existing group will result in an error. ```cs var settings = new PersistentSubscriptionSettings(); await client.CreateToStreamAsync("order-123", "subscription-group", settings); ``` -------------------------------- ### Create a Continuous Projection Source: https://github.com/kurrent-io/kurrentdb-client-dotnet/blob/master/docs/api/projections.md Creates a continuous projection that processes events from the store. The projection runs until the last event and then continues processing new events. Projections can be enabled or disabled by name. ```APIDOC ## Create a Continuous Projection ### Description Creates a projection that runs until the last event in the store, and then continues processing new events as they are appended to the store. The query parameter contains the JavaScript you want created as a projection. Projections have explicit names, and you can enable or disable them via this name. ### Method `CreateContinuousAsync(string name, string query)` ### Parameters #### Path Parameters - `name` (string) - Required - The name of the projection. - `query` (string) - Required - The JavaScript query for the projection. ### Request Example ```cs const string js = @"\n fromAll()\n .when({\n $init: function() {\n return { count: 0 };\n },\n $any: function(s, e) {\n s.count += 1;\n }\n })\n .outputState();\n"; await client.CreateContinuousAsync("count-events", js); ``` ### Error Handling - `StatusCode.AlreadyExists`: If a projection with the same name already exists. ``` -------------------------------- ### Connect to Insecure KurrentDB Instance Source: https://github.com/kurrent-io/kurrentdb-client-dotnet/blob/master/docs/api/getting-started.md Use this connection string format when connecting to an insecure KurrentDB instance. Specify `tls=false` and note that authentication parameters are omitted for insecure deployments. ```plaintext kurrentdb://localhost:2113?tls=false ``` -------------------------------- ### Get Projection State as Raw JSON Source: https://github.com/kurrent-io/kurrentdb-client-dotnet/blob/master/docs/api/projections.md Retrieves the current state of a projection as a raw JSON string. A short delay is included to allow the projection time to process events and generate its state. ```cs const string js = @"fromAll() .when({ $init: function() { return { count: 0 }; }, $any: function(s, e) { s.count += 1; } }) .outputState(); "; var name = $"count-events"; await client.CreateContinuousAsync(name, js); await Task.Delay(500); // give it some time to process and have a state. var document = await client.GetStateAsync(name); Console.WriteLine(document.RootElement.GetRawText()) ``` -------------------------------- ### Read Stream Forwards Source: https://github.com/kurrent-io/kurrentdb-client-dotnet/blob/master/docs/api/reading-events.md Reads events from a specified stream in the forward direction, starting from a given position. Supports options like limiting the count, resolving linked events, and custom operation configurations. ```APIDOC ## Read Stream Forwards ### Description Reads events from a specified stream in the forward direction, starting from a given position. Supports options like limiting the count, resolving linked events, and custom operation configurations. ### Method `ReadStreamAsync` ### Parameters #### Path Parameters - **direction** (Direction) - Required - The direction to read the stream (Forwards or Backwards). - **streamName** (string) - Required - The name of the stream to read from. - **revision** (StreamPosition or long) - Required - The position in the stream to start reading from. Can be `StreamPosition.Start`, `StreamPosition.End`, a specific revision number, or a `StreamPosition` obtained from a previous read. #### Query Parameters - **maxCount** (int) - Optional - The maximum number of events to return. - **resolveLinkTos** (bool) - Optional - If true, KurrentDB will return the event linked to by a projection. - **configureOperationOptions** (Action) - Optional - A function to customize operation settings. - **userCredentials** (UserCredentials) - Optional - Overrides the default credentials for this operation. ### Request Example ```cs var events = client.ReadStreamAsync(Direction.Forwards, "order-123", StreamPosition.Start); ``` ### Response #### Success Response (200) An enumerable of `ResolvedEvent` objects representing the events in the stream. #### Response Example ```cs await foreach (var e in events) Console.WriteLine(Encoding.UTF8.GetString(e.OriginalEvent.Data.ToArray())); ``` ``` -------------------------------- ### Handle Updating Non-existent Projection Source: https://github.com/kurrent-io/kurrentdb-client-dotnet/blob/master/docs/api/projections.md Demonstrates how to catch and handle the RpcException that occurs when attempting to update a projection that does not exist. This ensures graceful error handling in your application. ```cs try { await client.UpdateAsync("Update Not existing projection", "fromAll().when()"); } catch (RpcException e) when (e.StatusCode is StatusCode.NotFound) { Console.WriteLine(e.Message); } catch (RpcException e) when (e.Message.Contains("NotFound")) { // will be removed in a future release Console.WriteLine("'Update Not existing projection' does not exists and can not be updated"); } ``` -------------------------------- ### Reading Events Forwards with User Credentials Source: https://github.com/kurrent-io/kurrentdb-client-dotnet/blob/master/docs/api/reading-events.md Demonstrates how to provide specific user credentials for reading events, overriding default connection credentials. ```APIDOC ## ReadAllAsync $all stream forwards with userCredentials ### Description Reads events from the '$all' stream forwards using specified user credentials, which override the default credentials. ### Method client.ReadAllAsync ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Request Example ```cs var result = client.ReadAllAsync( Direction.Forwards, Position.Start, userCredentials: new UserCredentials("admin", "changeit"), cancellationToken: cancellationToken ); ``` ### Response #### Success Response (200) An asynchronous stream of events, read with the provided credentials. #### Response Example None provided in source. ``` -------------------------------- ### Create and Serialize an Event Source: https://github.com/kurrent-io/kurrentdb-client-dotnet/blob/master/docs/api/getting-started.md Define an event class, create an instance, and serialize it to a UTF-8 byte array for the event payload. JSON serialization is recommended for server-side projections. ```cs using System.Text.Json; public class OrderCreated { public string? OrderId { get; set; } } var evt = new OrderCreated { OrderId = Guid.NewGuid().ToString("N"), }; var orderCreated = new EventData( Uuid.NewUuid(), "OrderCreated", JsonSerializer.SerializeToUtf8Bytes(evt) ); ``` -------------------------------- ### Subscribe to All Streams with Prefix Filtering Source: https://github.com/kurrent-io/kurrentdb-client-dotnet/blob/master/docs/api/subscriptions.md Subscribe to the $all stream and filter events by stream name using prefixes. This is useful for receiving only specific types of events. ```csharp await using var subscription = client.SubscribeToAll( FromAll.Start, filterOptions: new SubscriptionFilterOptions(StreamFilter.Prefix("test-", "other-")) ); ``` -------------------------------- ### Connect to KurrentDB Cluster using Comma-Separated Nodes Source: https://github.com/kurrent-io/kurrentdb-client-dotnet/blob/master/docs/api/getting-started.md Alternatively, list cluster nodes separated by commas instead of using a cluster DNS name. This format is useful when direct node addresses are known. ```text kurrentdb+discover://admin:changeit@node1.dns.name:2113,node2.dns.name:2113,node3.dns.name:2113 ``` -------------------------------- ### Restore Subscription from $all Stream Position Source: https://github.com/kurrent-io/kurrentdb-client-dotnet/blob/master/docs/api/subscriptions.md When subscribing to the $all stream, use this to restore the subscription from its last known position. Remember that $all stream positions involve two integers (prepare and commit). ```cs var checkpoint = FromAll.Start; // or read from a persistent store await using var subscription = client.SubscribeToAll(checkpoint); await foreach (var message in subscription.Messages) { switch (message) { case StreamMessage.Event(var evnt): Console.WriteLine($"Received event {evnt.OriginalEventNumber}@{evnt.OriginalStreamId}"); if (evnt.OriginalPosition is not null) checkpoint = FromAll.After(evnt.OriginalPosition.Value); break; } } ``` -------------------------------- ### Generate CA Certificate Source: https://github.com/kurrent-io/kurrentdb-client-dotnet/blob/master/samples/secure-with-tls/README.md Use this command to generate a Certificate Authority (CA) certificate and key. This CA will be used to sign node certificates. ```bash ./es-gencert-cli create-ca -out ./es-ca ``` -------------------------------- ### Configure Checkpoint Interval Source: https://github.com/kurrent-io/kurrentdb-client-dotnet/blob/master/docs/api/subscriptions.md Configure the checkpoint interval for subscriptions to adjust how often the client is notified about processed events. This balances checkpoint overhead with recovery speed. ```csharp var filterOptions = new SubscriptionFilterOptions( filter: EventTypeFilter.ExcludeSystemEvents(), checkpointInterval: 1000 ); ``` -------------------------------- ### Handle Resetting Non-existent Projection Source: https://github.com/kurrent-io/kurrentdb-client-dotnet/blob/master/docs/api/projections.md Demonstrates catching the RpcException when attempting to reset a projection that does not exist. The expected status code is NotFound. ```csharp try { await client.ResetAsync("projection that does not exists"); } catch (RpcException e) when (e.StatusCode is StatusCode.NotFound) { Console.WriteLine(e.Message); } catch (RpcException e) when (e.Message.Contains("NotFound")) { // will be removed in a future release Console.WriteLine(e.Message); } ``` -------------------------------- ### List Continuous Projections Source: https://github.com/kurrent-io/kurrentdb-client-dotnet/blob/master/docs/api/projections.md Fetches a list of all continuous projections. This is useful for monitoring projections that are designed to run continuously and update their state. ```cs var details = client.ListContinuousAsync(); await foreach (var detail in details) Console.WriteLine( $@"{detail.Name}, {detail.Status}, {detail.CheckpointStatus}, {detail.Mode}, {detail.Progress}" ); ``` -------------------------------- ### Subscribe to All Streams Excluding System Events Source: https://github.com/kurrent-io/kurrentdb-client-dotnet/blob/master/docs/api/subscriptions.md Subscribe to the $all stream and exclude system events, which are prefixed with '$'. This helps in processing only user-defined events. ```csharp await using var subscription = client.SubscribeToAll( FromAll.Start, filterOptions: new SubscriptionFilterOptions(EventTypeFilter.ExcludeSystemEvents()) ); ``` -------------------------------- ### Subscribe to Stream with Link Resolution Source: https://github.com/kurrent-io/kurrentdb-client-dotnet/blob/master/docs/api/subscriptions.md Subscribe to a stream and resolve link-to events by setting `resolveLinkTos` to true. This is useful when dealing with projections that create link-to events. ```csharp await using var subscription = client.SubscribeToStream( "$et-order", FromStream.Start, resolveLinkTos: true ); await foreach (var message in subscription.Messages) { switch (message) { case StreamMessage.Event(var evnt): Console.WriteLine($"Received event {evnt.OriginalEventNumber}@{evnt.OriginalStreamId}"); break; } } ``` -------------------------------- ### Live Updates Only Subscription ($all) Source: https://github.com/kurrent-io/kurrentdb-client-dotnet/blob/master/docs/api/subscriptions.md Subscribe to the end of the event log to receive only new events across all streams as they are appended. ```APIDOC ## Live Updates Only Subscription ($all) ### Description Subscribes to all events and only receives new events appended after the subscription starts. ### Method ```cs client.SubscribeToAll(FromAll.End) ``` ### Parameters - **fromAll** (FromAll): Set to `FromAll.End` to only receive new events. ### Code Example ```cs await using var subscription = client.SubscribeToAll(FromAll.End); ``` ``` -------------------------------- ### List All Projections Source: https://github.com/kurrent-io/kurrentdb-client-dotnet/blob/master/docs/api/projections.md Retrieves a list of all projections, including both user-defined and system projections. The output provides details such as name, status, and progress. ```cs var details = client.ListAllAsync(); await foreach (var detail in details) Console.WriteLine( $@"{detail.Name}, {detail.Status}, {detail.CheckpointStatus}, {detail.Mode}, {detail.Progress}" ); ``` -------------------------------- ### Connecting to a Specific Stream Source: https://github.com/kurrent-io/kurrentdb-client-dotnet/blob/master/docs/api/persistent-subscriptions.md Shows how to subscribe to events from a specific stream using a persistent subscription group with manual acknowledgements. ```APIDOC ## SubscribeToStream ### Description Subscribes to events from a specific stream for a given subscription group, allowing for manual acknowledgements. ### Method `SubscribeToStreamAsync` ### Endpoint N/A (SDK method) ### Parameters - **streamName** (string) - Required - The name of the stream to subscribe to. - **subscriptionGroupName** (string) - Required - The name of the subscription group. - **cancellationToken** (CancellationToken) - Optional - Token to cancel the operation. ### Request Example ```cs await using var subscription = client.SubscribeToStream( "test-stream", "subscription-group", cancellationToken: ct ); await foreach (var message in subscription.Messages) { switch (message) { case PersistentSubscriptionMessage.SubscriptionConfirmation(var subscriptionId): Console.WriteLine($"Subscription {subscriptionId} to stream with manual acks started"); break; case PersistentSubscriptionMessage.Event(var resolvedEvent, _): try { await HandleEvent(resolvedEvent); await subscription.Ack(resolvedEvent); } catch (UnrecoverableException ex) { await subscription.Nack(PersistentSubscriptionNakEventAction.Park, ex.Message, resolvedEvent); } break; } } ``` ### Acknowledgements - **Ack(resolvedEvent)**: Acknowledges successful processing of an event. - **Nack(action, reason, resolvedEvent)**: Not acknowledges an event, specifying an action for the server to take. ### Nack Event Actions | Action | Description | |:----------|:---------------------------------------------------------------------| | `Unknown` | The client does not know what action to take. Let the server decide. | | `Park` | Park the message and do not resend. Put it on poison queue. | | `Retry` | Explicitly retry the message. | | `Skip` | Skip this message do not resend and do not put in poison queue. | ```