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
- .NET 8+ or netstandard2.0
- Required NuGet packages:
-
Fluent.Brighter.RMQ.Async
(RabbitMQ Client V7 support) -
Paramore.Brighter.ServiceActivator.Extensions.Hosting
(Service Activator integration)
-
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; }
}
-
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
}
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);
}
}
Configuration with Fluent.Brighter
Start by registering the service in your DI container:
services.AddFluentBrighter(opt =>
{
// Configuration goes here
});
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"))
);
});
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")))
);
});
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")))));
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>()));
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)