### Implement State Projection with IProjection in C# Source: https://context7.com/lokad/azureeventstore/llms.txt Defines how events transform into application state using `Initial` for starting state and `Apply` for event handling. Optionally supports `TrySaveAsync` and `TryLoadAsync` for state caching. This example demonstrates an `OrderProjection`. ```csharp using Lokad.AzureEventStore.Projections; using System.Collections.Immutable; using MessagePack; public sealed class OrderProjection : IProjection { public string FullName => "orders-v1"; public Type State => typeof(OrderState); public bool NeedsMemoryMappedFolder => false; public OrderState Initial(StateCreationContext ctx) => new OrderState(ImmutableDictionary.Empty); public OrderState Apply(uint sequence, IOrderEvent e, OrderState previous) { return e switch { OrderCreated created => new OrderState( previous.Orders.Add(created.OrderId, new OrderState.Order(created.OrderId, created.CustomerName, created.Amount))), OrderCancelled cancelled => new OrderState( previous.Orders.Remove(cancelled.OrderId)), _ => previous }; } public async Task TryLoadAsync(Stream source, CancellationToken cancel) { try { var orders = await MessagePackSerializer.DeserializeAsync< ImmutableDictionary>(source); return new OrderState(orders); } catch { return null; } } public async Task TrySaveAsync(Stream destination, OrderState state, CancellationToken cancel) { await MessagePackSerializer.SerializeAsync(destination, state.Orders); return true; } public Task?> TryRestoreAsync( StateCreationContext ctx, CancellationToken cancel = default) => Task.FromResult?>(null); public Task CommitAsync(OrderState state, uint sequence, CancellationToken cancel = default) => Task.CompletedTask; public Task UpkeepAsync( StateUpkeepContext ctx, OrderState state, CancellationToken cancel = default) => Task.FromResult(state); } ``` -------------------------------- ### Start New Event Stream Service (C#) Source: https://github.com/lokad/azureeventstore/blob/master/README.md Initializes a new EventStreamService instance. It connects to the stream, retrieves events, and builds materialized views. The service is not ready until the catch-up phase is complete. ```csharp var svc = EventStreamService.StartNew( storage: new StorageConfiguration("..."), projections: new[] { new Projection() }, projectionCache: null, log: null, cancel: cancellationToken); ``` -------------------------------- ### Complete Application Example in C# Source: https://context7.com/lokad/azureeventstore/llms.txt Demonstrates service initialization, state access, and transactional event appending for a document indexing application using Lokad.AzureEventStore. It includes event definitions, state representation, and a projection implementation. ```csharp using System.Collections.Immutable; using Lokad.AzureEventStore; using Lokad.AzureEventStore.Cache; using Lokad.AzureEventStore.Projections; // Events public interface IDocEvent { int DocId { get; } } [DataContract] public sealed class DocAdded : IDocEvent { [DataMember] public int DocId { get; private set; } [DataMember] public string Title { get; private set; } [DataMember] public string Content { get; private set; } public DocAdded(int docId, string title, string content) { DocId = docId; Title = title; Content = content; } [JsonConstructor] private DocAdded() { } } // State public sealed record DocState(ImmutableList Documents) { public record Document(int Id, string Title, string Content); } // Projection public sealed class DocProjection : IProjection { public string FullName => "docs-v1"; public Type State => typeof(DocState); public bool NeedsMemoryMappedFolder => false; public DocState Initial(StateCreationContext ctx) => new DocState(ImmutableList.Empty); public DocState Apply(uint seq, IDocEvent e, DocState prev) => e switch { DocAdded d => new DocState(prev.Documents.Add( new DocState.Document(d.DocId, d.Title, d.Content))), _ => prev }; public Task TryLoadAsync(Stream s, CancellationToken c) => Task.FromResult(null); public Task TrySaveAsync(Stream s, DocState st, CancellationToken c) => Task.FromResult(false); public Task?> TryRestoreAsync(StateCreationContext c, CancellationToken t) => Task.FromResult?>(null); public Task CommitAsync(DocState s, uint seq, CancellationToken c) => Task.CompletedTask; public Task UpkeepAsync(StateUpkeepContext c, DocState s, CancellationToken t) => Task.FromResult(s); } // Main application public static async Task Main() { var config = new StorageConfiguration( "DefaultEndpointsProtocol=https;AccountName=myaccount;AccountKey=key==;Container=docs"); var cts = new CancellationTokenSource(); var svc = EventStreamService.StartNew( storage: config, projections: new[] { new DocProjection() }, projectionCache: new MappedCacheProvider("/cache/docs"), projectionFolder: null, log: new ConsoleLogAdapter(), cancel: cts.Token); svc.RefreshPeriod = 60; await svc.Ready; // Add a document transactionally var result = await svc.TransactionAsync(tx => { var nextId = tx.State.Documents.Count; tx.Add(new DocAdded(nextId, "Hello World", "This is my first document.")); return nextId; }); Console.WriteLine($"Added document {result.More}"); // Query current state var state = await svc.CurrentState(CancellationToken.None); foreach (var doc in state.Documents) { Console.WriteLine($"[{doc.Id}] {doc.Title}"); } // Cleanup cts.Cancel(); } ``` -------------------------------- ### Implement Console Logging with ILogAdapter in C# Source: https://context7.com/lokad/azureeventstore/llms.txt Demonstrates how to implement the ILogAdapter interface to capture diagnostic messages from the EventStreamService. This example uses Console.WriteLine for output and can be integrated directly into the service configuration. ```csharp public sealed class ConsoleLogAdapter : ILogAdapter { public void Debug(string message) => Console.WriteLine($"[DEBUG] {DateTime.UtcNow:HH:mm:ss} {message}"); public void Info(string message) => Console.WriteLine($"[INFO] {DateTime.UtcNow:HH:mm:ss} {message}"); public void Warning(string message, Exception? ex = null) { Console.WriteLine($"[WARN] {DateTime.UtcNow:HH:mm:ss} {message}"); if (ex != null) Console.WriteLine($" {ex.GetType().Name}: {ex.Message}"); } public void Error(string message, Exception? ex = null) { Console.WriteLine($"[ERROR] {DateTime.UtcNow:HH:mm:ss} {message}"); if (ex != null) Console.WriteLine($" {ex}"); } } // Usage with service var service = EventStreamService.StartNew( storage: config, projections: new[] { new OrderProjection() }, projectionCache: new MappedCacheProvider("/cache"), projectionFolder: null, log: new ConsoleLogAdapter(), // Receives all diagnostic messages cancel: cts.Token); ``` -------------------------------- ### Configure Storage Backend in C# Source: https://context7.com/lokad/azureeventstore/llms.txt Sets up the storage configuration for the event store, supporting various backends. Examples include Azure Blob Storage connection strings, local file paths for development, in-memory storage for testing, and options for enabling caching, read-only modes, and request tracing. ```csharp // Azure Blob Storage configuration var azureConfig = new StorageConfiguration( "DefaultEndpointsProtocol=https;AccountName=mystorageaccount;AccountKey=base64key==;Container=myevents"); // Local file storage for development var localConfig = new StorageConfiguration("/var/data/events"); // Enable local caching of remote events var cachedConfig = new StorageConfiguration( "DefaultEndpointsProtocol=https;AccountName=myaccount;AccountKey=key==;Container=events") { CachePath = "/var/cache/event-stream", // Cache events locally ReadOnly = false, // Allow writes Trace = true // Enable request tracing }; // In-memory storage for testing var memoryStream = new MemoryStream(); var testConfig = new StorageConfiguration(memoryStream); // Single-blob storage for smaller event streams var monoBlobConfig = azureConfig.MonoBlob("orders-stream"); ``` -------------------------------- ### Configure Projection Caching with MappedCacheProvider in C# Source: https://context7.com/lokad/azureeventstore/llms.txt Shows how to configure MappedCacheProvider for projection snapshots, reducing startup time. Examples include local-only caching and hybrid caching with Azure Blob Storage backup. The cache configuration is passed to the EventStreamService. ```csharp using Lokad.AzureEventStore.Cache; // Local-only cache var localCache = new MappedCacheProvider("/var/cache/projections") { MaxCacheFilesCount = 4 // Keep last 4 cache files }; // Cache with Azure Blob Storage backup var azureCache = new AzureCacheProvider( new BlobContainerClient(connectionString, "projection-cache")); var hybridCache = new MappedCacheProvider( directory: "/var/cache/projections", inner: azureCache // Falls back to Azure if local cache misses ); // Use with service var service = EventStreamService.StartNew( storage: config, projections: new[] { new OrderProjection() }, projectionCache: hybridCache, projectionFolder: null, log: new ConsoleLogAdapter(), cancel: cts.Token); // Manually trigger cache save await service.TrySaveAsync(CancellationToken.None); ``` -------------------------------- ### C# Migration Concierge for Event Stream Source: https://github.com/lokad/azureeventstore/blob/master/README.md Demonstrates how to create a migration concierge in C# to migrate events from a current stream to a new stream. It uses EventStream and MigrationStream to read and write events, with an option to filter or drop specific event types. The example includes refreshing the current stream to catch new events. ```csharp var currentStream = new EventStream(currentConfig); var newStream = new MigrationStream(newConfig); await newStream.MigrateFromAsync( currentStream, // Drop events of type 'ObsoletEvent' (IMyEvent ev, uint _seq) => ev is ObseleteEvent ? null : ev, // When reaching the end of 'currentStream', refresh it every 2 seconds // to see if new events have appeared TimeSpan.FromSeconds(2), default(CancellationToken)); ``` -------------------------------- ### Initialize Event Stream Service with Lokad.AzureEventStore Source: https://context7.com/lokad/azureeventstore/llms.txt Creates and starts a new `EventStreamService` for managing event streams in Azure Blob Storage. It connects to storage, loads events, applies projections to build state, and maintains background synchronization. Requires `Lokad.AzureEventStore` and `System.Threading`. ```csharp using Lokad.AzureEventStore; using Lokad.AzureEventStore.Cache; using System.Threading; // Define your event interface public interface IOrderEvent { Guid OrderId { get; } } // Define event types [DataContract] public sealed class OrderCreated : IOrderEvent { [DataMember] public Guid OrderId { get; private set; } [DataMember] public string CustomerName { get; private set; } [DataMember] public decimal Amount { get; private set; } public OrderCreated(Guid orderId, string customerName, decimal amount) { OrderId = orderId; CustomerName = customerName; Amount = amount; } [JsonConstructor] private OrderCreated() { } } // Define immutable state public sealed class OrderState { public ImmutableDictionary Orders { get; } public OrderState(ImmutableDictionary orders) => Orders = orders; public record Order(Guid Id, string CustomerName, decimal Amount); } // Start the service var connectionString = "DefaultEndpointsProtocol=https;AccountName=myaccount;AccountKey=mykey;Container=events"; var config = new StorageConfiguration(connectionString); var cts = new CancellationTokenSource(); var service = EventStreamService.StartNew( storage: config, projections: new[] { new OrderProjection() }, projectionCache: new MappedCacheProvider("/var/cache/orders"), projectionFolder: null, log: new ConsoleLogAdapter(), cancel: cts.Token); // Wait for initialization to complete await service.Ready; Console.WriteLine($"Service ready. Current sequence: {service.Sequence}"); ``` -------------------------------- ### C# Testing: In-Memory Event Stream Source: https://github.com/lokad/azureeventstore/blob/master/README.md Initializes a non-persistent, in-memory event stream for unit testing purposes. This allows for quick setup of initial stream states without requiring external storage. ```csharp Testing.Initialize(); Testing.Initialize(initialEvents); ``` -------------------------------- ### Implement Custom Event Serialization with MessagePack in C# Source: https://context7.com/lokad/azureeventstore/llms.txt Provides an example of implementing a custom event serializer using MessagePack for improved performance. The MessagePackEventSerializer implements IEventSerializer and defines a unique tag byte. Custom serializers are passed to the EventStreamService. ```csharp using MessagePack; public sealed class MessagePackEventSerializer : IEventSerializer { // Tag byte identifies this serializer (must not conflict with JSON's '{' = 0x7B) public byte Tag => 0x01; public IOrderEvent Deserialize(ReadOnlyMemory data) { // Skip the tag byte var payload = data.Slice(1); return MessagePackSerializer.Deserialize(payload); } public Memory Serialize(IOrderEvent e, byte[] buffer, int position) { buffer[position] = Tag; using var ms = new MemoryStream(buffer, position + 1, buffer.Length - position - 1); MessagePackSerializer.Serialize(ms, e); return buffer.AsMemory(position, (int)ms.Position + 1); } } // Use custom serializer with service var serializers = new IEventSerializer[] { new MessagePackEventSerializer(), // JsonEventSerializer is added automatically if not present }; var service = EventStreamService.StartNew( storage: config, projections: new[] { new OrderProjection() }, projectionCache: cache, projectionFolder: null, log: new ConsoleLogAdapter(), cancel: cts.Token, serializers: serializers); ``` -------------------------------- ### Execute Transactional Event Appends in C# Source: https://context7.com/lokad/azureeventstore/llms.txt Provides optimistic concurrency for appending events. The callback receives a transaction object with current state, allows adding events via `transaction.Add()`, and returns a result. The callback is replayed automatically if the stream is modified concurrently. Examples show transactions with and without return values, and with abort capability. ```csharp // Transaction that reads state and conditionally adds events var result = await service.TransactionAsync(transaction => { var state = transaction.State; var orderId = Guid.NewGuid(); // Business logic: check state before adding events if (state.Orders.Count >= 1000) throw new InvalidOperationException("Order limit reached"); // Add event to transaction - state is updated immediately transaction.Add(new OrderCreated(orderId, "John Doe", 99.99m)); // Can read updated state within transaction Console.WriteLine($"Order count after add: {transaction.State.Orders.Count}"); // Return value is included in AppendResult return orderId; }, CancellationToken.None); Console.WriteLine($"Created order {result.More}, sequence starts at {result.First}"); // Transaction without return value await service.TransactionAsync(transaction => { var orderToCancel = transaction.State.Orders.Values.FirstOrDefault(); if (orderToCancel != null) { transaction.Add(new OrderCancelled(orderToCancel.Id)); } }, CancellationToken.None); // Transaction with abort capability await service.TransactionAsync(transaction => { if (!ShouldProceed()) { transaction.Abort(); // No events will be written return; } transaction.Add(new OrderCreated(Guid.NewGuid(), "Jane Doe", 149.99m)); }); ``` -------------------------------- ### Implement Custom Event Serializer in C# for Azure Event Store Source: https://github.com/lokad/azureeventstore/blob/master/README.md Provides a C# implementation of a custom event serializer for Azure Event Store by implementing the 'IEventSerializer' interface. This includes methods for serializing and deserializing events using a specific tag byte, allowing for multiple serializers in the same stream. ```csharp public sealed class CustomEventSerializer : IEventSerializer { // The tag is a single byte that identifies the serializer used to write // an individual event. It allows multiple serializers to coexist in the // same stream, and allows the library to automatically detect the serializer // used to read an event. public byte Tag => (byte)'O'; // Write the event to the given buffer, with its first byte at the given // position, and return the written bytes. The returned memory may never // exceed 512 KiB. When this method is called, the remaining space in // the buffer will always be at least 512KiB. public Memory Serialize(IOneEvent e, byte[] buffer, int position) { // The first byte must always be the tag? buffer[position] = Tag; int length = // Write e to buffer.AsSpan(position + 1) return buffer.AsMemory(position, 1 + length); } // Deserializes the event from the given buffer. The buffer begins with the same // data as was returned by Serialize(), but may contain additional data after it // which should be ignored. public IEvent Deserialize(ReadOnlyMemory data) { var span = data.Span; // The Tag should always appear as the first byte of the event. if (span[0] != Tag) throw new InvalidOperationException($"Unexpected tag 0x{span[0]:X2}."); IEvent readEvent = // Read an event from span[1..] return readEvent; } } ``` -------------------------------- ### Access Current and Local State in C# Source: https://context7.com/lokad/azureeventstore/llms.txt Retrieves the projected state from the event store. `CurrentState` provides fully synchronized state, potentially involving network I/O, while `LocalState` offers faster access to a locally cached state that may be slightly stale. The `IsReady` property and `Ready` task can be used to manage initialization and ensure state is available. ```csharp // Get fully synchronized state (includes any remote events) var currentState = await service.CurrentState(CancellationToken.None); Console.WriteLine($"Total orders (current): {currentState.Orders.Count}"); // Get local state (faster, may be slightly stale) if (service.IsReady) { var localState = service.LocalState; Console.WriteLine($"Total orders (local): {localState.Orders.Count}"); Console.WriteLine($"Local sequence: {service.Sequence}"); // Process orders from local state foreach (var order in localState.Orders.Values.Take(10)) { Console.WriteLine($" Order {order.Id}: {order.CustomerName} - ${order.Amount}"); } } // Check readiness before accessing state if (!service.IsReady) { Console.WriteLine($"Loading... {service.Sequence}/{service.RemoteSequence} events processed"); await service.Ready; // Wait for initialization } // Set refresh period (how often LocalState catches up) service.RefreshPeriod = 30; // seconds ``` -------------------------------- ### C# Storage Configuration: Local File Path Source: https://github.com/lokad/azureeventstore/blob/master/README.md Configures the storage location for an event stream using a local file path. This is suitable for development and testing but not for production use due to its lack of support for concurrent access. ```csharp new StorageConfiguration(@"C:\MyStream"); new StorageConfiguration(@".\MyStream"); ``` -------------------------------- ### C# Projection: Initial State Implementation Source: https://github.com/lokad/azureeventstore/blob/master/README.md Defines the initial state for a projection. This state is applied to the first event in the stream. It requires an initial state object, typically an empty immutable dictionary. ```csharp public State Initial => new State(ImmutableDictionary.Empty); ``` -------------------------------- ### C# Projection: Apply Event to State Source: https://github.com/lokad/azureeventstore/blob/master/README.md Implements the core logic of a projection by defining how to transition from a previous state to a new state based on an incoming event. This function should handle different event types and must not rely on event order. It returns the new state after applying the event. ```csharp public State Apply(uint sequence, IEvent e, State previous) { if (e is ValueDeleted d) return new State(previous.Bindings.Remove(d.Key)); if (e is ValueUpdated u) return new State(previous.Bindings.SetItem(u.Key, u.Value)); throw new ArgumentOutOfRangeException(nameof(e), "Unknown event type " + e.GetType()); } ``` -------------------------------- ### CurrentState and LocalState Source: https://context7.com/lokad/azureeventstore/llms.txt Provides access to the projected state of the event stream. `CurrentState` returns the fully synchronized state, potentially involving network I/O, while `LocalState` returns the locally cached state, which may be slightly stale. ```APIDOC ## GET /state ### Description Retrieves the projected state of the event stream. `CurrentState` fetches the most up-to-date state, including remote events, while `LocalState` provides a faster, locally cached version that might be slightly delayed. The `IsReady` property indicates if the local state is available, and `Ready` can be awaited for initialization. ### Method GET ### Endpoint /state ### Parameters #### Query Parameters - **CancellationToken** (CancellationToken) - Optional - Cancellation token for the operation. ### Response #### Success Response (200) - **CurrentState** (object) - The fully synchronized state of the event stream. - **LocalState** (object) - The locally cached state of the event stream. - **IsReady** (bool) - Indicates if the local state is ready for access. - **Sequence** (long) - The sequence number of the last processed event in the local state. - **RemoteSequence** (long) - The sequence number of the last known event in the remote stream. #### Response Example ```json { "CurrentState": { "Orders": [ { "Id": "guid1", "CustomerName": "Customer A", "Amount": 50.00 }, { "Id": "guid2", "CustomerName": "Customer B", "Amount": 75.00 } ] }, "LocalState": { "Orders": [ { "Id": "guid1", "CustomerName": "Customer A", "Amount": 50.00 } ] }, "IsReady": true, "Sequence": 100, "RemoteSequence": 102 } ``` ``` -------------------------------- ### StorageConfiguration Source: https://context7.com/lokad/azureeventstore/llms.txt Configures the backend storage for the event stream. Supports various options including Azure Blob Storage, local file paths, in-memory storage, and enables features like caching, read-only modes, and tracing. ```APIDOC ## POST /storage/configure ### Description Configures the storage backend for the event stream. This endpoint allows specifying connection strings for Azure Blob Storage, local file paths, or in-memory streams. Optional settings include enabling local caching, setting read-only mode, and enabling request tracing. It also supports configuring single-blob storage. ### Method POST ### Endpoint /storage/configure ### Parameters #### Request Body - **connectionStringOrPath** (string | Stream) - Required - The connection string for Azure Blob Storage, a local file path, or an in-memory stream. - **cachePath** (string) - Optional - Path for local caching of remote events. - **readOnly** (bool) - Optional - If true, the storage will be in read-only mode. - **trace** (bool) - Optional - If true, request tracing will be enabled. - **monoBlobName** (string) - Optional - If specified, configures single-blob storage with the given name. ### Request Example ```json { "connectionStringOrPath": "DefaultEndpointsProtocol=https;AccountName=mystorageaccount;AccountKey=base64key==;Container=myevents", "cachePath": "/var/cache/event-stream", "readOnly": false, "trace": true } ``` ### Response #### Success Response (200) - **Status** (string) - Indicates the success of the configuration operation. #### Response Example ```json { "Status": "Storage configuration updated successfully." } ``` ``` -------------------------------- ### C# Storage Configuration: Azure Connection String Source: https://github.com/lokad/azureeventstore/blob/master/README.md Configures the storage location for an event stream using an Azure Storage connection string. This can be a read-write connection string or one with a Shared Access Signature (SAS) for read-only access. Optionally, a specific container can be specified. ```csharp new StorageConfiguration("DefaultEndpointsProtocol=..."); new StorageConfiguration("BlobEndpoint=..."); new StorageConfiguration("DefaultEndpointsProtocol=...;Container=..."); ``` -------------------------------- ### C# State Service for Azure Event Store CQRS Source: https://github.com/lokad/azureeventstore/blob/master/stream-readiness.md Implements a StateService class for managing application state using Azure Event Store and CQRS. It handles event streaming, projection caching, and state retrieval with error handling for service unavailability. Dependencies include Lokad.AzureEventStore, and custom domain event/state types. ```csharp using Lokad.AzureEventStore; using Lokad.AzureEventStore.Projections; using Foobar.Backend.Domain.Events; using Foobar.Backend.Domain.Projections; using Foobar.Backend.Domain.State; namespace Foobar.Backend.Domain.Host; public class StateServiceUnavailableException : Exception { public StateServiceUnavailableException(Exception e) : base("StateService is not ready yet.", e) { } public StateServiceUnavailableException(string msg) : base(msg) { } } /// Provides read-write access to the shared application state. public sealed class StateService { public readonly EventStreamService Stream; public static StateService StartNew( StorageConfiguration storage, IProjectionCacheProvider projectionCache, CancellationToken cancel) { return new StateService(storage, projectionCache, cancel); } private StateService( StorageConfiguration storage, IProjectionCacheProvider projectionCache, CancellationToken cancel) { var proj = new NewsStateProjection(); Stream = EventStreamService.StartNew( storage, new IProjection[] { proj }, projectionCache, new LogAdapter(), cancel); Stream.Ready.ContinueWith(_ => Stream.TrySaveAsync(cancel)); } /// Is the state ready ? /// Accessing the state before it's ready will throw exceptions. public bool Ready => Stream.IsReady; /// The current state (same as from ) updated with the last changes. public async Task Current(CancellationToken cancel) { using var cts = new CancellationTokenSource(); try { var race = Task.Delay(TimeSpan.FromSeconds(5), cts.Token); var state = Stream.CurrentState(cancel); await Task.WhenAny(race, state).ConfigureAwait(false); if (state.IsCompleted) return (await state); throw new StateServiceUnavailableException("StateService cannot be refreshed."); } catch (StreamNotReadyException e) { throw new StateServiceUnavailableException(e); } finally { cts.Cancel(); } } /// The local current state, which may not have catched up at the call time. /// To have an updated current state, call . public FoobarState LocalCurrent => Stream.LocalState; } ``` -------------------------------- ### Append Events Asynchronously with State-Based Logic in C# Source: https://context7.com/lokad/azureeventstore/llms.txt Appends events to the event store using a builder function that takes the current state and returns an Append struct. This method allows for state-based event construction and can handle conflicts by retrying the builder. It supports returning additional data alongside the appended events. ```csharp // Simple append with state-based event construction var appendResult = await service.AppendEventsAsync(state => { var nextId = Guid.NewGuid(); return service.Use( new OrderCreated(nextId, "Customer A", 50.00m), new OrderCreated(Guid.NewGuid(), "Customer B", 75.00m) ); }, CancellationToken.None); Console.WriteLine($"Appended {appendResult.Count} events starting at sequence {appendResult.First}"); // Append with additional return data var resultWithData = await service.AppendEventsAsync(state => { var newOrderId = Guid.NewGuid(); return service.With( more: newOrderId, // This value is returned in AppendResult.More new OrderCreated(newOrderId, "Customer C", 200.00m) ); }, CancellationToken.None); Console.WriteLine($"Created order with ID: {resultWithData.More}"); // Direct append without state inspection (use with caution - no conflict detection) await service.AppendEventsAsync( new IOrderEvent[] { new OrderCreated(Guid.NewGuid(), "Direct", 10.00m) }, CancellationToken.None); ``` -------------------------------- ### Append Events and Return Result (C#) Source: https://github.com/lokad/azureeventstore/blob/master/README.md Appends events to the stream and allows returning a result from the builder function. This is useful for scenarios where you need to retrieve data, such as the ID of a newly created item, after the append operation. ```csharp // Another occurence of 'word' has been found var result = await service.AppendEventsAsync(state => { state.Bindings.TryGetValue(word, out int currentCount); return service.With( currentCount + 1, // Return the new count new ValueUpdated(word, currentCount + 1)); }, CancellationToken.None); var newCount = result.Result; ``` -------------------------------- ### Perform Transaction to Append Events (C#) Source: https://github.com/lokad/azureeventstore/blob/master/README.md Appends events to the stream within a transaction. If the transaction builder throws an exception, the transaction is automatically rolled back. Transactions can also be explicitly aborted. The state is updated after each event is added. ```csharp var email = "..."; await service.TransactionAsync(transaction => { // Throwing automatically rolls back the transaction if (transaction.State.Emails.ContainsKey(email)) throw new ArgumentException("Mail already exists"); // Events added to the transaction are appended to the stream // after it ends. transaction.Add(new EmailAdded(email)); // After each Add() the state of the transaction is updated. // This also means that if the event causes the projection to // throw, the exception will interrupt the transaction. var mailCount = transaction.State.Emails.Count; // Transactions can be aborted. transaction.Abort(); }, cancellationToken); ``` -------------------------------- ### Define Immutable State Class in C# for Azure Event Store Source: https://github.com/lokad/azureeventstore/blob/master/README.md Defines a C# class 'State' to represent the immutable application state, utilizing an 'ImmutableDictionary' to store word tallies. This immutable nature ensures thread-safe reads while events are being applied. ```csharp public sealed class State { public State(ImmutableDictionary bindings) { Bindings = bindings; } public ImmutableDictionary Bindings { get; } } ``` -------------------------------- ### AppendEventsAsync Source: https://context7.com/lokad/azureeventstore/llms.txt Appends events to the event store using a builder function that can incorporate state-based logic and conflict resolution. It supports returning additional data alongside the appended events. ```APIDOC ## POST /events ### Description Appends events to the event store using a builder function that receives the current state and returns an `Append` struct. The builder may be called multiple times on conflict but doesn't provide immediate state updates within the callback. Supports returning additional data via the `With` method. ### Method POST ### Endpoint /events ### Parameters #### Query Parameters - **CancellationToken** (CancellationToken) - Optional - Cancellation token for the operation. #### Request Body - **state** (Func>) - Required - A builder function that receives the current state and returns an `Append` struct containing the events to append. - **more** (object) - Optional - Additional data to be returned with the append result. ### Request Example ```json { "state": "(state) => service.Use(new OrderCreated(Guid.NewGuid(), \"Customer A\", 50.00m))" } ``` ### Response #### Success Response (200) - **Count** (int) - The number of events appended. - **First** (long) - The sequence number of the first appended event. - **More** (object) - Additional data returned from the `With` method in the request. #### Response Example ```json { "Count": 2, "First": 100, "More": "order-123" } ``` ``` -------------------------------- ### Define C# Event Contracts for Azure Event Store Source: https://github.com/lokad/azureeventstore/blob/master/README.md Defines C# record types for 'ValueUpdated' and 'ValueDeleted' events, implementing the 'IEvent' interface for use with Azure Event Store. These events are JSON-serializable and marked with DataContract and DataMember attributes. ```csharp [DataContract] public sealed record ValueUpdated( [property: DataMember] string Key, [property: DataMember] int Value) : IEvent; [DataContract] public sealed record ValueDeleted( [property: DataMember] string Key) : IEvent; ``` -------------------------------- ### Append Events Directly to Stream (C#) Source: https://github.com/lokad/azureeventstore/blob/master/README.md Appends events directly to the event stream using a builder function. If a conflict occurs due to concurrent writes, the service automatically retries by fetching new events and updating the state before calling the builder again. ```csharp // Another occurence of 'word' has been found await service.AppendEventsAsync(state => { state.Bindings.TryGetValue(word, out int currentCount); return service.Use(new ValueUpdated(word, currentCount + 1)); }, CancellationToken.None) ``` -------------------------------- ### C# Testing: Retrieve Events from In-Memory Stream Source: https://github.com/lokad/azureeventstore/blob/master/README.md Retrieves all events currently stored in an in-memory event stream. This function is intended for unit testing to inspect the state of the stream after operations. ```csharp Testing.GetEvents(); ``` -------------------------------- ### C# Projection: State Type Declaration Source: https://github.com/lokad/azureeventstore/blob/master/README.md Declares the type of the state object used by the projection. This is essential for reflection, enabling the system to identify the correct projection for a given materialized view. ```csharp public Type State => typeof(State); ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.