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)