Zonit.Messaging.Commands
10.0.0-preview.2
dotnet add package Zonit.Messaging.Commands --version 10.0.0-preview.2
NuGet\Install-Package Zonit.Messaging.Commands -Version 10.0.0-preview.2
<PackageReference Include="Zonit.Messaging.Commands" Version="10.0.0-preview.2" />
<PackageVersion Include="Zonit.Messaging.Commands" Version="10.0.0-preview.2" />
<PackageReference Include="Zonit.Messaging.Commands" />
paket add Zonit.Messaging.Commands --version 10.0.0-preview.2
#r "nuget: Zonit.Messaging.Commands, 10.0.0-preview.2"
#:package Zonit.Messaging.Commands@10.0.0-preview.2
#addin nuget:?package=Zonit.Messaging.Commands&version=10.0.0-preview.2&prerelease
#tool nuget:?package=Zonit.Messaging.Commands&version=10.0.0-preview.2&prerelease
<div align="center">
Zonit.Messaging
Lightweight in-process messaging for .NET: Commands (CQRS), Events (pub/sub), Tasks (background jobs) and Schedules (recurring jobs).
</div>
Four small, independent libraries that share one idea: you write a handler class, the library finds it at compile time and wires it into DI. There is no runtime reflection and no assembly scanning, so everything works under trimming and Native AOT. Pick only the patterns you need.
// 1. Register (once, anywhere in your DI setup)
services.AddCommandHandlers();
services.AddEventHandlers();
services.AddTaskHandlers();
services.AddScheduleHandlers();
// 2. Write a handler. A source generator discovers and registers it.
public sealed class SendWelcome : IEventHandler<UserCreated>
{
public Task HandleAsync(UserCreated data, CancellationToken ct) => /* ... */;
}
// 3. Send.
eventProvider.Publish(new UserCreated(userId, email));
Full guides for every pattern live in
Instruction/. Installing a package also teaches your AI coding assistant (Claude Code, Copilot, Cursor) how to use the library.
Packages
Install only what you use. Each pattern has an *.Abstractions package so your domain layer can
depend on the contracts without the implementation.
dotnet add package Zonit.Messaging.Commands
dotnet add package Zonit.Messaging.Events
dotnet add package Zonit.Messaging.Tasks
dotnet add package Zonit.Messaging.Schedules
Register
Call the matching method for each pattern you use, in Program.cs or any plugin's DI module. The
calls are safe to repeat and work with or without handlers present. A source generator finds your
handler classes at compile time and emits concrete, reflection-free registration; these methods
wire it into DI. In a modular app, call them inside each plugin so the generator registers the
handlers in that compilation.
using Zonit.Messaging.Commands;
using Zonit.Messaging.Events;
using Zonit.Messaging.Tasks;
using Zonit.Messaging.Schedules;
services.AddCommandHandlers();
services.AddEventHandlers();
services.AddTaskHandlers();
services.AddScheduleHandlers();
Commands (CQRS)
A request handled by exactly one handler that returns a typed response. See Instruction/commands.md.
public record CreateUser(string Name, string Email) : IRequest<Guid>;
public sealed class CreateUserHandler : IRequestHandler<CreateUser, Guid>
{
public async Task<Guid> HandleAsync(CreateUser request, CancellationToken ct = default)
=> await _users.AddAsync(request.Name, request.Email, ct);
}
// send (response type inferred from the request)
Guid id = await commandProvider.SendAsync(new CreateUser("Ada", "ada@example.com"));
Events (Pub/Sub)
One event, many handlers (fan-out). Tune workers or timeout by declaring the matching property on
the handler; IEventHandler<T> exposes them as default interface members, so no base class is
needed. See Instruction/events.md.
public record UserCreated(Guid UserId, string Email);
public sealed class SendWelcome : IEventHandler<UserCreated>
{
public int WorkerCount => 4; // optional override (default 10)
public Task HandleAsync(UserCreated data, CancellationToken ct) => /* ... */;
}
eventProvider.Publish(new UserCreated(id, "ada@example.com"));
Group events into a transaction to dispatch them in order; in async code use await using:
await using var tx = eventProvider.CreateTransaction();
eventProvider.Publish(new OrderCreated(orderId));
eventProvider.Publish(new InventoryReserved(orderId));
await tx.WaitForCompletionAsync();
Tasks (background jobs)
Queue long-running work with progress reporting, retries and live monitoring. See Instruction/tasks.md.
public sealed class ImportHandler : TaskHandler<ImportData>
{
public override TaskProgressStep[]? ProgressSteps =>
[new(TimeSpan.FromSeconds(5), "Connecting..."), new(TimeSpan.FromSeconds(20), "Saving...")];
protected override async Task HandleAsync(ImportData d, ITaskProgressContext p, CancellationToken ct)
{
await p.NextAsync(); // connect
await p.NextAsync(); // save
}
}
taskProvider.Publish(new ImportData("data.csv", 1000));
taskManager.OnChange<ImportData>(s => Console.WriteLine($"{s.Progress}% {s.Message}"));
Schedules (recurring jobs)
Run work on a typed, cron-like schedule. Each run gets a fresh DI scope and never overlaps itself. See Instruction/schedules.md.
public sealed class DailyCleanup : IScheduleHandler
{
public Task HandleAsync(CancellationToken ct) => /* ... */;
}
services.AddSchedule<DailyCleanup>(o =>
{
o.Schedules = [Schedule.Now(), Schedule.EveryDay(3, 0)];
});
Distributed transport (planned)
Today delivery is in-process only. Cross-service events over a broker (publish in service A, handle in services B and C) are designed but not yet implemented. See docs/transport-plan.md. Until then, do not assume cross-process delivery, durability or ordering.
Requirements and license
Requires .NET 10. Released under the MIT License.
Issues and pull requests are welcome at github.com/Zonit/Zonit.Services.EventMessage.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net10.0
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 10.0.2)
- Zonit.Messaging.Commands.Abstractions (>= 10.0.0-preview.2)
NuGet packages (1)
Showing the top 1 NuGet packages that depend on Zonit.Messaging.Commands:
| Package | Downloads |
|---|---|
|
Zonit.Services.EventMessage
Package Description |
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 10.0.0-preview.2 | 60 | 6/10/2026 |
| 10.0.0-preview.1 | 58 | 6/9/2026 |
| 1.1.8 | 120 | 5/26/2026 |
| 1.1.7 | 144 | 4/19/2026 |
| 1.1.6 | 145 | 2/4/2026 |
| 1.1.5 | 143 | 2/4/2026 |
| 1.1.4 | 153 | 1/22/2026 |
| 1.1.3 | 155 | 1/22/2026 |
| 1.1.2 | 148 | 1/15/2026 |
| 1.1.1 | 155 | 1/11/2026 |
| 1.1.0 | 189 | 1/10/2026 |
| 1.0.7 | 148 | 1/10/2026 |
| 1.0.6 | 149 | 1/10/2026 |
| 1.0.5 | 151 | 1/10/2026 |
| 1.0.4 | 141 | 1/10/2026 |
| 1.0.3 | 143 | 1/10/2026 |
| 1.0.2 | 168 | 1/10/2026 |
| 1.0.1 | 144 | 1/9/2026 |
| 1.0.0 | 150 | 1/9/2026 |