EventTransit 2.0.1

There is a newer version of this package available.
See the version list below for details.
dotnet add package EventTransit --version 2.0.1
                    
NuGet\Install-Package EventTransit -Version 2.0.1
                    
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="EventTransit" Version="2.0.1" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="EventTransit" Version="2.0.1" />
                    
Directory.Packages.props
<PackageReference Include="EventTransit" />
                    
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 EventTransit --version 2.0.1
                    
#r "nuget: EventTransit, 2.0.1"
                    
#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 EventTransit@2.0.1
                    
#: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=EventTransit&version=2.0.1
                    
Install as a Cake Addin
#tool nuget:?package=EventTransit&version=2.0.1
                    
Install as a Cake Tool

EventTransit

NuGet License: MIT .NET

EventTransit is a high-performance, production-ready .NET messaging library that provides reliable message delivery with support for multiple message brokers. Built with clean architecture principles, it offers transactional outbox/inbox patterns, delayed messages, and comprehensive monitoring capabilities.

๐Ÿš€ Features

Core Capabilities

  • โœ… Multi-Broker Support - RabbitMQ (with Kafka and Azure Service Bus planned)
  • โœ… Transactional Outbox Pattern - Guaranteed message delivery with database transactions
  • โœ… Inbox Pattern - Automatic duplicate detection and idempotency
  • โœ… Delayed Messages - Schedule messages for future delivery using TTL + DLX pattern
  • โœ… Dead Letter Handling - Automatic retry with exponential backoff and dead letter queues
  • โœ… Direct Publishing - Fire-and-forget publishing for high-throughput scenarios
  • โœ… Multiple Exchange Types - Direct, Topic, Fanout, and Headers exchanges
  • โœ… Built-in Dashboard - Real-time monitoring UI for outbox, inbox, and dead letters
  • โœ… Entity Framework Integration - Seamless integration with EF Core
  • โœ… Repository Pattern Support - Use with or without Entity Framework

Production-Ready

  • ๐Ÿ”’ Type-Safe - Strongly-typed message contracts
  • ๐Ÿ“Š Observable - Comprehensive logging and metrics
  • ๐Ÿ”„ Resilient - Automatic reconnection and error recovery
  • โšก High Performance - Optimized for throughput and low latency
  • ๐Ÿงช Well Tested - Extensive test coverage
  • ๐Ÿ“– Well Documented - Complete API documentation and examples

๐Ÿ“ฆ Installation

dotnet add package EventTransit

๐ŸŽฏ Quick Start

1. Define Your Message

public class OrderCreatedEvent : IEventWithId
{
    public string Id { get; set; } = Guid.NewGuid().ToString();
    public string OrderId { get; set; }
    public decimal Amount { get; set; }
    public DateTime CreatedAt { get; set; }
}

2. Configure EventTransit

Option A: Using appsettings.json (Recommended)

{
  "EventTransit": {
    "Broker": {
      "BrokerType": "RabbitMQ",
      "ConnectionString": "amqp://guest:guest@localhost:5672",
      "ClientProvidedName": "my-service"
    },
    "DefaultExchange": {
      "Name": "my.events",
      "Type": "topic",
      "Durable": true
    },
    "Outbox": {
      "Enabled": true,
      "ProcessingIntervalSeconds": 1,
      "MaxRetryAttempts": 3,
      "DeadLetterAfterMaxRetries": true
    },
    "Inbox": {
      "Enabled": true,
      "MaxRetryAttempts": 3
    }
  }
}
// Program.cs
builder.Services.AddEventTransitWithEntityFramework<MyDbContext>(
    configureOptions: cfg => builder.Configuration.GetSection("EventTransit").Bind(cfg)
);

// Add Dashboard (optional but recommended)
builder.Services.AddEventTransitDashboardWithEntityFramework<MyDbContext>(builder.Configuration);

Option B: Programmatic Configuration

builder.Services.AddEventTransitWithEntityFramework<MyDbContext>(cfg =>
{
    cfg.Broker.BrokerType = BrokerType.RabbitMQ;
    cfg.Broker.ConnectionString = "amqp://guest:guest@localhost:5672";
    cfg.DefaultExchange.Name = "my.events";
    cfg.DefaultExchange.Type = ExchangeType.Topic;
    cfg.Outbox.Enabled = true;
    cfg.Inbox.Enabled = true;
});

3. Publish Messages

Using Outbox Publisher (Transactional - Recommended)

public class OrderService
{
    private readonly IOutboxPublisher _publisher;
    private readonly MyDbContext _dbContext;

    public OrderService(IOutboxPublisher publisher, MyDbContext dbContext)
    {
        _publisher = publisher;
        _dbContext = dbContext;
    }

    public async Task CreateOrderAsync(CreateOrderRequest request)
    {
        // Start transaction
        using var transaction = await _dbContext.Database.BeginTransactionAsync();
        
        try
        {
            // Save order to database
            var order = new Order { /* ... */ };
            _dbContext.Orders.Add(order);
            await _dbContext.SaveChangesAsync();
            
            // Publish event (saved to outbox table in same transaction)
            await _publisher.PublishAsync(new OrderCreatedEvent
            {
                OrderId = order.Id,
                Amount = order.Amount,
                CreatedAt = DateTime.UtcNow
            });
            
            // Commit transaction
            await transaction.CommitAsync();
        }
        catch
        {
            await transaction.RollbackAsync();
            throw;
        }
    }
}

Using Direct Publisher (Fire-and-Forget)

public class NotificationService
{
    private readonly IDirectPublisher _publisher;

    public NotificationService(IDirectPublisher publisher)
    {
        _publisher = publisher;
    }

    public async Task SendNotificationAsync(string userId, string message)
    {
        await _publisher.PublishAsync(new NotificationEvent
        {
            UserId = userId,
            Message = message,
            SentAt = DateTime.UtcNow
        });
    }
}

Publishing Delayed Messages

// Publish a message to be delivered after 5 minutes
await _publisher.PublishDelayedAsync(
    new ReminderEvent { UserId = "123", Message = "Don't forget!" },
    delay: TimeSpan.FromMinutes(5)
);

4. Consume Messages

[MessageBinding("my.events", "order-service-queue", RoutingKey = "order.created")]
public class OrderCreatedConsumer : ConsumerBase<OrderCreatedEvent>
{
    private readonly ILogger<OrderCreatedConsumer> _logger;
    private readonly IOrderProcessor _orderProcessor;

    public OrderCreatedConsumer(
        ILogger<OrderCreatedConsumer> logger,
        IOrderProcessor orderProcessor) : base(logger)
    {
        _logger = logger;
        _orderProcessor = orderProcessor;
    }

    protected override async Task HandleMessageAsync(OrderCreatedEvent message)
    {
        _logger.LogInformation("Processing order {OrderId}", message.OrderId);
        
        await _orderProcessor.ProcessOrderAsync(message.OrderId);
        
        _logger.LogInformation("Order {OrderId} processed successfully", message.OrderId);
    }
}

Consumer with Inbox (Automatic Duplicate Detection)

[MessageBinding("my.events", "payment-service-queue", RoutingKey = "order.created")]
public class PaymentConsumer : InboxConsumerBase<OrderCreatedEvent>
{
    private readonly IPaymentService _paymentService;

    public PaymentConsumer(
        ILogger<PaymentConsumer> logger,
        IInboxService inboxService,
        IPaymentService paymentService) : base(logger, inboxService)
    {
        _paymentService = paymentService;
    }

    protected override async Task HandleMessageAsync(OrderCreatedEvent message)
    {
        // This will only be called once per unique message ID
        // Duplicates are automatically detected and rejected
        await _paymentService.ProcessPaymentAsync(message.OrderId, message.Amount);
    }
}

5. Access the Dashboard

Navigate to: http://localhost:5000/eventtransit

The dashboard provides:

  • ๐Ÿ“Š Overview - Total messages, pending, completed, dead letters
  • ๐Ÿ“ค Outbox - View all outgoing messages with filtering and search
  • ๐Ÿ“ฅ Inbox - View all incoming messages with duplicate tracking
  • โ˜ ๏ธ Dead Letters - View failed messages with retry/republish capabilities
  • ๐Ÿ” Message Details - Click any message to see full payload, headers, and history

๐Ÿ“š Documentation

When to Use Which Publisher?

Feature Outbox Publisher Direct Publisher
Guaranteed Delivery โœ… Yes โŒ No
Transactional โœ… Yes โŒ No
Survives Broker Downtime โœ… Yes โŒ No
Performance Good Excellent
Use Case Critical business events High-throughput notifications
Examples Orders, Payments, Inventory Logs, Metrics, Analytics

Recommendation: Use Outbox Publisher for critical business events where you cannot afford to lose messages. Use Direct Publisher for high-throughput scenarios where occasional message loss is acceptable.

Exchange Types

// Direct Exchange - Point-to-point messaging
[MessageBinding("orders.direct", "order-queue", RoutingKey = "order.created")]

// Topic Exchange - Pattern-based routing
[MessageBinding("events.topic", "payment-queue", RoutingKey = "order.*.created")]

// Fanout Exchange - Broadcast to all queues
[MessageBinding("notifications.fanout", "email-queue")]

// Headers Exchange - Route based on message headers
[MessageBinding("tasks.headers", "priority-queue", Headers = new { priority = "high" })]

Configuration Options

For complete configuration options, see EVENTTRANSIT-DOCUMENTATION.md

๐Ÿ—๏ธ Architecture

EventTransit follows clean architecture principles:

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚                        Your Application                      โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚  Publishers (IOutboxPublisher, IDirectPublisher)            โ”‚
โ”‚  Consumers (ConsumerBase<T>, InboxConsumerBase<T>)          โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚                      EventTransit Core                       โ”‚
โ”‚  - Message Routing                                           โ”‚
โ”‚  - Serialization                                             โ”‚
โ”‚  - Error Handling                                            โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚                   Outbox/Inbox Patterns                      โ”‚
โ”‚  - Transactional Outbox                                      โ”‚
โ”‚  - Duplicate Detection                                       โ”‚
โ”‚  - Retry Logic                                               โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚                    Broker Abstraction                        โ”‚
โ”‚  - RabbitMQ                                                  โ”‚
โ”‚  - Kafka (Coming Soon)                                       โ”‚
โ”‚  - Azure Service Bus (Coming Soon)                           โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

๐Ÿ”ง Advanced Features

Custom Message Headers

await _publisher.PublishAsync(message, headers: new Dictionary<string, object>
{
    { "correlation-id", correlationId },
    { "user-id", userId },
    { "priority", 5 }
});

Batch Publishing

var messages = new List<OrderCreatedEvent> { /* ... */ };
await _publisher.PublishBatchAsync(messages);

Manual Retry from Dashboard

  1. Navigate to Dead Letters page
  2. Select failed messages
  3. Click "Retry" or "Republish"
  4. Messages are requeued automatically

๐Ÿ› Troubleshooting

"HandleMessageAsync doesn't exist" Error

If you encounter this error after installing EventTransit:

# Clear NuGet cache
dotnet nuget locals all --clear

# Restore without cache
dotnet restore --no-cache

# Rebuild
dotnet build

This ensures you're using the latest version of the library.

๐Ÿค Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

๐Ÿ“„ License

This project is licensed under the MIT License.

๐Ÿ™ Acknowledgments

Built with โค๏ธ by Robert Orosume Eru

Product Compatible and additional computed target framework versions.
.NET net9.0 is compatible.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 was computed.  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
2.0.3 196 10/1/2025
2.0.2 170 10/1/2025
2.0.1 174 9/30/2025
2.0.0 182 9/30/2025

v2.0.1: Added delayed messages support, dashboard improvements, and bug fixes.