In my previous articles about Fluent Brighter and migrating Postgres outbox to v10, I covered RabbitMQ integration. In this article, I'll demonstrate how to configure Postgres for outbox, inbox, and messaging gateway functionality using Fluent Brighter.
Requirements
- .NET 8+ or netstandard2.0
- Required NuGet packages:
- Fluent.Brighter.Postgres - Postgres integration package
- Paramore.Brighter.ServiceActivator.Extensions.Hosting - Service Activator integration for background tasks
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.,
ProcessOrderCommand
) -
Events: Broadcast notifications (e.g.,
OrderPlacedEvent
)
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);
}
}
Configuring Postgres with Fluent.Brighter
Start by registering the service in your DI container:
services.AddFluentBrighter(opt =>
{
// Configuration goes here
});
1. Registering Subscriptions
Configure Postgres subscriptions using AddPostgresSubscription
:
services.AddFluentBrighter(opt =>
{
opt.Subscriptions(x => x
.AddRabbitMqChannelFactory(new RelationalDatabaseConfiguration(...))
.AddPostgresSubscription(new PostgresSubscription(/*...*/))
.AddPostgresSubscription(b => b
.SetQueue("greeting.queue"))
);
});
2. Registering Publications
Configure publications with AddPostgresPublication
:
services.AddFluentBrighter(opt =>
{
opt.Producers(opt => opt
.AddPostgresPublication(rp => rp
.SetConnection(new RelationalDatabaseConfiguration(/*...*/))
.AddPublication(new PostgresPublication { /*...*/ })
.AddPublication(p => p.SetQueue("greeting.event.topic")))
);
});
3. Setting Up Outbox
To configure the outbox with Postgres, use UsePostgresOutbox
:
services
.AddHostedService<ServiceActivatorHostedService>()
.AddFluentBrighter(builder =>
{
builder
.UseDbTransactionOutboxArchive()
.UseOutboxSweeper()
.Producers(x => x.UsePostgresOutbox(new RelationalDatabaseConfiguration(/**/)));
});
4. Setting Up Inbox
To configure the inbox with Postgres, use UsePostgresInbox
:
services
.AddHostedService<ServiceActivatorHostedService>()
.AddFluentBrighter(builder =>
{
builder
.Subscriptions(x => x.UsePostgresInbox(new RelationalDatabaseConfiguration(/**/)));
});
5. Unified Postgres Configuration
Use UsingPostgres
to define connection settings once for all components:
services
.AddHostedService<ServiceActivatorHostedService>()
.AddFluentBrighter(builder => builder
.UseDbTransactionOutboxArchive()
.UseOutboxSweeper()
.UsingPostgres(cfg =>
{
cfg.SetConnection(c => c
.SetConnectionString("Host=localhost;Username=postgres;Password=password;Database=brightertests;")
.SetOutboxTableName("some_outbox_table"));
cfg
.UseInbox()
.UseOutbox()
.UsePublications(pp => pp
.AddPublication<GreetingEvent>(p => p.SetQueue("greeting.queue"))
.AddPublication<FarewellEvent>(p => p.SetQueue("farewell.queue")))
.UseSubscriptions(sb => sb
.AddSubscription<GreetingEvent>(s => s
.SetQueue("greeting.queue")
.SetMessagePumpType(MessagePumpType.Reactor))
.AddSubscription<FarewellEvent>(s => s
.SetQueue("farewell.queue")
.SetMessagePumpType(MessagePumpType.Reactor)));
});
Conclusion
This article demonstrates how to configure Postgres for outbox, inbox, and messaging gateway functionality with Fluent Brighter. The unified configuration approach using UsingPostgres
simplifies setup while maintaining flexibility for more complex scenarios.
For a complete working example, check out the full implementation on GitHub.
Top comments (0)