Solid arrows below are the message travelling forward through the pipeline, in priority order;
dashed arrows are the result on its way back. A result doesn't exist until MessageHandlerMiddleware
resolves and invokes the handler, and it returns directly to the caller from there, notice no
dashed arrow ever touches earlier middleware, since it has no part on that side.
GitHub renders Mermaid diagrams as scalable SVG, so you can zoom in (browser zoom, or pinch/scroll on
the diagram) for a closer look. Each diagram below is also wrapped in a collapsible <details> block
and laid out top-to-bottom so it stays readable without needing to scroll sideways.
Overview
Expand/collapse diagram
flowchart TD
App([Application]) -->|handle message| Bus[MessageBus]
Bus -->|handle message| Pipe[MiddlewarePipe]
Pipe -->|process message, next| MW[Registered middleware]
MW -->|next.handle message| HandlerMW[MessageHandlerMiddleware]
HandlerMW <-->|resolve message| Resolver[MessageHandlerResolver]
HandlerMW -->|handle message| Handler[Command/QueryHandler]
Handler -.->|Result| HandlerMW
HandlerMW -.->|Result| Pipe
Pipe -.->|Result| Bus
Bus -.->|Result| App
MessageHandlerMiddleware is just the last entry in the pipeline (lowest default priority), so any
middleware you register runs before the handler is resolved.
Custom middleware example
Using the LoggingMiddleware from
Writing custom middleware, registered at priority
10 (above MessageHandlerMiddleware's default priority of 1):
Expand/collapse diagram
flowchart TD
Bus[MessageBus] -->|process CreateUser, next| Log[LoggingMiddleware<br/>priority 10]
Log -->|next.handle message| HandlerMW[MessageHandlerMiddleware<br/>priority 1, runs last]
HandlerMW -->|handle message| Handler[CreateUserHandler]
Handler -.->|CommandResult| HandlerMW
HandlerMW -.->|CommandResult| Bus