DEV Community

Cover image for Fluent Brighter: A new way to setup Brighter V10
Rafael Andrade
Rafael Andrade

Posted on

Fluent Brighter: A new way to setup Brighter V10

After starting work with Brighter, I encountered significant challenges with its configuration system. For first-time users, Brighter's setup can feel confusing, overly verbose, and lacking a Fluent API. To address this, I created Fluent.Brighter—a package designed to simplify Brighter configuration through an intuitive fluent interface.

In this article, I'll demonstrate how to configure RabbitMQ using Fluent.Brighter.

What is Fluent.Brighter?

Fluent.Brighter provides a streamlined Fluent API for Brighter configuration, inspired by libraries like MassTransit and JustSaying. Its key features include:

  • Simplified setup: Replace complex configuration with readable method chains
  • Package consolidation: Modules like Fluent.Brighter.Postgres bundle related components (Inbox, Outbox, DistributedLock, and Messaging Gateway)
  • Progressive coverage: While not yet supporting 100% of Brighter's features, we're actively expanding support for AWS, Microsoft SQL Server, and documentation

Note: Found an issue or have suggestions? Please open a GitHub issue.

Requirements

Brighter Fundamentals Recap

Before diving into Fluent.Brighter, let's review core Brighter concepts:

Requests (Commands/Events)

Define messages using IRequest:

public class OrderPlaced : Event(Id.Random())
{
    public string OrderId { get; set; } = string.Empty;
    public decimal Value { get; set; }
}
Enter fullscreen mode Exit fullscreen mode
  • Commands: Target single recipients (e.g., SendEmailCommand)
  • Events: Broadcast notifications (e.g., OrderShippedEvent)

Message Mapper (Optional)

Translates between Brighter messages and application objects (JSON serialization is default):

public class OrderPlacedMapper : IAmAMessageMapper<OrderPlaced>, IAmAMessageMapperAsync<OrderPlaced>
{ 
    // Implementation
}
Enter fullscreen mode Exit fullscreen mode

Request Handler

Processes incoming messages:

public class OrderPlacedHandler(ILogger<OrderPlacedHandler> logger) 
    : RequestHandler<OrderPlaced>
{
    public override OrderPlaced Handle(OrderPlaced command)
    {
        logger.LogInformation("Order {OrderId} placed with value {OrderValue}", 
            command.OrderId, command.Value);
        return base.Handle(command);
    }
}
Enter fullscreen mode Exit fullscreen mode

Configuration with Fluent.Brighter

Start by registering the service in your DI container:

services.AddFluentBrighter(opt => 
{
    // Configuration goes here
});
Enter fullscreen mode Exit fullscreen mode

1. Registering Subscriptions

Configure RabbitMQ subscriptions using AddRabbitMqSubscription:

services.AddFluentBrighter(opt => 
{
    opt.Subscriptions(x => x
        .AddRabbitMqChannelFactory(new RmqMessagingGatewayConnection())
        .AddRabbitMqSubscription(new RmqSubscription(/*...*/))
        .AddRabbitMqSubscription(b => b
            .SetAmqp("amqp://guest:guest@localhost:5672")
            .SetExchange("paramore.brighter.exchange"))
    );
});
Enter fullscreen mode Exit fullscreen mode

2. Registering Publications

Configure RabbitMQ publications with AddRabbitMqPublication:

services.AddFluentBrighter(opt => 
{
    opt.Producers(opt => opt
        .AddRabbitMqPublication(rp => rp
            .SetConnection(new RmqMessagingGatewayConnection(/*...*/))
            .AddPublication(new RmqPublication { /*...*/ })
            .AddPublication(p => p.SetTopic("greeting.event.topic")))
    );
});
Enter fullscreen mode Exit fullscreen mode

3. Unified RabbitMQ Configuration

Use UsingRabbitMq to define connection settings once for all components:

services.AddFluentBrighter(brighter => brighter
    .UsingRabbitMq(rabbitmq => rabbitmq
        .SetConnection(conn => conn
            .SetAmqp("amqp://guest:guest@localhost:5672")
            .SetExchange("paramore.brighter.exchange"))
        .UsePublications(pb => pb
            .AddPublication<GreetingEvent>(p => p
                .SetTopic("greeting.event.topic")
                .CreateTopicIfMissing())
            .AddPublication<FarewellEvent>(p => p
                .SetTopic("farewell.event.topic")
                .CreateTopicIfMissing()))
        .UseSubscriptions(sb => sb
            .AddSubscription<GreetingEvent>(s => s
                .SetSubscription("paramore.example.greeting")
                .SetQueue("greeting.event.queue")
                .SetTopic("greeting.event.topic")
                .SetTimeout(TimeSpan.FromSeconds(200))
                .EnableDurable()
                .EnableHighAvailability())
            .AddSubscription<FarewellEvent>(s => s
                .SetSubscription("paramore.example.farewell")
                .SetQueue("farewell.event.queue")
                .SetTopic("farewell.event.topic")))));
Enter fullscreen mode Exit fullscreen mode

4. Registering Components

Fluent.Brighter auto-scans assemblies by default, but you can manually register components:

services.AddFluentBrighter(brighter => brighter
    .Mappers(m => m.AddMapper<OrderPlaced, OrderPlacedMapper>())
    .RequestHandlers(rh => rh
        .AddHandler<OrderPlaced, OrderPlacedHandler>()
        .AddHandlerAsync<OrderShipped, OrderShippedHandlerAsync>()));
Enter fullscreen mode Exit fullscreen mode

Conclusion

Fluent.Brighter significantly reduces Brighter's configuration complexity while maintaining full functionality. By adopting a fluent interface and consolidating related packages, it lowers the learning curve for new users and streamlines setup for experienced developers.

Ready to try it?

→ Full implementation example on GitHub

→ Report issues or contribute

Top comments (0)