v1.0.0 · Available on NuGet

Domain Events for .NET,
without the ceremony.

Raise domain events from your entities. Dispatch them automatically after SaveChanges. Handle them with multiple handlers. Built on MediatR, integrated with EF Core.

Product.cs
C#
public class Product : Entity
{
    public Guid Id { get; private set; }
    public string Name { get; private set; } = "";

    public static Product Create(string name)
    {
        var product = new Product
        {
            Id = Guid.NewGuid(),
            Name = name
        };

        // Raise event — dispatched after commit
        product.RaiseDomainEvent(
            new ProductCreatedEvent(product.Id, name));

        return product;
    }
}
Features

Everything you need. Nothing you don't.

A focused set of primitives for in-process domain events — without the complexity of Event Sourcing, Outbox Pattern, or distributed messaging.

01

Simple API

Raise an event with a single line: RaiseDomainEvent(...). No ceremony.

02

Immutable events

Events are records — value-based equality, safe to pass around.

03

Auto dispatch

Events dispatch automatically after SaveChanges succeeds.

04

Multiple handlers

One event, many handlers. Add features without touching existing code.

05

Error isolation

Handler failures are logged, not rethrown. Your transaction stays safe.

06

Post-commit dispatch

Handlers only run when the database write actually succeeded.

Get Started

Four steps. Five minutes.

1

Install

Add the core package. Add the EF Core package if you use it.

Terminal bash
dotnet add package Eventra.Core
dotnet add package Eventra.Core.EntityFrameworkCore
2

Define an event

Events use record and inherit from DomainEvent.

ProductCreatedEvent.cs C#
public sealed record ProductCreatedEvent(
    Guid ProductId,
    string ProductName
) : DomainEvent;
3

Raise from entity

Inherit from Entity and call RaiseDomainEvent.

Product.cs C#
public class Product : Entity
{
    public static Product Create(string name)
    {
        var product = new Product
        {
            Id = Guid.NewGuid(),
            Name = name
        };

        product.RaiseDomainEvent(
            new ProductCreatedEvent(product.Id, name));

        return product;
    }
}
4

Save and dispatch

Events are dispatched after SaveChanges succeeds.

CreateProductCommandHandler.cs C#
var product = Product.Create(request.Name);
_dbContext.Products.Add(product);

await _dbContext.SaveChangesAndDispatchEventsAsync(
    _dispatcher, cancellationToken);

return product.Id;
Architecture

Clean separation, by design.

Two packages, one purpose.

Eventra.Core contains abstractions and base classes. No EF Core dependency. Eventra.Core.EntityFrameworkCore adds the integration — and depends on Core.

This separation means EF Core is entirely optional. The core package has no dependency on any data access technology.

  • IDomainEvent Base contract for all events
  • Entity Base class with RaiseDomainEvent
  • IDomainEventDispatcher Dispatches events to handlers
  • SaveChangesAndDispatchEventsAsync EF Core extension
Flow diagram
1. Command Handler
   Product.Create("Kopi")
   └─► RaiseDomainEvent(ProductCreatedEvent)

2. DbContext
   SaveChangesAndDispatchEventsAsync()
   ├─► SaveChangesAsync()    ──► DB
   ├─► ClearDomainEvents()
   └─► DispatchAsync()

3. Dispatcher
   foreach evt in events:
   └─► mediator.Publish(evt)
       └─► Handlers (parallel)
Packages

Install what you need.

Two packages. Pick what fits your stack.

Eventra.Core required

Core abstractions, base classes, dispatcher. No EF Core dependency.

dotnet add package Eventra.Core
Eventra.Core.EntityFrameworkCore optional

EF Core integration. Adds SaveChangesAndDispatchEventsAsync.

dotnet add package Eventra.Core.EntityFrameworkCore
Non-Goals

What Eventra is not.

Eventra focuses on in-process domain events. It deliberately does not implement:

  • × Event Sourcing
  • × Outbox Pattern
  • × Distributed messaging (Kafka, RabbitMQ)
  • × Automatic retry

If you need these, consider EventFlow, Marten, or MassTransit.

Ready to get started?

Install the packages and start raising domain events in minutes.