Introduction to NetMediate
GenDI-first ecosystem: Throughout the docs, prefer
NetMediate.SourceGenerationin the startup project and GenDI's[Injectable]+[Inject]style for your own services so you can control lifetime, group, order, and key. Use[Injectable<TService>]only when you need to force a specific non-generic contract and contract discovery does not already find[ServiceInjection]. Concrete non-generic classes that implement closed generic contracts can still use[Injectable]. Only generic/open service implementations (for exampleAuditBehavior<TMessage, TResponse>) should be registered manually inbuilder.Servicesfor the AOT-oriented path.
Welcome to NetMediate, a lightweight and efficient .NET implementation of the Mediator pattern for in-process messaging and communication between components.
What is NetMediate?
NetMediate is a mediator pattern library for .NET that enables decoupled communication between components in your application. It provides a simple and flexible way to send commands, publish notifications, make requests, and handle streaming responses while maintaining clean architecture principles.
Key Features
🚀 Commands
Send one-way messages to all registered handlers sequentially. Perfect for triggering side-effects across multiple consumers.
📨 Notifications
Publish messages to multiple handlers — handlers are started concurrently and the dispatch is fire-and-forget (the pipeline task is discarded and the caller gets Task.CompletedTask immediately). Handler and behavior exceptions are logged by the executor but do not propagate to the caller. Batch notifications are dispatched sequentially in a loop. Ideal for event-driven architectures.
🔄 Requests
Send a message to a single handler and receive a typed response. Great for queries and request-response patterns.
📡 Streaming
Handle requests that return multiple responses over time via IAsyncEnumerable. Perfect for real-time data feeds.
🔌 Pipeline Behaviors
Interceptors with pre/post flow for every message kind. Implement cross-cutting concerns like logging, validation, and caching.
🔑 Keyed Handler Routing
Register handlers under named keys and dispatch to specific subsets at runtime — fully NativeAOT + Trimming compatible via GenDI keyed-service resolution.
🌊 Streaming Fan-Out
Multiple IStreamHandler registrations supported — their items are merged sequentially.
⏹️ Cancellation Support
Full cancellation token support across all operations.
🌐 Broad Runtime Compatibility
Multi-targeted for net10.0, netstandard2.0, and netstandard2.1.
Why this version is a productivity upgrade
- Less setup friction:
NetMediate.Core+NetMediate.SourceGenerationkeep contracts and startup wiring clean while still enabling the runtime automatically. - Better code organization: generated typed dispatch methods keep mediator calls explicit and easier to maintain.
- Scales with teams: compile-time registration and transitive generator propagation improve consistency across multi-project solutions.
Why Use the Mediator Pattern?
The Mediator pattern helps you:
- Decouple Components: Reduce direct dependencies between classes
- Single Responsibility: Each handler focuses on one specific task
- Testability: Handlers can be easily unit tested in isolation
- Maintainability: Changes to one handler don't affect others
- Flexibility: Easy to add or remove handlers without affecting the rest of your code
Architecture Overview
┌─────────────┐
│ Client │
└──────┬──────┘
│
├─── Send Command ────►┌──────────────┐ ┌─────────────────┐
│ │ │ │ Command │
├─── Notify ──────────►│ ├─────►│ Notification │
│ │ IMediator │ │ Request │
├─── Request ─────────►│ │ │ Stream │
│ | | │ Handlers │
└─── RequestStream ───►└──────────────┘ └─────────────────┘
│
▼
┌─────────────────┐
│ Pipeline │
│ Behaviors │
| Via Decorators |
└─────────────────┘
Message Types
NetMediate supports four types of messages, each with a specific purpose:
| Message Kind | Handler Interface | Dispatch Semantics |
|---|---|---|
| Command | ICommandHandler<TMessage> | All registered handlers, sequential in registration order |
| Request | IRequestHandler<TMessage, TResponse> | First registered handler only; returns TResponse |
| Notification | INotificationHandler<TMessage> | All handlers started concurrently (fire-and-forget); handler exceptions are logged but do not propagate |
| Stream | IStreamHandler<TMessage, TResponse> | All registered handlers, items merged sequentially |
No Marker Interfaces Required
Unlike some mediator implementations, NetMediate does not require marker interfaces on your message types. Any plain class or record can be a message:
public record CreateUserCommand(string Email, string Name); // ✅ Works!
public record UserCreatedNotification(string UserId); // ✅ Works!
public record GetUserQuery(string UserId); // ✅ Works!
Getting Started
Ready to dive in? Head over to the Installation Guide to get NetMediate set up in your project, or jump straight to the Quick Start for a working example.
Package Ecosystem
NetMediate consists of several packages:
- NetMediate.Core - Contracts package for shared projects and reusable message definitions
- NetMediate - Runtime mediator implementation consumed indirectly by the generator package or directly when needed
- NetMediate.SourceGeneration - Source generator package for startup projects; injects
NetMediate+GenDI.SourceGeneratorthroughbuildTransitive - NetMediate.Moq - Testing utilities for Moq
Community and Support
- GitHub: schivei/net-mediate
- Issues: Report bugs or request features
- Discussions: Ask questions and share ideas
- NuGet: NetMediate packages
License
NetMediate is licensed under the MIT License. See the LICENSE file for details.