Overview
El Event Sourcing es un patrón de diseño en el que los cambios en el estado de una aplicación se almacenan como una secuencia de eventos. En lugar de almacenar solo el estado actual de los datos, cada cambio se registra como un evento que describe la modificación. Esto permite reconstruir el estado actual reproduciendo todos los eventos en orden. Event Sourcing es especialmente útil en sistemas financieros, aplicaciones de auditoría, sistemas de control de versiones, aplicaciones de comercio electrónico y sistemas distribuidos.
La biblioteca CodeDesignPlus.Net.EventStore
proporciona una solución completa y eficiente para la implementación de event sourcing en aplicaciones .NET utilizando EventStore. La biblioteca incluye servicios, opciones de configuración y métodos de extensión para facilitar la integración con EventStore y garantizar una gestión robusta y escalable de eventos.
Propósito y alcance
El objetivo de la biblioteca CodeDesignPlus.Net.EventStore
es proporcionar una solución completa y eficiente para la implementación de event sourcing en aplicaciones .NET implementando los servicios definidos en en la biblioteca CodeDesignPlus.Net.Event.Sourcing
y asi facilitar la integración con EventStore.
Principales características
- Servicios: Incluye servicios esenciales para la gestión de eventos, flujos de eventos y conexiones a EventStore.
- Opciones de Configuración: Proporciona opciones de configuración para personalizar la configuración de EventStore.
- Métodos de Extensión: Ofrece métodos de extensión útiles para interactuar con EventStore de manera eficiente.
Casos de uso típicos
- Sistemas de Auditoría: Donde es necesario mantener un historial completo de cambios.
- Sistemas Financieros: Para rastrear transacciones y cambios en el estado.
- Aplicaciones de Comercio Electrónico: Para mantener un historial de pedidos y cambios en el inventario.
- Sistemas de Control de Versiones: Para rastrear cambios en los datos y mantener un historial de versiones.
- Gestión de eventos de dominio: Para capturar, almacenar y gestionar eventos de dominio en aplicaciones .NET.
Componentes principales
EventStoreConnection
: Clase que implementa la interfazIEventStoreConnection
y se encarga de conectar e interactuar con una instancia de EventStore.EventStoreFactory
: Clase que implementa la interfazIEventStoreFactory
y se encarga de gestionar y recuperar conexiones a instancias de EventStore.EventStoreService
: Clase que implementa la interfazCodeDesignPlus.Net.Event.Sourcing.Abstractions.IEventSourcingService.cs
que proporciona métodos para gestionar eventos de manera eficiente independientemente del proveedor de almacenamiento de eventos.EventStoreOptions
: Clase que define las opciones de configuración para EventStore, incluyendo detalles del servidor, autenticación y configuración de la conexión.
Directorysrc
DirectoryCodeDesignPlus.Net.EventStore
DirectoryExceptions
- EventStoreException.cs
DirectoryExtensions
- ServiceCollectionExtensions.cs
DirectorySerializer
- EventStoreContratResolver.cs
DirectoryServices
- EventStoreConnection.cs
- EventStoreFactory.cs
- EventStoreService.cs
DirectoryCodeDesignPlus.Net.EventStore.Abstractions
- EventStoreFactoryConst.cs
- IEventStoreConnection.cs
- IEventStoreFactory.cs
- IEventStoreService.cs
- Server.cs
DirectoryOptions
- EventStoreOptions.cs
Primeros pasos
En esta sección, aprenderás a configurar y utilizar la biblioteca CodeDesignPlus.Net.EventStore
en tus aplicaciones .NET. A continuación, se describen los pasos necesarios para integrar EventStore en tu aplicación y comenzar a gestionar eventos de manera eficiente.
Requisitos previos
- .NET Core 8 o superior.
- Conocimientos básicos de Event Sourcing y CQRS.
- Inyección de dependencias en aplicaciones .NET.
Instalación
Para instalar la biblioteca CodeDesignPlus.Net.EventStore
, puedes utilizar el administrador de paquetes NuGet o la CLI de .NET. A continuación, se muestran los comandos para instalar la biblioteca utilizando NuGet y la CLI de .NET.
dotnet add package CodeDesignPlus.Net.EventStore
Install-Package CodeDesignPlus.Net.EventStore
<PackageReference Include="CodeDesignPlus.Net.EventStore" Version="1.0.0" />
Configuración básica
-
Asignar las opciones de configuración en el
appsettings.json
:{"Core": {"Business": "CodeDesignPlus","AppName": "sample-eventstore","Version": "v1","Description": "Sample of CodeDesignPlus.Net.Core","Contact": {"Name": "CodeDesignPlus","Email": "custom@outlook.com"}},"EventStore": {"Servers": {"Core": {"ConnectionString": "tcp://localhost:1113?tls=false","User": "admin","Password": "12345678"}}}} -
Registra los servicios en el contenedor de dependencias de tu aplicación:
// ...servicesCollection.AddEventStore(configuration);
Ejemplo rápido
El proyecto de ejemplo CodeDesignPlus.Net.EventStore.Sample
hace uso de la biblioteca CodeDesignPlus.Net.EventStore
para gestionar eventos de manera eficiente.
// See https://aka.ms/new-console-template for more informationusing CodeDesignPlus.Net.Event.Sourcing.Abstractions;using CodeDesignPlus.Net.EventStore.Extensions;using CodeDesignPlus.Net.EventStore.Sample.Aggregates;using CodeDesignPlus.Net.EventStore.Sample.Events;using Microsoft.Extensions.Configuration;using Microsoft.Extensions.DependencyInjection;
Console.WriteLine("This is a sample of how to use the CodeDesignPlus.Net.EventStore package.");
var configuration = new ConfigurationBuilder() .SetBasePath(Directory.GetCurrentDirectory()) .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true) .Build();
var servicesCollection = new ServiceCollection();servicesCollection.AddLogging();servicesCollection.AddSingleton(configuration);
servicesCollection.AddEventStore(configuration);
var serviceProvider = servicesCollection.BuildServiceProvider();
var eventSourcing = serviceProvider.GetRequiredService<IEventSourcing>();
var orderAggregate = OrderAggregate.Create(Guid.NewGuid(), "Order 1", Guid.NewGuid());
orderAggregate.UpdateName("Order 1 Updated");orderAggregate.AddProduct("Product 1");orderAggregate.AddProduct("Product 2");orderAggregate.AddProduct("Product 3");orderAggregate.AddProduct("Product 4");orderAggregate.AddProduct("Product 5");
// AppendEventAsync - Append a new event to the event storeforeach (var @event in orderAggregate.GetAndClearEvents()){ await eventSourcing.AppendEventAsync("Order", @event);}
// CountEventAsync - Count the number of events in the event storevar countEvents = await eventSourcing.CountEventsAsync("Order", orderAggregate.Id);
Console.WriteLine($"Count events: {countEvents}");
// GetVersionAsync - Get the version of the aggregate
var version = await eventSourcing.GetVersionAsync("Order", orderAggregate.Id);
Console.WriteLine($"Version Aggregate: {orderAggregate.Version} - Version Event Store: {version}");
// LoadEventsAsync - Load all events of the aggregate
var events = await eventSourcing.LoadEventsAsync("Order", orderAggregate.Id);
var orderRehydrate = AggregateRoot.Rehydrate<OrderAggregate>(orderAggregate.Id, events);
Console.WriteLine($"Order rehydrate: {orderRehydrate.Name}");
// SaveSnapshotAsync - Save a snapshot of the aggregate
await eventSourcing.SaveSnapshotAsync(orderAggregate);
// LoadSnapshotAsync - Load the snapshot of the aggregate
var orderSnapshot = await eventSourcing.LoadSnapshotAsync<OrderAggregate>("Order", orderAggregate.Id);
Console.WriteLine($"Order snapshot: {orderSnapshot.Name}");
// SearchEventsAsync - Search all events of the event store
var allEvents = await eventSourcing.SearchEventsAsync($"Order-{orderAggregate.Id}");
foreach (var @event in allEvents){ Console.WriteLine($"Event: {@event}");}
// SearchEventsAsync - Search all events of the event store by type
var allEventsByType = await eventSourcing.SearchEventsAsync<ProductAddedDomainEvent>();
foreach (var @event in allEventsByType){ Console.WriteLine($"Event: {@event}");}
// SearchEventsAsync - Search all events of the event store by category
var allEventsByCategory = await eventSourcing.SearchEventsAsync<ProductAddedDomainEvent>("Order");
foreach (var @event in allEventsByCategory){ Console.WriteLine($"Event: {@event}");}
-
Configuración de EventStore en el
appsettings.json
:El archivo
appsettings.json
contiene la configuración de EventStore, incluyendo los detalles del servidor, la autenticación y la configuración de la conexión.{"Core": {"Business": "CodeDesignPlus","AppName": "sample-eventstore","Version": "v1","Description": "Sample of CodeDesignPlus.Net.Core","Contact": {"Name": "CodeDesignPlus","Email": "custom@outlook.com"}},"EventStore": {"Servers": {"Core": {"ConnectionString": "tcp://localhost:1113?tls=false","User": "admin","Password": "12345678"}}}} -
Creación de los eventos de dominio:
Las clases
NameUpdatedDomainEvent
,OrderCreatedDomainEvent
yProductAddedDomainEvent
representan eventos de dominio que se utilizan para gestionar eventos en la aplicación.using CodeDesignPlus.Net.Core.Abstractions;using CodeDesignPlus.Net.Core.Abstractions.Attributes;using CodeDesignPlus.Net.EventStore.Sample.Aggregates;namespace CodeDesignPlus.Net.EventStore.Sample.Events;[EventKey<OrderAggregate>(1, "updated")]public class NameUpdatedDomainEvent(Guid aggregateId,string name,Guid? eventId = null,Instant? occurredAt = null,Dictionary<string, object>? metadata = null) : DomainEvent(aggregateId, eventId, occurredAt, metadata){public string Name { get; set; } = name;}using CodeDesignPlus.Net.Core.Abstractions;using CodeDesignPlus.Net.Core.Abstractions.Attributes;using CodeDesignPlus.Net.EventStore.Sample.Aggregates;namespace CodeDesignPlus.Net.EventStore.Sample.Events;[EventKey<OrderAggregate>(1, "created")]public class OrderCreatedDomainEvent(Guid aggregateId,string name,Guid idUser,Guid? eventId = null,Instant? occurredAt = null,Dictionary<string, object>? metadata = null) : DomainEvent(aggregateId, eventId, occurredAt, metadata){public string Name { get; set; } = name;public Guid IdUser { get; set; } = idUser;}using CodeDesignPlus.Net.Core.Abstractions;using CodeDesignPlus.Net.Core.Abstractions.Attributes;using CodeDesignPlus.Net.EventStore.Sample.Aggregates;namespace CodeDesignPlus.Net.EventStore.Sample.Events;[EventKey<OrderAggregate>(1, "product-added")]public class ProductAddedDomainEvent(Guid aggregateId,string product,Guid? eventId = null,Instant? occurredAt = null,Dictionary<string, object>? metadata = null) : DomainEvent(aggregateId, eventId, occurredAt, metadata){public string Product { get; set; } = product;} -
Creación del OrderAggregate
La clase
OrderAggregate
representa un agregado de eventos que se utiliza para gestionar eventos de pedidos.using System;using CodeDesignPlus.Net.Event.Sourcing.Abstractions;using CodeDesignPlus.Net.EventStore.Sample.Events;namespace CodeDesignPlus.Net.EventStore.Sample.Aggregates;public class OrderAggregate : AggregateRoot{public string? Name { get; private set; }public Guid IdUser { get; private set; }public List<string> Products { get; private set; } = [];public override string Category { get; protected set; } = "Order";public OrderAggregate(Guid id) : base(id) { }private OrderAggregate(Guid id, string name, Guid idUser) : base(id){this.Name = name;this.IdUser = idUser;}public static OrderAggregate Create(Guid id, string name, Guid idUser){var aggregate = new OrderAggregate(id, name, idUser);aggregate.AddEvent(new OrderCreatedDomainEvent(id, name, idUser));return aggregate;}public void UpdateName(string name){this.AddEvent(new NameUpdatedDomainEvent(this.Id, name, this.IdUser));}public void AddProduct(string product){this.AddEvent(new ProductAddedDomainEvent(this.Id, product));}private void Apply(OrderCreatedDomainEvent @event){this.Name = @event.Name;this.IdUser = @event.IdUser;}private void Apply(NameUpdatedDomainEvent @event){this.Name = @event.Name;}private void Apply(ProductAddedDomainEvent @event){this.Products.Add(@event.Product);}} -
Registrar Servicios
Se registran los servicios de EventStore en el contenedor de dependencias de la aplicación.
var servicesCollection = new ServiceCollection();servicesCollection.AddLogging();servicesCollection.AddSingleton(configuration);servicesCollection.AddEventStore(configuration); -
Uso del servicio
IEventSourcingService
Se obtiene una instancia del servicio IEventSourcingService del proveedor de servicios.
var eventSourcing = serviceProvider.GetRequiredService<IEventSourcingService>(); -
Creación y manipulación del
OrderAggregate
Se crea una instancia de
OrderAggregate
y se manipula utilizando el servicioIEventSourcingService
.var orderAggregate = OrderAggregate.Create(Guid.NewGuid(), "Order 1", Guid.NewGuid());orderAggregate.UpdateName("Order 1 Updated");orderAggregate.AddProduct("Product 1");orderAggregate.AddProduct("Product 2");orderAggregate.AddProduct("Product 3");orderAggregate.AddProduct("Product 4");orderAggregate.AddProduct("Product 5");foreach (var @event in orderAggregate.GetAndClearEvents()){await eventSourcing.AppendEventAsync("Order", @event);}
Métodos de extensión
La biblioteca CodeDesignPlus.Net.EventStore
proporciona una serie de métodos de extensión útiles para simplificar la implementación de EventStore en aplicaciones .NET. Estos métodos permiten a los desarrolladores interactuar con EventStore de manera eficiente, realizar operaciones comunes y gestionar eventos de forma sencilla.
ServiceCollection
ServiceCollection es una clase que proporciona métodos de extensión para registrar servicios en el contenedor de dependencias.
Opciones de configuración
La biblioteca CodeDesignPlus.Net.EventStore
proporciona opciones de configuración para EventStore a través de la clase EventStoreOptions
. Estas opciones permiten a los desarrolladores personalizar la configuración de EventStore, incluidos los detalles del servidor, la autenticación y la configuración de la conexión.
Servicios
La biblioteca CodeDesignPlus.Net.EventStore
proporciona varios servicios esenciales para la implementación de event sourcing. Estos servicios se encuentran en la carpeta CodeDesignPlus.Net.EventStore.Abstractions
.
IEventStoreService
Este servicio hereda de IEventSourcingService
y proporciona métodos adicionales específicos de EventStore para gestionar eventos de manera eficiente.
IEventStoreFactory
Este servicio define un contrato para gestionar y recuperar conexiones a instancias de EventStore de manera eficiente.
IEventStoreConnection
Este servicio define un contrato para conectar e interactuar con una instancia de EventStore.
Conclusiones
La biblioteca CodeDesignPlus.Net.EventStore
proporciona una solución completa y eficiente para la implementación de event sourcing en aplicaciones .NET utilizando EventStore. La biblioteca incluye servicios, opciones de configuración y métodos de extensión para facilitar la integración con EventStore y garantizar una gestión robusta y escalable de eventos.