Skip to content

Getting Started

A. Shafie edited this page Sep 26, 2025 · 2 revisions

Getting Started

This guide will walk you through installing LiteBus and implementing your first command, from definition to execution.

Installation

LiteBus is DI-agnostic and provides extension packages for specific DI containers. Choose the set of packages that matches your application's container.

For Microsoft Dependency Injection (Default)

Install the extension packages for the modules you need. These packages include all necessary dependencies.

# 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

For Autofac

Install the Autofac-specific extension packages.

# For Commands
dotnet add package LiteBus.Commands.Extensions.Autofac

# For Queries
dotnet add package LiteBus.Queries.Extensions.Autofac

# For Events
dotnet add package LiteBus.Events.Extensions.Autofac

Basic Configuration

Register LiteBus and its modules in your application's startup file (e.g., Program.cs).

The AddCommandModule, AddQueryModule, and AddEventModule extensions automatically register the core MessageModule if it hasn't been added yet, simplifying configuration.

Microsoft DI Example (Program.cs)

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddLiteBus(liteBus =>
{
    // Register the Command Module and scan the current assembly for handlers
    liteBus.AddCommandModule(module =>
    {
        module.RegisterFromAssembly(typeof(Program).Assembly);
    });

    // Register the Query Module
    liteBus.AddQueryModule(module =>
    {
        module.RegisterFromAssembly(typeof(Program).Assembly);
    });

    // Register the Event Module
    liteBus.AddEventModule(module =>
    {
        module.RegisterFromAssembly(typeof(Program).Assembly);
    });
});

// ... rest of your configuration

Autofac Example

var builder = new ContainerBuilder();

builder.AddLiteBus(liteBus =>
{
    liteBus.AddCommandModule(module =>
    {
        module.RegisterFromAssembly(typeof(Program).Assembly);
    });
});

var container = builder.Build();

Quick Example: Creating a Product

Let's implement a complete pipeline for creating a product.

1. Define the Command and its Result

The command carries the data, and it specifies what it will return.

// The data transfer object for the result
public sealed record ProductDto(Guid Id, string Name, decimal Price);

// The command to create a product, which returns a ProductDto
public sealed record CreateProductCommand(string Name, decimal Price) : ICommand<ProductDto>;

2. Implement the Command Handler

This class contains the core business logic.

public sealed class CreateProductCommandHandler : ICommandHandler<CreateProductCommand, ProductDto>
{
    private readonly IProductRepository _repository;

    public CreateProductCommandHandler(IProductRepository repository)
    {
        _repository = repository;
    }

    public async Task<ProductDto> HandleAsync(CreateProductCommand command, CancellationToken cancellationToken = default)
    {
        var product = new Product(command.Name, command.Price);
        await _repository.AddAsync(product, cancellationToken);
        return new ProductDto(product.Id, product.Name, product.Price);
    }
}

3. (Optional) Add a Validator (Pre-Handler)

This pre-handler runs before the main handler to validate the input.

public sealed class CreateProductValidator : ICommandValidator<CreateProductCommand>
{
    public Task ValidateAsync(CreateProductCommand command, CancellationToken cancellationToken = default)
    {
        if (string.IsNullOrWhiteSpace(command.Name))
        {
            throw new ValidationException("Product name cannot be empty.");
        }
        if (command.Price <= 0)
        {
            throw new ValidationException("Price must be positive.");
        }
        return Task.CompletedTask;
    }
}

4. (Optional) Add a Notifier (Post-Handler)

This post-handler runs after the main handler to perform side effects, like publishing an event.

public sealed class ProductCreationNotifier : ICommandPostHandler<CreateProductCommand, ProductDto>
{
    private readonly IEventPublisher _eventPublisher;

    public ProductCreationNotifier(IEventPublisher eventPublisher)
    {
        _eventPublisher = eventPublisher;
    }

    public Task PostHandleAsync(CreateProductCommand command, ProductDto? result, CancellationToken cancellationToken = default)
    {
        if (result is not null)
        {
            // Publish an event to notify other parts of the system
            return _eventPublisher.PublishAsync(new ProductCreatedEvent(result.Id), cancellationToken);
        }
        return Task.CompletedTask;
    }
}

5. Use the Mediator

Inject ICommandMediator into your controller or service and send the command.

[ApiController]
[Route("products")]
public class ProductsController : ControllerBase
{
    private readonly ICommandMediator _commandMediator;

    public ProductsController(ICommandMediator commandMediator)
    {
        _commandMediator = commandMediator;
    }

    [HttpPost]
    public async Task<ActionResult<ProductDto>> Create(CreateProductCommand command)
    {
        var productDto = await _commandMediator.SendAsync(command);
        return CreatedAtAction(nameof(GetById), new { id = productDto.Id }, productDto);
    }
}

When you send the CreateProductCommand, LiteBus will automatically execute the validator, then the handler, and finally the notifier in a single, transactional pipeline.

Clone this wiki locally