Reservoir Middleware Reference
Overview
Middleware wraps the synchronous dispatch path for ordinary Reservoir actions. Use it for an application-wide concern that belongs around dispatch, while feature reducers and effects retain their own responsibilities.
Contract
Mississippi.Reservoir.Abstractions.IMiddleware defines void Invoke(IAction action, Action<IAction> nextAction).
Choice in Invoke | Effect |
|---|---|
Call nextAction(action) | Continue with the current action |
Call nextAction with another action | Continue with that replacement |
Return without calling nextAction | Stop that ordinary action's downstream pipeline |
Use nextAction for an ordinary action replacement. The system-action check occurs at the Store.Dispatch entry point before middleware is built, so passing a restore/reset action to nextAction continues through the ordinary core instead of performing restoration. Dispatch a system action through the store entry point when that operation is intended.
Call nextAction once for the normal pass-through pattern. Multiple calls deliberately execute the downstream pipeline multiple times and should be treated as multiple dispatch paths.
Registration and Ordering
Register middleware with IReservoirBuilder.AddMiddleware<TMiddleware>(), where the type is a class implementing IMiddleware. The implementation registers middleware as transient and resolves it into the store's pipeline.
The first registered middleware is the outermost wrapper. Its before-next work runs first; its after-next work runs after the inner wrappers return. Configure middleware during startup before using the store.
The store resolves its middleware collection during construction and retains those instances across its dispatches. Treat mutable middleware fields as state shared by that store's operations; the transient DI registration does not create a fresh middleware instance for each action.
The store does not serialize concurrent Dispatch calls. A retained middleware instance can therefore run concurrently for the same store. Avoid mutable instance state, synchronize access to it, or serialize dispatch at the application boundary.
Execution Boundary
nextAction is synchronous, but the store can start asynchronous effects during that call. Return from nextAction marks the synchronous downstream return, so observe effect completion through result actions and feature state.
For exact reduction boundaries, subscribe to IStore.StoreEvents: ActionDispatchingEvent occurs before reducers and ActionDispatchedEvent carries the resulting snapshot. Keep middleware's responsibility small so those observations remain useful to developers and AI-assisted debugging.
The store handles ISystemAction restoration/reset before building the user middleware pipeline. Those actions therefore use their dedicated path. Use DevTools reference for local restoration behavior.
Handle middleware failures deliberately. An exception before nextAction prevents downstream dispatch; one after nextAction returns reaches the caller after reducers have run and effects may have started. Inspect the actual outcome before retrying an action, because a caller-visible exception can follow completed downstream work.
For recognized reset and restore system actions, observe ActionDispatchingEvent followed by StateRestoredEvent. Use StateRestoredEvent as the restoration completion boundary; those operations use the dedicated path instead of emitting the ordinary ActionDispatchedEvent.
Keep synchronous StoreEvents observers from throwing into dispatch. Failure during ActionDispatchingEvent interrupts processing before reduction; failure during ActionDispatchedEvent occurs after state updates and before listeners and effects. Contain diagnostic errors inside the observer; see state flow for the complete dispatch boundaries.
Source and Verification
- IMiddleware.
- Builder registration.
- Store dispatch and pipeline construction.
- Store tests, including
MiddlewarePipelineExecutesInOrder.
Summary
Middleware controls whether and how an ordinary action proceeds through dispatch. Keep its synchronous boundary distinct from asynchronous effect completion and the dedicated system-action path.
Next Steps
- Action effect reference for asynchronous feature work.
- State flow for reduction and notification timing.