LiteEventBus 0.2.2

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

LiteEventBus

ℹ️ Disclosure: This application was developed using AI (vibecoding).

Uma biblioteca .NET leve para comunicação Publish/Subscribe em memória, com foco em simplicidade, baixo overhead e integração nativa com Microsoft.Extensions.DependencyInjection.

Objetivo

LiteEventBus permite que publicadores emitam eventos fortemente tipados e que múltiplos assinantes sejam notificados de forma assíncrona. A biblioteca não implementa Mediator, Command Bus, CQRS, Event Sourcing ou mensageria distribuída.

Instalação

dotnet add package LiteEventBus

Primeiros passos

1. Definir um evento

public sealed record UserRegistered(
    Guid UserId,
    string Email,
    string FullName);

2. Criar subscribers

using LiteEventBus.Abstractions;

public sealed class SendWelcomeEmail : IEventSubscriber<UserRegistered>
{
    public Task HandleAsync(UserRegistered @event, CancellationToken cancellationToken)
    {
        Console.WriteLine($"Welcome email sent to {@event.Email}");
        return Task.CompletedTask;
    }
}

public sealed class LogAuditEntry : IEventSubscriber<UserRegistered>
{
    public Task HandleAsync(UserRegistered @event, CancellationToken cancellationToken)
    {
        Console.WriteLine($"Audit: user {@event.UserId} registered");
        return Task.CompletedTask;
    }
}

3. Registrar na DI

using Microsoft.Extensions.DependencyInjection;

var services = new ServiceCollection();
services.AddLiteEventBus();
services.AddSubscriber<UserRegistered, SendWelcomeEmail>();
services.AddSubscriber<UserRegistered, LogAuditEntry>();
var provider = services.BuildServiceProvider();

4. Publicar um evento

var eventBus = provider.GetRequiredService<IEventBus>();

await eventBus.PublishAsync(
    new UserRegistered(
        Guid.NewGuid(),
        "john.doe@example.com",
        "John Doe"));

Tratamento de erros

Comportamento padrão (fail-fast)

Por padrão, a publicação é interrompida na primeira exceção. Subscribers registrados após o que falhou não executam:

await eventBus.PublishAsync(new UserRegistered(Guid.NewGuid(), "a@b.com", "A"));
// Se o 2º subscriber lançar exceção, o 3º não executa

ContinueOnError (por chamada)

Para executar todos os subscribers mesmo em caso de erro, use PublishOptions:

var options = new PublishOptions { ContinueOnError = true };

try
{
    await eventBus.PublishAsync(new UserRegistered(Guid.NewGuid(), "a@b.com", "A"), options);
}
catch (AggregateException ex)
{
    // ex.InnerExceptions contém as exceções de todos os subscribers que falharam
    foreach (var inner in ex.InnerExceptions)
    {
        Console.WriteLine($"Subscriber error: {inner.Message}");
    }
}

Configuração global

Defina o comportamento padrão para todas as publicações durante o registro na DI:

services.AddLiteEventBus(options =>
{
    options.DefaultContinueOnError = true;
});

A configuração global é usada quando PublishAsync é chamado sem PublishOptions. O valor por chamada sempre sobrescreve o global.

Callback de erro

Registre um callback para ser notificado quando um subscriber falha (útil para logging ou métricas):

services.AddLiteEventBus(options =>
{
    options.DefaultContinueOnError = true;
    options.OnSubscriberError = async (serviceProvider, @event, exception) =>
    {
        var logger = serviceProvider.GetRequiredService<ILogger<IEventBus>>();
        logger.LogError(exception, "Subscriber falhou ao processar {EventType}", @event.GetType().Name);
    };
});

O callback recebe o IServiceProvider do escopo atual, permitindo resolver serviços scoped (loggers, etc.).

Subscribers com dependências scoped

Cada chamada de PublishAsync cria um escopo DI, permitindo que subscribers consumam dependências scoped como DbContext do Entity Framework Core:

using LiteEventBus.Abstractions;

public sealed class UserRegisteredHandler : IEventSubscriber<UserRegistered>
{
    private readonly AppDbContext _db;

    public UserRegisteredHandler(AppDbContext db)
    {
        _db = db;
    }

    public async Task HandleAsync(UserRegistered @event, CancellationToken cancellationToken)
    {
        _db.Users.Add(new User(@event.UserId, @event.Email, @event.FullName));
        await _db.SaveChangesAsync(cancellationToken);
    }
}

Registro na DI:

services.AddDbContext<AppDbContext>(...);
services.AddLiteEventBus();
services.AddSubscriber<UserRegistered, UserRegisteredHandler>();

API

IEventSubscriber<TEvent>

Contrato para subscribers. Deve ser implementado por cada assinante de evento.

IEventBus

Contrato para publicação de eventos.

Task PublishAsync<TEvent>(TEvent @event, CancellationToken cancellationToken = default);

Task PublishAsync<TEvent>(TEvent @event, PublishOptions options, CancellationToken cancellationToken = default);

PublishOptions

Configura o comportamento de uma publicação específica.

Propriedade Tipo Padrão Descrição
ContinueOnError bool false Quando true, todos subscribers executam mesmo em caso de erro. As exceções são coletadas e um AggregateException é lançado ao final.

EventBusOptions

Configura o comportamento global do LiteEventBus durante o registro na DI.

Propriedade Tipo Padrão Descrição
DefaultContinueOnError bool false Valor global usado quando PublishAsync é chamado sem PublishOptions.
OnSubscriberError Func<IServiceProvider, object, Exception, Task>? null Callback invocado quando um subscriber falha e ContinueOnError é true.

IServiceCollection.AddLiteEventBus()

// Registro padrão
services.AddLiteEventBus();

// Com configuração global
services.AddLiteEventBus(options => { ... });

Registra IEventBus como singleton. É idempotente: chamadas múltiplas não criam registros duplicados.

IServiceCollection.AddSubscriber<TEvent, TSubscriber>()

Registra um subscriber como transient. Ignora silenciosamente registros duplicados do mesmo par (TEvent, TSubscriber).

Comportamento

  • Subscribers são executados sequencialmente na ordem de registro.
  • Por padrão, a primeira exceção interrompe a publicação e é propagada imediatamente.
  • Com ContinueOnError = true, todos subscribers executam. Exceções são coletadas e um AggregateException é lançado ao final. O callback OnSubscriberError é invocado para cada falha.
  • Cada chamada de PublishAsync cria um escopo DI. Subscribers podem consumir dependências scoped (DbContext, HttpContext, etc.).
  • Subscribers são resolvidos via DI como transient a cada chamada de PublishAsync.
  • O IEventBus é registrado como singleton.
  • AddSubscriber ignora registros duplicados do mesmo tipo de subscriber para o mesmo evento.
  • ConfigureAwait(false) é utilizado em todo código interno da biblioteca.

Limitações

  • Apenas comunicação em memória.
  • Sem suporte a mensageria distribuída (RabbitMQ, Kafka, Azure Service Bus, etc.).
  • Sem suporte a Mediator, CQRS ou Command Bus.
  • Sem pipeline behaviors ou middleware.
  • Sem retry, dead letter ou persistência.
  • Sem reflection scanning ou source generators.
  • Apenas API assíncrona.

Design principles

  • KISS — a solução mais simples possível.
  • YAGNI — nada além do necessário.
  • Zero configuração — apenas registrar na DI.
  • Thread-safe — sem estado mutável compartilhado.
  • Performance — sem reflection, sem dynamic, sem Activator no caminho crítico.
Product Compatible and additional computed target framework versions.
.NET net8.0 is compatible.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 was computed.  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
0.4.2 110 8/1/2026
0.4.1 103 7/30/2026
0.4.0 103 7/23/2026
0.3.3 100 7/22/2026
0.3.2 103 7/21/2026
0.2.2 102 7/21/2026
0.2.1 97 7/21/2026
0.2.0 101 7/19/2026
0.1.0 101 7/19/2026