Skip to content

Overview

Event Store es no solo permite almacenar eventos, sino que también proporciona una forma de publicar y suscribirse a eventos. CodeDesignPlus.Net.EventStore.PubSub es una biblioteca que implementa CodeDesignPlus.Net.PubSub para la publicación y suscripción de eventos en aplicaciones .NET Core. Esta biblioteca simplifica el proceso de publicar y suscribirse a eventos, permitiendo a los desarrolladores construir sistemas escalables y desacoplados basados en eventos.

Propósito y Alcance


El propósito de CodeDesignPlus.Net.EventStore.PubSub es administrar y gestionar la conexión con EventStore para la publicación y suscripción de eventos en aplicaciones .NET Core implementando la interfaz IMessage de CodeDesignPlus.Net.PubSub. Esta biblioteca proporciona un conjunto completo de herramientas y servicios para capturar, almacenar y reproducir eventos, facilitando la construcción de sistemas robustos y escalables basados en eventos.

Principales características


  • Implementación de la interfaz IMessage para la publicación y suscripción de eventos.
  • Publicación/Suscripción (Pub/Sub): Permite a los servicios suscribirse a eventos específicos y recibir actualizaciones en tiempo real cuando esos eventos se producen.
  • Persistencia de Eventos: Los eventos se almacenan de forma duradera, lo que permite un historial completo y auditado de todas las acciones.
  • Orden de Eventos: Garantiza que los eventos se procesen en el orden en que fueron escritos, lo cual es crucial para mantener la consistencia.
  • Compatibilidad con Proyecciones: Permite crear proyecciones que indexan eventos de múltiples flujos, facilitando la consulta y el análisis.
  • Suscripciones Persistentes: Los suscriptores pueden mantener sus conexiones incluso después de reinicios, asegurando que no se pierdan eventos.
  • Consumidores Competitivos: Soporta múltiples consumidores que pueden procesar eventos de forma concurrente, asegurando la entrega exactamente una vez.
  • Integración con CQRS: Ideal para arquitecturas basadas en Command Query Responsibility Segregation (CQRS), donde las escrituras y lecturas están separadas.
  • Seguridad y Control de Acceso: Permite definir permisos y controlar quién puede publicar o suscribirse a eventos.
  • Escalabilidad: Diseñado para manejar grandes volúmenes de eventos y suscripciones, ideal para sistemas distribuidos.

Casos de uso típicos


  • Historial de Eventos: Ideal para aplicaciones que requieren un historial completo y auditado de eventos.
  • CQRS (Command Query Responsibility Segregation): Perfecto para arquitecturas que separan las operaciones de escritura y lectura.
  • Proyecciones: Facilita la creación de proyecciones que indexan eventos de múltiples flujos.
  • Consumidores Competitivos: Soporta múltiples consumidores que procesan eventos de forma concurrente.
  • Persistencia de Eventos: Los eventos se almacenan de forma duradera, asegurando que no se pierdan.

Componentes Principales


  • EventStorePubSubService: Implementa la interfaz IMessage para la publicación y suscripción de eventos.
  • EventStorePubSubOptions: Representa las opciones de configuración para EventStore Pub/Sub.
  • Métodos de extensión: Facilitan la configuración y el uso de EventStore Pub/Sub en aplicaciones .NET Core.
  • Directorysrc
    • DirectoryCodeDesignPlus.Net.EventStore.PubSub
      • DirectoryExceptions
        • EventStorePubSubException.cs
      • DirectoryExtensions
        • ServiceCollectionExtensions.cs
      • DirectoryServices
        • EventStorePubSubService.cs
    • DirectoryCodeDesignPlus.Net.EventStore.PubSub.Abstractions
      • IEventStorePubSub.cs
      • DirectoryOptions
        • EventStorePubSubOptions.cs

Primeros Pasos


En esta sección, aprenderás a instalar y configurar la biblioteca CodeDesignPlus.Net.EventStore.PubSub en tu proyecto de .NET Core. Además, explorarás los servicios, opciones y métodos de extensión que proporciona la biblioteca para implementar la publicación y suscripción de eventos en aplicaciones .NET Core.

Requisitos previos

  • .NET 8 o superior.
  • Conocimientos básicos de patrones de diseño y sistemas distribuidos.
  • Conocimientos sobre la arquitectura orientada a eventos (Event-Driven).
  • Inyección de dependencias en aplicaciones .NET.

Instalación


Para instalar la biblioteca CodeDesignPlus.Net.EventStore.PubSub, agrega el paquete NuGet a tu proyecto:

Terminal window
dotnet add package CodeDesignPlus.Net.EventStore.PubSub

Configuración básica

  1. Asignar las opciones de configuración en el appsettings.json:

    {
    "Core": {
    "Business": "CodeDesignPlus",
    "AppName": "sample-eventstore-producer",
    "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"
    }
    }
    },
    "EventStorePubSub": {
    "Enabled": true,
    "UseQueue": false
    }
    }
  2. Registra los servicios el contenedor de dependencias de tu aplicación:

    // ...
    services.AddEventStorePubSub(configuration);

Ejemplo rápido


El proyecto de ejemplo CodeDesignPlus.Net.EventStore.PubSub.Sample contiene los diferentes casos de uso para hacer uso de la biblioteca.

// See https://aka.ms/new-console-template for more information
using CodeDesignPlus.Net.EventStore.PubSub.Extensions;
using CodeDesignPlus.Net.EventStore.PubSub.Producer.Sample.Aggregates;
using CodeDesignPlus.Net.PubSub.Abstractions;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
Console.WriteLine("This is a sample of how to use the CodeDesignPlus.Net.EventStore.PubSub 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.AddEventStorePubSub(configuration);
var serviceProvider = servicesCollection.BuildServiceProvider();
var pubSub = serviceProvider.GetRequiredService<IPubSub>();
// Create an order aggregate and publish the events
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())
{
_ = pubSub.PublishAsync(@event, CancellationToken.None);
Console.WriteLine($"Event {@event.GetType().Name} published, id: {@event.EventId}, aggregate id: {@event.AggregateId}");
}
// Wait for the background services to finish
await Task.Delay(1000);
Console.ReadLine();
  1. Configuración de EventStore Pub/Sub.

    El archivo appsettings.json contiene la configuración de EventStore Pub/Sub.

    {
    "Core": {
    "Business": "CodeDesignPlus",
    "AppName": "sample-eventstore-producer",
    "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"
    }
    }
    },
    "EventStorePubSub": {
    "Enabled": true,
    "UseQueue": false
    }
    }
  2. Creación del OrderAggregate

    Los eventos de dominio que serán publicados o consumidos, modifican el estado de la aplicación, ya sea un Aggregate o Entidad. En este caso, se crea el OrderAggregate que representa una orden.

    using System;
    using CodeDesignPlus.Net.Event.Sourcing.Abstractions;
    using CodeDesignPlus.Net.EventStore.PubSub.Producer.Sample.Events;
    namespace CodeDesignPlus.Net.EventStore.PubSub.Producer.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);
    }
    }
  3. Creación de los eventos de dominio

    Los eventos de dominio representan los cambios en el estado de la aplicación. En este caso, se crean los eventos OrderCreatedDomainEvent, NameUpdatedDomainEvent y ProductAddedDomainEvent.

    using CodeDesignPlus.Net.Core.Abstractions;
    using CodeDesignPlus.Net.Core.Abstractions.Attributes;
    using CodeDesignPlus.Net.EventStore.PubSub.Producer.Sample.Aggregates;
    namespace CodeDesignPlus.Net.EventStore.PubSub.Producer.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.PubSub.Producer.Sample.Aggregates;
    namespace CodeDesignPlus.Net.EventStore.PubSub.Producer.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.PubSub.Producer.Sample.Aggregates;
    namespace CodeDesignPlus.Net.EventStore.PubSub.Producer.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;
    }
  4. Registraremos los servicios necesarios en el contenedor de dependencias.

    services.AddEventStorePubSub(configuration);
  5. Obtenemos una instancia de IPubSub del contenedor de dependencias.

    var pubSub = host.Services.GetRequiredService<IPubSub>();
  6. Creamos la instancia del OrderAggregate.

    Es necesario recordar, que el Aggregate internamente va almacenando los eventos de dominio que se van generando por cada acción que se realice. En este caso se realizan las siguientes acciones:

    • Crear la orden: Al crear la instancia del OrderAggregate, se crearán los eventos OrderCreatedDomainEvent.
    • Modificar el nombre de la orden: Al modificar el nombre de la orden, se crearán los eventos NameUpdatedDomainEvent.
    • Agregar productos a la orden: Al agregar productos a la orden, se crearán los eventos ProductAddedDomainEvent.
    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");
  7. Obtenemos y publicamos los eventos de dominio generados por el OrderAggregate.

    foreach (var @event in orderAggregate.GetAndClearEvents())
    {
    _ = pubSub.PublishAsync(@event, CancellationToken.None);
    Console.WriteLine($"Event {@event.GetType().Name} published, id: {@event.EventId}, aggregate id: {@event.AggregateId}");
    }

Métodos de extensión


La biblioteca CodeDesignPlus.Net.EventStore.PubSub proporciona métodos de extensión para facilitar la configuración y el uso de EventStore Pub/Sub en aplicaciones .NET Core. Estos métodos permiten a los desarrolladores integrar EventStore Pub/Sub de manera eficiente y desacoplada, asegurando una gestión robusta y escalable de eventos.

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.PubSub proporciona opciones de configuración para EventStore a través de la clase EventStorePubSubOptions. 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.PubSub proporciona varios servicios esenciales, llevando a cabo la implementación del servicio CodeDesignPlus.Net.PubSub.Abstractions.IMessage para la publicación y suscripción de eventos. Estos servicios están diseñados para facilitar la gestión de eventos y garantizar una comunicación eficiente y desacoplada entre los componentes de la aplicación.

IEventStorePubSub

IEventStorePubSub hereda de IMessage, una interfaz base que encapsula las operaciones fundamentales de mensajería como el envío y recepción de mensajes asíncronos. Esta herencia proporciona una base sólida para implementar servicios de publicación/suscripción robustos y escalables.

Conclusiones


CodeDesignPlus.Net.EventStore.PubSub es una biblioteca robusta y escalable que facilita la implementación de la publicación y suscripción de eventos en aplicaciones .NET Core. Proporciona una serie de servicios, opciones y métodos de extensión que permiten a los desarrolladores construir sistemas desacoplados y eficientes basados en eventos. Con CodeDesignPlus.Net.EventStore.PubSub, los desarrolladores pueden implementar fácilmente patrones de pub-sub y gestionar eventos de forma eficiente y segura.

Recursos adicionales