Samples
Every messaging pattern in the Learn section has a matching runnable example in the examples/ folder of the repository. They are full console apps: no stubs, no mocks, real RabbitMQ (and MongoDB where persistence is needed) running in Docker.
Prerequisites
Section titled “Prerequisites”Every sample expects a RabbitMQ broker and — for the persistence-backed ones — a MongoDB instance. One docker-compose file starts them both:
docker compose -f examples/docker-compose.yml up -dEach sample’s run.sh (or run.ps1 on Windows) launches the sender and consumer(s) in the right order with sensible pauses between them. If you want to see the individual invocations, the sample’s README lists the raw dotnet run commands.
Catalog
Section titled “Catalog”Each row below has a brief description, the pattern it illustrates, and a link to the source.
Point-to-Point
Section titled “Point-to-Point”Send one command from one sender to one consumer queue — the simplest shape.
- Pattern: Point-to-Point
- Source:
examples/PointToPoint
Pub/Sub
Section titled “Pub/Sub”Publish one event; several independent subscribers each get their own copy.
- Pattern: Pub/Sub
- Source:
examples/PublishSubscribe
Request/Reply
Section titled “Request/Reply”Send a request, wait for a reply — async under the hood, blocking at the call site.
- Pattern: Request/Reply
- Source:
examples/RequestReply
Competing Consumers
Section titled “Competing Consumers”Two workers share a queue; each message goes to one of them — horizontal throughput.
- Pattern: Competing Consumers
- Source:
examples/CompetingConsumers
Content-Based Routing
Section titled “Content-Based Routing”Publish split-by-type events; different consumers bind to the types they care about.
- Pattern: Content-Based Routing
- Source:
examples/ContentBasedRouting
Polymorphic Messages
Section titled “Polymorphic Messages”Publish derived events; a base-type handler catches the whole category while specific handlers catch one type.
- Pattern: Polymorphic Messages
- Source:
examples/PolymorphicMessages
Routing Slip
Section titled “Routing Slip”Ordered multi-stage pipeline: inventory → billing → shipping. Stages don’t know each other.
- Pattern: Routing Slip
- Source:
examples/RoutingSlip
Scatter-Gather
Section titled “Scatter-Gather”Send the same request to several responders in parallel; collect replies into one list.
- Pattern: Scatter-Gather
- Source:
examples/ScatterGather
Aggregator
Section titled “Aggregator”Buffer telemetry slices and flush by size or by time — batching as the unit of work.
- Pattern: Aggregator
- Source:
examples/Aggregator
Process Manager
Section titled “Process Manager”A saga coordinating order submission, inventory reservation, and payment across three services — state persisted in MongoDB.
- Pattern: Process Manager
- Source:
examples/ProcessManager
Filters
Section titled “Filters”Stamp an X-Trace-Id header on every outgoing message — filters as the cross-cutting hook.
- Pattern: Filters
- Source:
examples/Filters
CustomFilterAndMiddleware
Section titled “CustomFilterAndMiddleware”Runnable end-to-end demo of how to build your own filter and middleware against the public extension points. The worked scenario is broker-redelivery deduplication using the OnConsumedSuccessfully pipeline stage.
IFilter · IMessageProcessingMiddleware · examples/CustomFilterAndMiddleware
Streaming
Section titled “Streaming”Chunk a payload too large for one message, reassembled on the receiver, one handler invocation at the end.
- Pattern: Streaming
- Source:
examples/Streaming
Telemetry
Section titled “Telemetry”End-to-end OpenTelemetry tracing across publish → consume, demonstrating W3C trace-context propagation through the broker. Three processes share one TraceId; each subscriber’s span is a direct child of the publisher’s.
- Tracing reference: Observability — Tracing
- Source:
examples/Telemetry
StressHarness
Section titled “StressHarness”Concurrency / soak / throughput harness over every pattern. Surfaces cross-tenant routing leaks, deadlocks, memory growth, and lifecycle races against two Bus instances.
- Source:
examples/StressHarness
Reading the output
Section titled “Reading the output”Each sample’s processes print status lines in a uniform shape:
READY:<name>— the consumer is listening.SUCCESS:<name>:<what happened>— a message was handled.
So a Point-to-Point run produces:
READY:point-to-point-consumerSUCCESS:point-to-point-sender:sent work-001SUCCESS:point-to-point-consumer:processed work-001That shape is deliberately minimal — enough to follow the sequence across terminals, not so much that it obscures the messaging itself. If you want more, each sample is just a few hundred lines of C#; read the source.
If you get stuck
Section titled “If you get stuck”- Docker services not up:
docker compose -f examples/docker-compose.yml psshould show RabbitMQ (and MongoDB for the persistence-backed samples) in a healthy state. - Handlers don’t fire: check the RabbitMQ management UI at
http://localhost:15672(guest/guest). Each example’s README lists the queue names it declares. - MongoDB-backed samples fail to start: the Mongo container takes a few seconds longer than RabbitMQ. The samples’
DependencyWaiterhandles this; if you’re runningdotnet runmanually, start the consumer and wait a moment before the sender.