Zonit.Messaging.Commands 10.0.0-preview.2

This is a prerelease version of Zonit.Messaging.Commands.
dotnet add package Zonit.Messaging.Commands --version 10.0.0-preview.2
                    
NuGet\Install-Package Zonit.Messaging.Commands -Version 10.0.0-preview.2
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Zonit.Messaging.Commands" Version="10.0.0-preview.2" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Zonit.Messaging.Commands" Version="10.0.0-preview.2" />
                    
Directory.Packages.props
<PackageReference Include="Zonit.Messaging.Commands" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add Zonit.Messaging.Commands --version 10.0.0-preview.2
                    
#r "nuget: Zonit.Messaging.Commands, 10.0.0-preview.2"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package Zonit.Messaging.Commands@10.0.0-preview.2
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=Zonit.Messaging.Commands&version=10.0.0-preview.2&prerelease
                    
Install as a Cake Addin
#tool nuget:?package=Zonit.Messaging.Commands&version=10.0.0-preview.2&prerelease
                    
Install as a Cake Tool

<div align="center">

Zonit.Messaging

Lightweight in-process messaging for .NET: Commands (CQRS), Events (pub/sub), Tasks (background jobs) and Schedules (recurring jobs).

.NET License: MIT

</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.

Package Version Downloads Use it for
Zonit.Messaging.Commands v dt CQRS request, one handler, typed response
Zonit.Messaging.Events v dt Pub/Sub fan-out to many handlers
Zonit.Messaging.Tasks v dt Background jobs with progress and retries
Zonit.Messaging.Schedules v dt Recurring jobs on a typed schedule
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 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. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

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