A small, fast request/handler library for .NET. You define a request and its handler, register them with one call, and dispatch through a single interface. All the wiring happens at runtime, once at startup, with no compiler plugin and no build-time code generation: if a project can reference a NuGet package, it can run RequestFlow.
The core library stays unopinionated about how you name your requests. If you want a type-level split between commands and queries for CQRS- and DDD-style apps, install RequestFlow.Cqrs instead; it already contains the core package.
Status: preview on NuGet. Install with the
--prereleaseflag:dotnet add package RequestFlow --prerelease
MediatR went commercial in 2025, and the search for a replacement now turns up a crowded field of free mediators. Many of the fastest are built on source generators: compiler plugins that write the dispatch code during your build. That buys speed and compile-time checks. It also ties the library to your toolchain: a recent compiler, PackageReference, analyzers left on, and generated code in every build.
RequestFlow trades those requirements away and keeps everything at runtime.
- Errors surface at startup, not in production. Discovery, validation, and the dispatch plan all finish before the first request, and a broken configuration fails the boot with one exception listing every problem. After that, dispatch is one dictionary lookup with no reflection, LINQ, or locking.
- No build step. Nothing runs inside your compiler, and there is no generated code to step through when something misbehaves. One package behaves the same from .NET 10 down to .NET Framework 4.6.2.
- MIT, permanently. This library exists because a license changed underneath its users once. It takes no dependency whose license could do the same.
- Migration is mostly renames. Requests and handlers keep their shape coming from MediatR; the mapping table below covers a typical codebase.
Fast is a claim to prove, not to assert. A BenchmarkDotNet suite against the other mediators, raw artifacts included, is on the roadmap before v1. Until it lands, this README quotes no numbers.
| MediatR | RequestFlow |
|---|---|
IRequest<TResponse>, IRequest |
same names, RequestFlow namespace |
IRequestHandler<TRequest, TResponse> with Handle |
same interface, method is HandleAsync |
IMediator.Send(...) |
IRequestDispatcher.SendAsync(...) |
void requests through Unit |
void handlers return plain Task, no Unit anywhere |
IPipelineBehavior<,> |
IRequestStage<,> |
services.AddMediatR(...) |
services.AddRequestFlow(...) |
What doesn't move yet: notifications (INotification / Publish) and streaming. Both are on the roadmap for after v1.0. Notifications return as events, an in-process publish/subscribe (IEvent, IEventHandler, IEventPublisher); streaming arrives through IAsyncEnumerable<T>. Neither is built today, so if your codebase leans on either, hold the migration until they land.
RequestFlow.Abstractionsholds the contracts:IRequest,IRequestHandler,IRequestDispatcher,IRequestStage,NoResult. Depends on nothing.RequestFlowis the runtime: dispatcher,AddRequestFlowwith assembly scanning, startup validation. Depends on Abstractions andMicrosoft.Extensions.DependencyInjection.Abstractions.RequestFlow.Cqrs.Abstractionsholds the CQRS contracts:ICommand,IQuery, their handler interfaces,ICommandDispatcher,IQueryDispatcher. Depends onRequestFlow.Abstractionsonly.RequestFlow.Cqrsis the CQRS runtime: typed dispatcher implementations, registered withAddRequestFlow(...).AddCqrs(). Depends on the contracts package and the core runtime.
Contracts live in their own packages so your domain layer, and any future add-on package, can reference the interfaces without taking a dependency on a runtime. Install a runtime package at the composition root and the matching contracts arrive transitively. Core types share the RequestFlow namespace; the CQRS types live in RequestFlow.Cqrs.
- Getting started: install, first request and handler, dispatching
- Registration: every
AddRequestFlowoption, scanning, generic handlers, startup validation - Stages: wrapping handlers, execution order, which requests a stage reaches, filters
- Service lifetimes: what RequestFlow registers, with which lifetime, and what you can change
- Exceptions: every exception RequestFlow throws, when it surfaces, and how to fix it
Design feedback is the most useful contribution right now.
MIT. See LICENSE.