Cosmos.EventSourcing.CritterStack 0.0.7

dotnet add package Cosmos.EventSourcing.CritterStack --version 0.0.7
                    
NuGet\Install-Package Cosmos.EventSourcing.CritterStack -Version 0.0.7
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Cosmos.EventSourcing.CritterStack" Version="0.0.7" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Cosmos.EventSourcing.CritterStack" Version="0.0.7" />
                    
Directory.Packages.props
<PackageReference Include="Cosmos.EventSourcing.CritterStack" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add Cosmos.EventSourcing.CritterStack --version 0.0.7
                    
#r "nuget: Cosmos.EventSourcing.CritterStack, 0.0.7"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package Cosmos.EventSourcing.CritterStack@0.0.7
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=Cosmos.EventSourcing.CritterStack&version=0.0.7
                    
Install as a Cake Addin
#tool nuget:?package=Cosmos.EventSourcing.CritterStack&version=0.0.7
                    
Install as a Cake Tool

Cosmos.EventSourcing.CritterStack

NuGet

Implementación completa de Event Sourcing y CQRS usando Wolverine y Marten (CritterStack).

Descripción

Este paquete proporciona implementaciones listas para producción de todas las abstracciones definidas en Cosmos.EventSourcing.Abstractions y Cosmos.EventDriven.Abstractions. Utiliza Wolverine para mensajería y mediación, y Marten como Event Store y Document Database sobre PostgreSQL.

CritterStack es el nombre de la combinación de Wolverine + Marten, dos poderosas herramientas del ecosistema .NET.

Características

Event Store

  • MartenEventStore: Implementación de IEventStore usando Marten
  • Soporte para recuperar agregados por ID, versión o timestamp
  • Persistencia de eventos en PostgreSQL

Command Routing

  • WolverineCommandRouter: Router de comandos usando Wolverine
  • Soporte para comandos con y sin valor de retorno
  • Integración con multi-tenancy

Query Routing

  • WolverineQueryRouter: Router de consultas usando Wolverine
  • Ejecución distribuida de queries

Event Publishing

  • WolverineEventSender: Publicación de eventos usando Wolverine
  • Integración con RabbitMQ para mensajería distribuida
  • Soporte para multi-tenancy

Projection Store

  • MartenProjectionStore: Almacén de proyecciones usando Marten
  • Operaciones CRUD sobre proyecciones/vistas de lectura

Instalación

dotnet add package Cosmos.EventSourcing.CritterStack

Este paquete incluye automáticamente las dependencias de:

  • Cosmos.EventSourcing.Abstractions
  • Cosmos.EventDriven.Abstractions
  • Cosmos.MultiTenancy

Configuración

Registrar Servicios en el DI Container

using Marten;
using Wolverine;
using Cosmos.EventSourcing.CritterStack.Commands;
using Cosmos.EventSourcing.CritterStack.Queries;
using Cosmos.EventSourcing.CritterStack.Routers;

var builder = WebApplication.CreateBuilder(args);

// Configurar Marten
builder.Services.AddMarten(options =>
{
    options.Connection(builder.Configuration.GetConnectionString("Postgres")!);

    // Configurar Event Store
    options.Events.StreamIdentity = StreamIdentity.AsString;

    // Registrar agregados
    options.Events.AddEventType<OrderCreated>();
    options.Events.AddEventType<ItemAdded>();
});

// Configurar Wolverine
builder.Host.UseWolverine(opts =>
{
    // Configurar RabbitMQ para eventos públicos
    opts.UseRabbitMq("amqp://localhost")
        .AutoProvision();

    // Publicar eventos a RabbitMQ
    opts.PublishMessage<IPublicEvent>()
        .ToRabbitExchange("public-events");
});

// Registrar implementaciones de Cosmos
builder.Services.AddScoped<IEventStore, MartenEventStore>();
builder.Services.AddScoped<ICommandRouter, WolverineCommandRouter>();
builder.Services.AddScoped<IQueryRouter, WolverineQueryRouter>();
builder.Services.AddScoped<IEventSender, WolverineEventSender>();
builder.Services.AddScoped<IProjectionStore, MartenProjectionStore>();

var app = builder.Build();
app.Run();

Uso

Implementar Command Handlers con Wolverine

using Cosmos.EventSourcing.Abstractions.Commands;
using Wolverine.Attributes;

public record CreateOrder(string OrderId, string CustomerId);

// Los handlers son descubiertos automáticamente por Wolverine
public class CreateOrderHandler
{
    private readonly IEventStore _eventStore;

    public CreateOrderHandler(IEventStore eventStore)
    {
        _eventStore = eventStore;
    }

    public async Task Handle(CreateOrder command, CancellationToken ct)
    {
        var order = new Order(command.OrderId, command.CustomerId);

        _eventStore.Save(order);
        await _eventStore.SaveChangesAsync();
    }
}

Ejecutar Comandos con el Router

public class OrderController : ControllerBase
{
    private readonly ICommandRouter _commandRouter;

    public OrderController(ICommandRouter commandRouter)
    {
        _commandRouter = commandRouter;
    }

    [HttpPost]
    public async Task<IActionResult> CreateOrder(CreateOrderRequest request)
    {
        var command = new CreateOrder(Guid.NewGuid().ToString(), request.CustomerId);

        await _commandRouter.InvokeAsync(command, HttpContext.RequestAborted);

        return Ok(new { OrderId = command.OrderId });
    }
}

Implementar Query Handlers

public record GetOrderById(string OrderId);

public class GetOrderByIdHandler
{
    private readonly IProjectionStore _projectionStore;

    public GetOrderByIdHandler(IProjectionStore projectionStore)
    {
        _projectionStore = projectionStore;
    }

    public async Task<OrderDto?> Handle(GetOrderById query, CancellationToken ct)
    {
        return await _projectionStore.GetByIdAsync<OrderDto>(query.OrderId, ct);
    }
}

Publicar Eventos Públicos

using Cosmos.EventDriven.Abstractions;

public record OrderShipped(string OrderId, DateTime ShippedAt) : IPublicEvent;

public class ShipOrderHandler
{
    private readonly IEventStore _eventStore;
    private readonly IEventSender _eventSender;

    public ShipOrderHandler(IEventStore eventStore, IEventSender eventSender)
    {
        _eventStore = eventStore;
        _eventSender = eventSender;
    }

    public async Task Handle(ShipOrder command, CancellationToken ct)
    {
        var order = await _eventStore.GetAggregateRootAsync<Order>(command.OrderId, ct);

        order?.Ship();

        _eventStore.Save(order!);
        await _eventStore.SaveChangesAsync();

        // Publicar evento público a RabbitMQ
        var publicEvent = new OrderShipped(command.OrderId, DateTime.UtcNow);
        await _eventSender.PublishEventAsync(publicEvent);
    }
}

Trabajar con Proyecciones

using Cosmos.EventSourcing.Linq.Extensions;

public class OrderQueryService
{
    private readonly IQuerySession _querySession;

    public OrderQueryService(IQuerySession querySession)
    {
        _querySession = querySession;
    }

    public async Task<IReadOnlyList<OrderDto>> GetCustomerOrdersAsync(
        string customerId,
        CancellationToken ct)
    {
        var orders = await _querySession
            .Query<OrderDto>()
            .Where(o => o.CustomerId == customerId)
            .OrderByDescending(o => o.CreatedAt)
            .ToListAsync(ct);

        return orders;
    }
}

Multi-Tenancy

Este paquete incluye soporte para multi-tenancy a través de Cosmos.MultiTenancy. Los routers de comandos y queries utilizan automáticamente el TenantResolver para ejecutar operaciones en el contexto del tenant correcto.

// El WolverineCommandRouter usa automáticamente el TenantId
await _commandRouter.InvokeAsync(command, ct);
// Internamente: messageBus.InvokeForTenantAsync(tenantId, command, ct)

Requisitos

  • .NET 10.0 o superior
  • PostgreSQL 12+ (para Marten)
  • RabbitMQ (opcional, para eventos públicos)

Dependencias

  • Marten (v8.16.1) - Event Store y Document DB
  • WolverineFx (v5.4.0) - Mediación y mensajería
  • WolverineFx.Marten (v5.4.0) - Integración Wolverine-Marten
  • WolverineFx.RabbitMQ (v5.4.0) - Integración con RabbitMQ
  • Cosmos.EventSourcing.Abstractions
  • Cosmos.EventDriven.Abstractions
  • Cosmos.MultiTenancy

Recursos

Licencia

Copyright © Cosmos. Todos los derechos reservados.

Product Compatible and additional computed target framework versions.
.NET net10.0 is compatible.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
0.0.7 657 12/3/2025
0.0.6 663 12/3/2025
0.0.5 191 11/25/2025
0.0.1 280 9/19/2025