{"id":16083848,"url":"https://github.com/eventstorage/eventstorage","last_synced_at":"2025-10-13T10:37:13.013Z","repository":{"id":254359169,"uuid":"846050866","full_name":"eventstorage/eventstorage","owner":"eventstorage","description":"Lightweight event sourcing framework with event storage of choice.","archived":false,"fork":false,"pushed_at":"2024-12-10T21:54:47.000Z","size":551,"stargazers_count":5,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2024-12-13T09:07:01.442Z","etag":null,"topics":["azuresql","cicd","dotnet","event-driven","event-sourcing","event-store","eventstorage","postgres","sqlserver"],"latest_commit_sha":null,"homepage":"","language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/eventstorage.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-08-22T12:47:26.000Z","updated_at":"2024-12-10T21:54:02.000Z","dependencies_parsed_at":"2025-01-02T22:25:23.280Z","dependency_job_id":"8e471e16-c1a7-4d5d-8dea-757906c429af","html_url":"https://github.com/eventstorage/eventstorage","commit_stats":{"total_commits":98,"total_committers":2,"mean_commits":49.0,"dds":"0.15306122448979587","last_synced_commit":"74d25e49115559129f2c28d90ec15388177c6119"},"previous_names":["asynchandler/asynchandler.eventsourcing","eventstorage/eventstorage"],"tags_count":30,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/eventstorage%2Feventstorage","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/eventstorage%2Feventstorage/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/eventstorage%2Feventstorage/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/eventstorage%2Feventstorage/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/eventstorage","download_url":"https://codeload.github.com/eventstorage/eventstorage/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248410877,"owners_count":21098789,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["azuresql","cicd","dotnet","event-driven","event-sourcing","event-store","eventstorage","postgres","sqlserver"],"created_at":"2024-10-09T12:06:22.838Z","updated_at":"2025-10-13T10:37:07.977Z","avatar_url":"https://github.com/eventstorage.png","language":"C#","funding_links":[],"categories":[],"sub_categories":[],"readme":"# eventstorage\n\n### A lightweight event sourcing framework for .NET with event storage of choice.\n\n[![Github follow](https://img.shields.io/badge/follow-eventstorage-bf9136?logo=github)](https://github.com/eventstorage)\n[![Nuget Package](https://badgen.net/nuget/v/eventstorage)](https://www.nuget.org/packages/eventstorage)\n[![Nuget](https://badgen.net/nuget/dt/eventstorage)](https://www.nuget.org/packages/eventstorage)\n[![Github follow](https://img.shields.io/badge/give_us_a-⭐-yellow?logo=github)](https://github.com/eventstorage/eventstorage)\n[![In follow](https://img.shields.io/badge/follow-LinkedIn-blue?logo=linkedin)](https://www.linkedin.com/in/sarwansurchi/)\n[![build Status](https://dev.azure.com/eventstorage/eventstorage/_apis/build/status%2Feventstorage?branchName=main\u0026label=azure%20pipes)](https://dev.azure.com/eventstorage/eventstorage/_build/latest?definitionId=1\u0026branchName=main)\n\n\u003cdiv align=\"left\"\u003e\n    \u003cimg src=\".assets/2.png\" width=\"120\" height=\"120\" style=\"float:left;\" alt=\"eventstorage\"\u003e\n\u003c/div\u003e\n\n## Overview\n\neventstorage is a high-performance event sourced infrastructure out of the box, powered by latest\ninnovative C# that allows selecting event storage of choice with `Azure Sql`, `Postgres` and `Sql Server`,\nand offers multiple projection modes with support to `Redis` for high-performance asynchronous projections.\n\n#### Key benefits of eventstorage\n* Runs plain sql resulting in high-performance storage infrastructure \n* Flexible schema gains with denormalization and throwing away ORM\n* Identifies aggregates with `GUID` and `long` and allows switching back and forth\n* Lightning-fast storage operations by selecting `long` aggregate identifier\n* Allows event storage selection with `Azure Sql`, `Postgre Sql` and `Sql Server`\n* Offers transient/runtime, ACID-compliant and async projections modes\n* Allows projection source as either selected storage or high-performance `Redis`\n* Lightweight asynchronous projection engine that polls for async projections\n* Restores projections at startup ensuring consistency without blocking business\n* Designed to survive failures and prevents possible inconsistencies\n\n## Environment setup\n\n[![My Skills](https://skillicons.dev/icons?i=dotnet)](https://dotnet.microsoft.com/en-us/download/dotnet/8.0)\n\neventstorage runs on .Net 8 and requires the SDK installed:\n\n    https://dotnet.microsoft.com/en-us/download/dotnet/8.0\n\n[![My Skills](https://skillicons.dev/icons?i=docker)](https://dotnet.microsoft.com/en-us/download/dotnet/8.0)\n\nUse docker to run mssql or postgres databases, execute `docker-compose` or `docker run`:\n```sh\ndocker compose --project-name eventstorage up -d\n```\n`Postgres`\n```sh\ndocker run --name some-postgres -p 5432:5432 -e POSTGRES_PASSWORD=postgres -d postgres\n```\n`Sql Server`\n```sh\ndocker run --name some-mssql -p 1433:1433 -e \"ACCEPT_EULA=Y\" -e \"MSSQL_SA_PASSWORD=sysadmin@1234\" -d mcr.microsoft.com/mssql/server:2019-latest\n```\nOptionally run `Redis` for high-performance projections:\n```sh\ndocker run -d --name redis-stack -p 6379:6379 -p 8001:8001 redis/redis-stack:latest\n```\n\n## Getting started\n\n[![My Skills](https://skillicons.dev/icons?i=vscode)](https://dotnet.microsoft.com/en-us/download/dotnet/8.0)\n#### Install the package\n\n###### Simply install `EventStorage` package.\n```sh\ndotnet add package EventStorage --prerelease\n```\n#### Configure event storage\n\n###### Use `AddEventStorage` service collection extension.\n\n```csharp\nbuilder.Services.AddEventStorage(storage =\u003e\n{\n    storage.Schema = \"es\";\n    storage.AddEventSource(source =\u003e\n    {\n        source.Select(EventStore.PostgresSql, connectionString);\n    });\n});\n```\nUse configuration options to select your event storage of choice and make sure connection string is defined.\n\n#### Create aggregate root\n###### Add your aggregate with `EventSource\u003cTId\u003e`\n\n```csharp\npublic class OrderBooking : EventSource\u003clong\u003e // or Guid\n{\n    public OrderStatus OrderStatus { get; private set; }\n    public void Apply(OrderPlaced e)\n    {\n        OrderStatus = OrderStatus.Placed;\n    }\n    public void PlaceOrder(PlaceOrder command)\n    {\n        if(OrderStatus == OrderStatus.Placed)\n            return;\n        RaiseEvent(new OrderPlaced(command));\n    }\n}\n\npublic enum OrderStatus\n{\n    Draft = 0,\n    Placed = 1,\n    Confirmed = 2,\n}\npublic record PlaceOrder(string ProductName, int Quantity, string UserId);\npublic record OrderPlaced(PlaceOrder Command) : SourcedEvent;\n```\n`EventSource\u003cTId\u003e` allows selecting `long` or `Guid` to identify event streams.\n\nWhile selecting `long` offers lightnening-fast queries and is human readable, we can always switch back and forth between the two!\n\n#### Use `IEventStorage\u003cT\u003e` service\n\n```csharp\napp.MapPost(\"api/placeorder\", \nasync(IEventStorage\u003cOrderBooking\u003e eventStorage, PlaceOrder command) =\u003e\n{\n    var aggregate = await eventStorage.CreateOrRestore();\n    aggregate.PlaceOrder(command);\n\n    await eventStorage.Commit(aggregate);\n    return Results.Ok(aggregate.SourceId);\n});\n```\n\nSimilar to placing order, add two more methods to the aggregate to confirm an order, `ConfirmOrder` command and `Apply(OrderConfirmed)` method:\n\n```csharp\napp.MapPost(\"api/confirmorder/{orderId}\", \nasync(IEventStorage\u003cOrderBooking\u003e eventStorage, string orderId, ConfirmOrder command) =\u003e\n{\n    var aggregate = await eventStorage.CreateOrRestore(orderId);\n    aggregate.ConfirmOrder(command);\n\n    await eventStorage.Commit(aggregate);\n});\n```\n\n#### Configure projections\nTransient (runtime), consistent and async projection modes are supported.\n\n```csharp\neventstorage.AddEventSource(source =\u003e\n{\n    source.Select(EventStore.PostgresSql, connectionString)\n    .Project\u003cOrderProjection\u003e(ProjectionMode.Transient)\n    .Project\u003cOrderDetailProjection\u003e(ProjectionMode.Consistent)\n    .Project\u003cOrderInfoProjection\u003e(ProjectionMode.Async)\n    .Project\u003cOrderDocumentProjection\u003e(ProjectionMode.Async, src =\u003e src.Redis(\"redis://localhost\"));\n});\n```\nWhen projection mode set to async, optional projection source can be selected and is by default set to selected event store.\n\n##### Sample projection\n```csharp\npublic record Order(string SourceId, OrderStatus Status, long Version);\n\npublic class OrderProjection : Projection\u003cOrder\u003e\n{\n    public static Order Project(OrderPlaced orderPlaced) =\u003e \n        new(orderPlaced.SourceId?.ToString()?? \"\", OrderStatus.Placed, orderPlaced.Version);\n    public static Order Project(OrderConfirmed orderConfirmed, Order order) =\u003e\n        order with { Status = OrderStatus.Confirmed, Version = orderConfirmed.Version };\n}\n```\n##### Sample Redis projection\n```csharp\n[Document(StorageType = StorageType.Json, Prefixes = [\"OrderDocument\"])]\npublic class OrderDocument\n{\n    [RedisIdField][Indexed]\n    public string? SourceId { get; set; } = string.Empty;\n    // [Searchable]\n    public OrderStatus Status { get; set; }\n    public long Version { get; set; }\n}\n\npublic class OrderDocumentProjection : Projection\u003cOrderDocument\u003e\n{\n    public static OrderDocument Project(OrderPlaced orderPlaced) =\u003e new()\n    {\n        SourceId = orderPlaced.SourceId?.ToString(),\n        Version = orderPlaced.Version,\n        Status = OrderStatus.Placed\n    };\n    public static OrderDocument Project(OrderConfirmed orderConfirmed, OrderDocument orderDocument)\n    {\n        orderDocument.Status = OrderStatus.Confirmed;\n        orderDocument.Version = orderConfirmed.Version;\n        return orderDocument;\n    }\n}\n```\n\n#### Define endpoints to project\n```csharp\n// endpoint for transient OrderProjection\napp.MapGet(\"api/order/{orderId}\",\nasync(IEventStorage\u003cOrderBooking\u003e eventStorage, string orderId) =\u003e\n{\n    var order = await eventStorage.Project\u003cOrder\u003e(orderId);\n    return Results.Ok(order);\n});\n// endpoint for async OrderDocumentProjection on Redis\napp.MapGet(\"api/orderDocument/{orderId}\",\n    async(IEventStorage\u003cOrderBooking\u003e eventStorage, string orderId) =\u003e\n    await eventStorage.Project\u003cOrderDocument\u003e(orderId)\n);\n```\n\n## Documentation\nFor detailed walkthrough and guides, visit our beautiful [documentation](https://eventstorage.github.io) site.\n\n\n## Give us a ⭐\nIf you are an event sourcer and love OSS, give [eventstorage](https://github.com/eventstorage/eventstorage) a star. :purple_heart:\n\n### License\n\nThis project is licensed under the terms of [MIT](https://github.com/eventstorage/eventstorage/blob/main/LICENSE) license.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Feventstorage%2Feventstorage","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Feventstorage%2Feventstorage","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Feventstorage%2Feventstorage/lists"}