SkillAgentSearch skills...

LiteBus

LiteBus is an easy-to-use and ambitious in-process mediator providing the foundation to implement Command Query Separation (CQS). It is implemented with minimal reflection and instead utilizes covariance and contravariance to provide its core functionality.

Install / Use

/learn @litenova/LiteBus
About this skill

Quality Score

0/100

Supported Platforms

Universal

README

<h1 align="center"> <a href="https://github.com/litenova/LiteBus"> <img src="assets/logo/icon.png" alt="LiteBus Logo" width="128"> </a> <br> LiteBus </h1> <h4 align="center">A lightweight, high-performance mediator for building clean, scalable, and testable .NET applications with CQS and DDD.</h4> <p align="center"> <a href="https://github.com/litenova/LiteBus/actions/workflows/release.yml"> <img src="https://github.com/litenova/LiteBus/actions/workflows/release.yml/badge.svg" alt="Build Status" /> </a> <a href="https://codecov.io/gh/litenova/LiteBus" > <img src="https://codecov.io/gh/litenova/LiteBus/graph/badge.svg?token=XBNYITSV5A" alt="Code Coverage" /> </a> <a href="https://www.nuget.org/packages/LiteBus.Commands.Extensions.Microsoft.DependencyInjection"> <img src="https://img.shields.io/nuget/vpre/LiteBus.Commands.Extensions.Microsoft.DependencyInjection.svg" alt="NuGet Version" /> </a> <a href="https://github.com/litenova/LiteBus/wiki"> <img src="https://img.shields.io/badge/documentation-wiki-blue.svg" alt="Wiki" /> </a> </p> <h4 align="center">LiteBus is a modern, powerful, and perpetually free alternative to MediatR.</h4>

It is, and always will be, governed by the MIT license. LiteBus helps you implement Command Query Separation (CQS) and Domain-Driven Design (DDD) patterns by providing a clean, decoupled architecture for your application's business logic.


Why LiteBus?

  • Truly Semantic: Go beyond generic requests. With first-class contracts like ICommand<TResult>, IQuery<TResult>, and IEvent, your code becomes self-documenting. You can even publish clean POCOs as domain events.
  • High Performance: Designed for minimal overhead. Handler metadata is cached on startup, and dependencies are resolved lazily. Large datasets are handled efficiently with IAsyncEnumerable<T> streaming.
  • Granular Pipeline Control: Go beyond simple "behaviors". LiteBus provides a full pipeline with distinct, type-safe Pre-Handlers, Post-Handlers, and Error-Handlers for each message.
  • Open Generic Handlers: Write a single pre/post/error handler once and have it automatically apply to every message type matching its constraints — perfect for cross-cutting concerns like logging, validation, and metrics.
  • Advanced Event Concurrency: Take full control of event processing. Configure Sequential or Parallel execution for both priority groups and for handlers within the same group to fine-tune throughput.
  • Resilient & Durable: Guarantee at-least-once execution for critical commands with a built-in durable Command Inbox.
  • DI-Agnostic by Design: Decoupled from any specific DI container. First-class integration for Microsoft DI and Autofac is provided, with a simple adapter pattern to support others.

Quick Start

1. Install Packages

Install the modules you need. The core messaging infrastructure is included automatically.

# For Commands
dotnet add package LiteBus.Commands.Extensions.Microsoft.DependencyInjection

# For Queries
dotnet add package LiteBus.Queries.Extensions.Microsoft.DependencyInjection

# For Events
dotnet add package LiteBus.Events.Extensions.Microsoft.DependencyInjection

2. Define Your Messages and Handlers

Command: Create a Product

// The Command
public sealed record CreateProductCommand(string Name, decimal Price) : ICommand<Guid>;

// The Handler
public sealed class CreateProductCommandHandler : ICommandHandler<CreateProductCommand, Guid>
{
    public Task<Guid> HandleAsync(CreateProductCommand command, CancellationToken cancellationToken)
    {
        var productId = Guid.NewGuid(); // Your business logic here...
        Console.WriteLine($"Product '{command.Name}' created with ID: {productId}");
        return Task.FromResult(productId);
    }
}

Query: Get a Product by ID

// The Query
public sealed record GetProductByIdQuery(Guid Id) : IQuery<ProductDto>;

// The DTO
public sealed record ProductDto(Guid Id, string Name, decimal Price);

// The Handler
public sealed class GetProductByIdQueryHandler : IQueryHandler<GetProductByIdQuery, ProductDto>
{
    public Task<ProductDto> HandleAsync(GetProductByIdQuery query, CancellationToken cancellationToken)
    {
        // Your data retrieval logic here...
        var product = new ProductDto(query.Id, "Sample Product", 99.99m);
        return Task.FromResult(product);
    }
}

Event: A Product was Created

// The Event (can be a simple POCO)
public sealed record ProductCreatedEvent(Guid ProductId, string Name);

// The Handler
public sealed class ProductCreatedEventHandler : IEventHandler<ProductCreatedEvent>
{
    public Task HandleAsync(ProductCreatedEvent @event, CancellationToken cancellationToken)
    {
        // Your side-effect logic here (e.g., send an email, update a projection)
        Console.WriteLine($"Handling side effects for new product '{@event.Name}'...");
        return Task.CompletedTask;
    }
}

3. Configure and Mediate

Register LiteBus and its modules in Program.cs, then inject the mediators into your services or controllers.

// In Program.cs
builder.Services.AddLiteBus(liteBus =>
{
    var appAssembly = typeof(Program).Assembly;

    // Scan the assembly for all command/query/event handlers
    liteBus.AddCommandModule(module => module.RegisterFromAssembly(appAssembly));
    liteBus.AddQueryModule(module => module.RegisterFromAssembly(appAssembly));
    liteBus.AddEventModule(module => module.RegisterFromAssembly(appAssembly));
});

// In your API Controller or Service
public class ProductController : ControllerBase
{
    private readonly ICommandMediator _commandMediator;
    private readonly IQueryMediator _queryMediator;
    private readonly IEventMediator _eventMediator;

    public ProductController(ICommandMediator cmd, IQueryMediator qry, IEventMediator evt)
    {
        _commandMediator = cmd;
        _queryMediator = qry;
        _eventMediator = evt;
    }

    [HttpPost]
    public async Task<IActionResult> Create(CreateProductCommand command)
    {
        // 1. Send a command to create the product
        var productId = await _commandMediator.SendAsync(command);

        // 2. Publish an event to handle side effects
        await _eventMediator.PublishAsync(new ProductCreatedEvent(productId, command.Name));

        // 3. Query for the newly created product to return it
        var productDto = await _queryMediator.QueryAsync(new GetProductByIdQuery(productId));

        return Ok(productDto);
    }
}

Key Features

A Semantic & Granular Pipeline

LiteBus provides a rich set of interfaces that make your pipeline explicit and powerful. Each message type (Command, Query, Event) has its own set of Pre-Handlers, Post-Handlers, and Error-Handlers.

This allows for fine-grained control, such as running validation logic, enriching a message, or logging results at specific stages of the pipeline. You can also share data between handlers via the AmbientExecutionContext.

// A semantic validator that runs before the main handler

public sealed class PlaceOrderValidator : ICommandValidator<PlaceOrderCommand> // or ICommandPreHandler<PlaceOrderCommand>
{
    public Task ValidateAsync(PlaceOrderCommand command, CancellationToken cancellationToken)
    {
        if (command.LineItems.Count == 0)
        {
            throw new ValidationException("At least one line item is required.");
        }
        return Task.CompletedTask;
    }
}

// A post-handler that runs after the command is successfully handled
public sealed class PlaceOrderNotifier : ICommandPostHandler<PlaceOrderCommand, Guid>
{
    public Task PostHandleAsync(PlaceOrderCommand command, Guid orderId, CancellationToken cancellationToken)
    {
        // Publish an OrderPlacedEvent with the result from the command handler
        return _eventPublisher.PublishAsync(new OrderPlacedEvent(orderId));
    }
}

The mediator also supports polymorphic dispatch, allowing handlers for a base message type to process any derived messages.

Open Generic Handlers for Cross-Cutting Concerns

Write a single handler that automatically applies to every command, query, or event. No changes to existing messages required.

// This pre-handler runs before EVERY command — registered once, applied everywhere
public sealed class CommandLogger<T> : ICommandPreHandler<T> where T : ICommand
{
    public Task PreHandleAsync(T message, CancellationToken cancellationToken)
    {
        Console.WriteLine($"Executing: {typeof(T).Name}");
        return Task.CompletedTask;
    }
}

// RegisterFromAssembly automatically discovers open generic handlers in the assembly
builder.Services.AddLiteBus(liteBus =>
{
    liteBus.AddCommandModule(module =>
    {
        module.RegisterFromAssembly(typeof(Program).Assembly); // picks up CommandLogger<> too
    });
});

// Or register explicitly if the handler is in a different assembly
builder.Services.AddLiteBus(liteBus =>
{
    liteBus.AddCommandModule(module =>
    {
        module.Register(typeof(CommandLogger<>));  // from an external library
        module.RegisterFromAssembly(typeof(Program).Assembly);
    });
});

RegisterFromAssembly automatically discovers open generic handlers in the scanned assembly — no separate Register(typeof(...)) call is needed. Use explicit registration only when the handler lives in a different assembly. LiteBus closes the generic at startup for each concrete message type. Generic constraints (where T : ICommand, class, struct, new()) are fully respected. Registration order does not matter.

Advanced Eventing with Concurrency Control

Define execution priority and concurrency for event handlers to manage complex workflows.

// This handler runs first
[HandlerPriority(1)]
public class ValidateOrderHandler : IEventHandler<Ord

Related Skills

View on GitHub
GitHub Stars215
CategoryDevelopment
Updated1d ago
Forks16

Languages

C#

Security Score

100/100

Audited on Mar 28, 2026

No findings